C#光盤刻錄

一.背景介紹

最近公司一個老項目須要添加導出數據到光盤的功能.開始對這功能添加有點抵觸的.光盤?都啥年代了.html

光盤一種即將淘汰的存儲媒介.就像當年的隨身聽,Mp3,Mp4同樣,即將退出歷史舞臺.領導讓加,發牢騷歸發牢騷,活仍是得幹哈.git

從網上找了一些資料,都是特別古老的文檔了.不少方法用起來並非特別的方便.github

1.CodePlex Archive https://archive.codeplex.com/?p=csimapi2samples 其中的例子功能不全,參數都使用dynamic類型,剛開始不瞭解那些基礎概念時,理解起來比較難.能夠參考學習.api

2.博客:https://blog.csdn.net/huanghunjiuba/article/details/12967463 中的例子BurnCdDemo.框架

裏面的BurnCdDemo對ImApi2作了封裝.其實例子裏面的封裝作的挺不錯的.註釋也特別全.ide

在作測試的時候發現刻錄功能在本機運行的很是好.在公司的測試機上卻獲取不到光盤大小,取到的大小是負數.對着Demo的源代碼檢查了半天,沒找到緣由.╮( ̄▽ ̄")╭,腦殼好大的.後來找到緣由了,在下面的過程當中會描述下.學習

PS:我的不喜歡啥都作抽象.抽象,意味着要多寫代碼,查找問題也不方便.抽象,依賴注入,控制反轉是個好東西,就是要多寫許多代碼.測試

我的以爲,不少技術仍是要看實際項目狀況而使用,沒有必要去爲了追求使用而濫用.看起來高大上,實際多寫了代碼維護也不方便.this

So,本身搞個簡單點的.由於就那麼幾個功能:獲取光驅設備列表,獲取光盤信息,添加媒體文件,刻錄,進度通知.spa

二.工欲善其事必先利其器

 因工做電腦沒有光驅,測試很是不方便.那咱們就安裝一個虛擬光驅.

推薦一個比較好用的虛擬光驅軟件PhantomBurner,帶註冊碼.下載地址:https://download.csdn.net/download/zjhaag/10909339

安裝過程就不說了.選下安裝路徑,一路Next.安裝完成後提示重啓.其實不重啓也能夠用.

安裝完成後界面以下.在About中輸入註冊碼激活.點擊Create,選擇Dvd+RW建立Virtual Disc Image.在資源管理器中就能夠看到咱們建立的虛擬光驅了.

 三.開工

1.設備列表獲取

(1)首先添加一個RecorderHelper.在RecorderHelper類中添加一個靜態方法GetRecorderList用於獲取光驅設備列表.

 1         /// <summary>
 2         /// 獲取光驅設備列表
 3         /// </summary>
 4         /// <returns></returns>
 5         public static List<Recorder> GetRecorderList()
 6         {
 7             List<Recorder> recordList = new List<Recorder>();
 8 
 9             // Create a DiscMaster2 object to connect to optical drives.
10             MsftDiscMaster2 discMaster = new MsftDiscMaster2();
11             for (int i = 0; i < discMaster.Count; i++)
12             {
13                 if (discMaster[i] != null)
14                 {
15                     Recorder recorder = new Recorder(discMaster[i]);
16                     recordList.Add(recorder);
17                 }
18             }
19             return recordList;
20         }
View Code

此時,須要Recorder光驅對象主要屬性以下

 1         MsftDiscRecorder2 msRecorder = null;    //Recorder
 2 
 3         /// <summary>
 4         /// 當前磁盤標籤
 5         /// </summary>
 6         public string RecorderName { get; private set; }    
 7 
 8         /// <summary>
 9         /// 是否支持當前刻錄機
10         /// </summary>
11         public bool IsRecorderSupported { get; private set; }
12 
13         /// <summary>
14         /// 是否支持當前磁盤媒體
15         /// </summary>
16         public bool IsCurrentMediaSupported { get; private set; }
17 
18         /// <summary>
19         /// 當前磁盤可用大小
20         /// </summary>
21         public long FreeDiskSize { get; private set; }
22 
23         /// <summary>
24         /// 當前磁盤總大小
25         /// </summary>
26         public long TotalDiskSize { get; private set; }
27 
28         /// <summary>
29         /// 當前媒體狀態
30         /// </summary>
31         public IMAPI_FORMAT2_DATA_MEDIA_STATE CurMediaState { get; private set; }
32 
33         /// <summary>
34         /// 當前媒體狀態
35         /// </summary>
36         public string CurMediaStateName { get; private set; }
37 
38         /// <summary>
39         /// 當前媒體類型
40         /// </summary>
41         public IMAPI_MEDIA_PHYSICAL_TYPE CurMediaType { get; private set; }
42 
43         /// <summary>
44         /// 當前媒體類型
45         /// </summary>
46         public string CurMediaTypeName { get; private set; }
47 
48         /// <summary>
49         /// 是否能夠刻錄
50         /// </summary>
51         public bool CanBurn {get;private set;}
View Code

(2)對Recorder各屬性進行初始化,賦值.主要方法以下

 1         /// <summary>
 2         /// Recorder Ctor
 3         /// </summary>
 4         /// <param name="uniqueId">標識Id</param>
 5         public Recorder(string uniqueId)
 6         {
 7             this.uniqueId = uniqueId;
 8             msRecorder = new MsftDiscRecorder2();
 9             msRecorder.InitializeDiscRecorder(uniqueId);
10             InitRecorder();
11 
12             this.BurnMediaList = new List<BurnMedia>();
13             this.BurnMediaFileSize = 0;
14         }
15 
16         /// <summary>
17         /// 初始化Recorder
18         /// 更新Recorder信息,更新光盤後可重試.
19         /// </summary>
20         public void InitRecorder()
21         {
22             try
23             {
24                 if (msRecorder.VolumePathNames != null && msRecorder.VolumePathNames.Length > 0)
25                 {
26                     foreach (object mountPoint in msRecorder.VolumePathNames)
27                     {   //掛載點 取其中一個
28                         RecorderName = mountPoint.ToString();
29                         break;
30                     }
31                 }
32                 // Define the new disc format and set the recorder
33                 MsftDiscFormat2Data dataWriter = new MsftDiscFormat2Data();
34                 dataWriter.Recorder = msRecorder;
35 
36                 if (!dataWriter.IsRecorderSupported(msRecorder))
37                 {
38                     return;
39                 }
40                 if (!dataWriter.IsCurrentMediaSupported(msRecorder))
41                 {
42                     return;
43                 }
44                 if (dataWriter.FreeSectorsOnMedia >= 0)
45                 {   //可用大小
46                     FreeDiskSize = dataWriter.FreeSectorsOnMedia * 2048L;
47                 }
48 
49                 if (dataWriter.TotalSectorsOnMedia >= 0)
50                 {   //總大小
51                     TotalDiskSize = dataWriter.TotalSectorsOnMedia * 2048L;
52                 }
53                 CurMediaState = dataWriter.CurrentMediaStatus;  //媒體狀態
54                 CurMediaStateName = RecorderHelper.GetMediaStateName(CurMediaState);
55                 CurMediaType = dataWriter.CurrentPhysicalMediaType; //媒介類型
56                 CurMediaTypeName = RecorderHelper.GetMediaTypeName(CurMediaType);
57                 CanBurn = RecorderHelper.GetMediaBurnAble(CurMediaState);   //判斷是否可刻錄
58             }
59             catch (COMException ex)
60             {
61                 string errMsg = ex.Message.Replace("\r\n", ""); //去掉異常信息裏的\r\n
62                 this.CurMediaStateName = $"COM Exception:{errMsg}";
63             }
64             catch (Exception ex)
65             {
66                 this.CurMediaStateName = $"{ex.Message}";
67             }
68         }
View Code

(3)測試代碼以下

 1                     #region 查找光驅設備
 2                     Console.Clear();
 3                     Console.WriteLine("正在查找光驅設備..");
 4                     List<Recorder> recorderList = RecorderHelper.GetRecorderList();
 5                     if (recorderList.Count <= 0)
 6                     {
 7                         Console.WriteLine("沒有可使用的光驅,請檢查.");
 8                         Console.WriteLine("請鏈接光驅後,按任意鍵重試...");
 9                         Console.ReadKey();
10                         continue;
11                     }
12                     for (int i = 0; i < recorderList.Count; i++)
13                     {
14                         Recorder tempRecorder = recorderList[i];
15                         Console.WriteLine($"發現光驅設備:[{i+1}]  {tempRecorder.RecorderName}");
16                         Console.WriteLine($"媒體類型:{tempRecorder.CurMediaTypeName}");
17                         Console.WriteLine($"媒體狀態:{tempRecorder.CurMediaStateName}");
18                         Console.WriteLine("支持刻錄:" + (tempRecorder.CanBurn ? "" : "×"));
19                         Console.WriteLine($"可用大小:{FormatFileSize(tempRecorder.FreeDiskSize)}");
20                         Console.WriteLine($"總大小:{FormatFileSize(tempRecorder.TotalDiskSize)}");
21                     }
22                     if (!recorderList.Any(r=>r.CanBurn))
23                     {
24                         Console.WriteLine("沒有能夠用於刻錄的光驅設備,請檢查後,按任意鍵重試.");
25                         Console.ReadKey();
26                         continue;
27                     }
28                     #endregion        
View Code

 測試結果:

 

至此,咱們完成了對於光驅設備列表的獲取及Recorder對象各屬性的初始化工做.

說明下,對光驅設備操做須要有管理員權限,沒有管理員權限會致使獲取失敗.對於C#應用程序設置以管理員身份啓動請參照http://www.javashuo.com/article/p-epoagggb-gg.html

2.添加刻錄文件

(1)咱們爲Recorder對象添加待刻錄媒體對象列表待刻錄媒體文件大小兩個屬性

1         /// <summary>
2         /// 待刻錄媒體對象List
3         /// </summary>
4         public List<BurnMedia> BurnMediaList {get;set;}
5 
6         /// <summary>
7         /// 待刻錄媒體文件大小
8         /// </summary>
9         public long BurnMediaFileSize { get; set; }
View Code

待刻錄媒體對象定義以下

 1     /// <summary>
 2     /// 刻錄媒體
 3     /// </summary>
 4     public class BurnMedia
 5     {
 6         /// <summary>
 7         /// 路徑
 8         /// </summary>
 9         public string MediaPath { get; set; }
10 
11         /// <summary>
12         /// 名稱
13         /// </summary>
14         public string MediaName { get; set; }
15 
16         /// <summary>
17         /// 是不是文件夾
18         /// </summary>
19         public bool IsDirectory { get; set; }
20 
21         /// <summary>
22         /// 大小
23         /// </summary>
24         public long Size { get; set; }
25     }
View Code

(2)爲Recorder對象添加AddBurnMedia方法

 1         /// <summary>
 2         /// 添加刻錄媒體對象
 3         /// </summary>
 4         public BurnMedia AddBurnMedia(string path)
 5         {
 6             BurnMedia media = null;
 7             if(string.IsNullOrEmpty(path))
 8             {
 9                 throw new Exception("文件路徑不能爲空.");
10             }
11             if(!CanBurn)
12             {
13                 throw new Exception("當前磁盤狀態不支持刻錄.");
14             }
15             media = new BurnMedia();
16             long fileSize = 0;
17             if (Directory.Exists(path))
18             {
19                 DirectoryInfo dirInfo = new DirectoryInfo(path);
20                 fileSize = GetDirectorySize(path);
21                 media.MediaName = dirInfo.Name;
22                 media.MediaPath = dirInfo.FullName;
23                 media.Size = fileSize;
24                 media.IsDirectory = true;
25             }
26             else if (File.Exists(path))
27             {
28                 FileInfo fileInfo = new FileInfo(path);
29                 fileSize = fileInfo.Length;
30                 media.MediaName = fileInfo.Name;
31                 media.MediaPath = fileInfo.FullName;
32                 media.Size = fileSize;
33                 media.IsDirectory = false;
34             }
35             else
36             {
37                 throw new Exception("文件不存在");
38             }
39             if (BurnMediaFileSize + fileSize >= FreeDiskSize)
40             {
41                 throw new Exception("剩餘空間不足");
42             }
43             if (BurnMediaList.Any(m => m.MediaName.ToLower() == media.MediaName.ToLower()))
44             {
45                 throw new Exception($"已存在媒體名稱爲{media.MediaName}的對象");
46             }
47             BurnMediaList.Add(media);
48             BurnMediaFileSize += fileSize;
49             return media;
50         }
View Code

(3)測試代碼以下

 1                     while (true)
 2                     {
 3                         Console.WriteLine("添加文件:請輸入待刻錄文件或文件夾路徑. 0完成 1查看已添加文件");
 4                         string filePath = Console.ReadLine();
 5                         if (string.IsNullOrEmpty(filePath))
 6                         {
 7                             continue;
 8                         }
 9                         else if (filePath == "0")
10                         {
11                             break;
12                         }
13                         else if (filePath == "1")
14                         {
15                             ShowBurnMediaListInfo(recorder);
16                         }
17                         else
18                         {
19                             try
20                             {
21                                 BurnMedia media = recorder.AddBurnMedia(filePath);
22                                 Console.WriteLine($"添加成功:{filePath}");
23                                 Console.WriteLine("文件大小:" + FormatFileSize(media.Size));
24                                 Console.WriteLine("已添加文件總大小:" + FormatFileSize(recorder.BurnMediaFileSize));
25                             }
26                             catch (Exception ex)
27                             {
28                                 Console.WriteLine($"添加失敗:{ex.Message}");
29                             }
30                         }
31                     }
View Code

運行結果:

3.刻錄及刻錄進度通知

 爲Recorder對象添加Burn方法.同時,添加刻錄進度通知.

(1)添加BurnProgressChanged委託用於通知刻錄進度

1     /// <summary>
2     /// 刻錄進度delegate
3     /// </summary>
4     public delegate void BurnProgressChanged(BurnProgress burnProgress);
View Code

刻錄進度通知對象定義以下(其屬性爲根據需求添加):

 1     /// <summary>
 2     /// 刻錄進度對象
 3     /// </summary>
 4     public class BurnProgress
 5     {
 6         /// <summary>
 7         /// 當前操做
 8         /// 對應IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION枚舉
 9         /// 4 正在寫入數據 5完成數據寫入 6 刻錄完成
10         /// </summary>
11         public int CurrentAction { get; set; }
12 
13         /// <summary>
14         /// 當前操做Name
15         /// </summary>
16         public string CurrentActionName { get; set; }
17 
18         /// <summary>
19         /// 已用時間單位S
20         /// </summary>
21         public int ElapsedTime { get; set; }
22 
23         /// <summary>
24         /// 預計總時間單位S
25         /// </summary>
26         public int TotalTime { get; set; }
27 
28         /// <summary>
29         /// 數據寫入進度
30         /// </summary>
31         public decimal Percent { get; set; }
32 
33         /// <summary>
34         /// 數據寫入進度%
35         /// </summary>
36         public string PercentStr { get { return Percent.ToString("0.00%"); } }
37     }
View Code

(2)爲Recorder對象添加委託屬性

1         /// <summary>
2         /// 刻錄進度變化通知
3         /// </summary>
4         public BurnProgressChanged OnBurnProgressChanged { get; set; }
View Code

(3)爲Recorder添加Burn方法

  1         /// <summary>
  2         /// 刻錄
  3         /// </summary>
  4         public void Burn(string diskName = "SinoUnion")
  5         {
  6             if(!CanBurn)
  7             {
  8                 throw new Exception("當前磁盤狀態不支持刻錄");
  9             }
 10             if (string.IsNullOrEmpty(diskName))
 11             {
 12                 throw new Exception("DiskName不能爲空");
 13             }
 14             if (BurnMediaList.Count <= 0)
 15             {
 16                 throw new Exception("待刻錄文件列表不能爲空");
 17             }
 18             if(BurnMediaFileSize<=0)
 19             {
 20                 throw new Exception("待刻錄文件大小爲0");
 21             }
 22 
 23             try
 24             {   //說明
 25                 //1.fsi.ChooseImageDefaults用的是IMAPI2FS的,咱們定義的msRecorder是IMAPI2的.因此必須用動態類型
 26                 //2.dataWriter也要使用動態類型,要否則Update事件會出異常.
 27                 // Create an image stream for a specified directory.
 28                 dynamic fsi = new IMAPI2FS.MsftFileSystemImage();  // Disc file system
 29                 IMAPI2FS.IFsiDirectoryItem dir = fsi.Root;                 // Root directory of the disc file system                
 30                 dynamic dataWriter = new MsftDiscFormat2Data(); //Create the new disc format and set the recorder
 31 
 32                 dataWriter.Recorder = msRecorder;
 33                 dataWriter.ClientName = "SinoGram";
 34                 //不知道這方法不用行不行.用的參數是IMAPI2FS的.
 35                 //因此學官網的例子,把fsi改爲了動態的.使用msRecorder做爲參數
 36                 fsi.ChooseImageDefaults(msRecorder);
 37 
 38                 //設置相關信息
 39                 fsi.VolumeName = diskName;   //刻錄磁盤名稱
 40                 for (int i = 0; i < BurnMediaList.Count; i++)
 41                 {
 42                     dir.AddTree(BurnMediaList[i].MediaPath, true);
 43                 }
 44                 // Create an image from the file system
 45                 IStream stream = fsi.CreateResultImage().ImageStream;
 46                 try
 47                 {
 48                     dataWriter.Update += new DDiscFormat2DataEvents_UpdateEventHandler(BurnProgressChanged);
 49                     dataWriter.Write(stream);// Write stream to disc
 50                 }
 51                 catch (System.Exception ex)
 52                 {
 53                     throw ex;
 54                 }
 55                 finally
 56                 {
 57                     if (stream != null)
 58                     {
 59                         Marshal.FinalReleaseComObject(stream);
 60                     }
 61                 }
 62             }
 63             catch (Exception ex)
 64             {
 65                 Console.WriteLine($"刻錄失敗:{ex.Message}");
 66             }
 67         }
 68 
 69         /// <summary>
 70         /// 刻錄進度通知
 71         /// </summary>
 72         /// <param name="object"></param>
 73         /// <param name="progress"></param>
 74         void BurnProgressChanged(dynamic @object, dynamic progress)
 75         {
 76             BurnProgress burnProgress = new BurnProgress();
 77             try
 78             {
 79                 burnProgress.ElapsedTime = progress.ElapsedTime;
 80                 burnProgress.TotalTime = progress.TotalTime;
 81                 burnProgress.CurrentAction = progress.CurrentAction;
 82                 if (burnProgress.ElapsedTime > burnProgress.TotalTime)
 83                 {   //若是已用時間已超過預估總時間.則將預估總時間設置爲已用時間
 84                     burnProgress.TotalTime = burnProgress.ElapsedTime;
 85                 }
 86                 string strTimeStatus;
 87                 strTimeStatus = "Time: " + progress.ElapsedTime + " / " + progress.TotalTime;
 88                 int currentAction = progress.CurrentAction;
 89                 switch (currentAction)
 90                 {
 91                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_CALIBRATING_POWER:
 92                         burnProgress.CurrentActionName = "Calibrating Power (OPC)";
 93                         break;
 94                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_COMPLETED:
 95                         burnProgress.CurrentActionName = "Completed the burn";
 96                         burnProgress.Percent = 1;
 97                         burnProgress.TotalTime = burnProgress.ElapsedTime;  //刻錄完成,將預估用時,修正爲已用時間
 98                         break;
 99                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_FINALIZATION:
100                         burnProgress.CurrentActionName = "Finishing the writing";
101                         burnProgress.Percent = 1;
102                         burnProgress.TotalTime = burnProgress.ElapsedTime;  //寫入完成,將預估用時,修正爲已用時間
103                         break;
104                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_FORMATTING_MEDIA:
105                         burnProgress.CurrentActionName = "Formatting media";
106                         break;
107                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_INITIALIZING_HARDWARE:
108                         burnProgress.CurrentActionName = "Initializing Hardware";
109                         break;
110                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_VALIDATING_MEDIA:
111                         burnProgress.CurrentActionName = "Validating media";
112                         break;
113                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_VERIFYING:
114                         burnProgress.CurrentActionName = "Verifying the data";
115                         break;
116                     case (int)IMAPI2.IMAPI_FORMAT2_DATA_WRITE_ACTION.IMAPI_FORMAT2_DATA_WRITE_ACTION_WRITING_DATA:
117                         dynamic totalSectors;
118                         dynamic writtenSectors;
119                         dynamic startLba;
120                         dynamic lastWrittenLba;
121                         totalSectors = progress.SectorCount;
122                         startLba = progress.StartLba;
123                         lastWrittenLba = progress.LastWrittenLba;
124                         writtenSectors = lastWrittenLba - startLba;                        
125                         burnProgress.CurrentActionName = "Writing data";
126                         burnProgress.Percent = Convert.ToDecimal(writtenSectors)/ Convert.ToDecimal(totalSectors);
127                         break;
128                     default:
129                         burnProgress.CurrentActionName = "Unknown action";
130                         break;
131                 }
132             }
133             catch (Exception ex)
134             {
135                 burnProgress.CurrentActionName = ex.Message;
136             }
137             if (OnBurnProgressChanged != null)
138             {
139                 OnBurnProgressChanged(burnProgress);
140             }
141         }
View Code

(4)測試代碼以下

 1                     if (recorder.BurnMediaList.Count <= 0)
 2                     {
 3                         Console.WriteLine($"未添加任何刻錄文件.已退出刻錄過程.");
 4                     }
 5                     else
 6                     {
 7                         #region 刻錄前確認
 8                         bool confirmBurn = false;
 9                         Console.Clear();
10                         ShowBurnMediaListInfo(recorder);
11                         while (true)
12                         {
13                             Console.WriteLine();
14                             Console.ForegroundColor = ConsoleColor.DarkGreen;//設置顏色.
15                             Console.WriteLine($"刻錄過程一旦開始,終止可能會形成磁盤損壞.確認要開始刻錄(y/n)?");
16                             Console.ForegroundColor = colorFore;//還原顏色.
17                             string confirmStr = Console.ReadLine();
18                             if (confirmStr.ToLower() == "n")
19                             {
20                                 break;
21                             }
22                             else if (confirmStr.ToLower() == "y")
23                             {
24                                 confirmBurn = true;
25                                 break;
26                             }
27                         }
28                         if (!confirmBurn)
29                         {
30                             Console.WriteLine($"本次刻錄過程已退出");
31                             continue;
32                         }
33                         #endregion
34                         Console.CursorVisible = false;    //隱藏光標
35                         ShowBurnProgressChanged(recorder);
36                         recorder.Burn();    //刻錄
37                         Console.WriteLine();
38                     }
View Code

(5)輸出刻錄進度變化,添加ShowBurnProgressChanged方法

在查找如何輸出進度數據的時候,看到了控制檯輸出進度條的功能.帶顏色的還挺漂亮的,看到好的功能就想加到咱們的項目裏.

 1         /// <summary>
 2         /// 輸出刻錄進度通知
 3         /// </summary>
 4         /// <param name="recorder"></param>
 5         static void ShowBurnProgressChanged(Recorder recorder)
 6         {
 7             Console.Clear();
 8 
 9             #region 搭建輸出顯示框架
10             Console.WriteLine();
11             Console.WriteLine($"**********************刻錄中,請稍候**********************");
12             Console.WriteLine();
13             Console.WriteLine("  當前操做:"); //第4行當前操做
14             Console.WriteLine();
15 
16             // 第6行繪製進度條背景
17             Console.Write("  ");
18             Console.BackgroundColor = ConsoleColor.DarkCyan;
19             for (int i = 1; i <= 50; i++)
20             {   //設置50*1的爲總進度
21                 Console.Write(" ");
22             }
23 
24             Console.WriteLine();
25             Console.BackgroundColor = colorBack;
26 
27             Console.WriteLine();    //第7行輸出空行
28             Console.WriteLine();    //第8行輸出進度
29             Console.WriteLine($"*********************************************************");  //第9行
30             Console.WriteLine();    //第10行輸出空行
31             #endregion
32 
33             //進度變化通知時,更新相關行數據便可.
34             recorder.OnBurnProgressChanged += (burnProgress) => {
35                 if (burnProgress.CurrentAction == 6)
36                 {   //刻錄完成
37                     Console.SetCursorPosition(0, 1);
38                     Console.WriteLine($"*************************刻錄完成************************");
39                 }
40                 //第4行 當前操做
41                 Console.SetCursorPosition(0, 3);
42                 Console.Write($"  當前操做:{burnProgress.CurrentActionName}");
43                 Console.Write("                  ");    //填充空白區域
44                 Console.ForegroundColor = colorFore;
45 
46                 // 第6行 繪製進度條進度(進度條前預留2空格)
47                 Console.BackgroundColor = ConsoleColor.Yellow; // 設置進度條顏色
48                 Console.SetCursorPosition(2, 5); // 設置光標位置,參數爲第幾列和第幾行
49                 for (int i = 0; i <burnProgress.Percent*50; i++)
50                 {   //每一個整數寫入1個空格
51                     Console.Write(" "); // 移動進度條
52                 }
53                 Console.BackgroundColor = colorBack; // 恢復輸出顏色
54                 
55                 //第8行 已用時間,總時間
56                 Console.ForegroundColor = ConsoleColor.Green;// 更新進度百分比,原理同上.
57                 Console.SetCursorPosition(0, 7);
58                 Console.Write($"  進度:{burnProgress.PercentStr}  " +
59                     $"已用時間:{FormatTime(0, 0, burnProgress.ElapsedTime)}  " +
60                     $"剩餘時間:{FormatTime(0, 0, burnProgress.TotalTime - burnProgress.ElapsedTime)}");
61                 Console.Write("      ");    //填充空白區域
62                 Console.ForegroundColor = colorFore;
63 
64                 Console.SetCursorPosition(0, 9);    //光標 定位到第10行
65             };
66         }
View Code

運行結果以下,剩餘時間爲IMAPI2提供.並不必定準確.

四.BurnCdDemo獲取磁盤大小爲負數bug

在開始的時候,咱們說了使用BurnCdDemo獲取光盤大小爲負數.在實際開發的過程當中,也碰到了.由於咱們買的光盤太大了?達到8G,實際模擬刻錄時,沒那麼大.因此沒啥問題.

咱們看BurnCdDemo裏Recorder對象的代碼:

1 private long m_nDiskSize = 0;
2 private long m_nUseableSize = 0;
3 
4 //可用的
5 m_nUseableSize = msFormat.FreeSectorsOnMedia * 2048;
6 //總大小
7 m_nDiskSize = msFormat.TotalSectorsOnMedia * 2048;

msFormat.FreeSectorsOnMediamsFormat.TotalSectorsOnMedia類型爲int.你們想到緣由了吧.int溢出了.因此把後面的2048改成2048L就能夠了.看似正常的代碼,之後在碰到類型轉換時要多注意些.

五.總結

總結寫點啥呢.固然是最重要的哈.上源碼:https://github.com/279328316/RecorderHelper

若有問題,歡迎留言.

相關文章
相關標籤/搜索