• C#光盘刻录


    一.背景介绍

    最近公司一个老项目需要添加导出数据到光盘的功能.开始对这功能添加有点抵触的.光盘?都啥年代了.

    光盘一种即将淘汰的存储媒介.就像当年的随身听,Mp3,Mp4一样,即将退出历史舞台.领导让加,发牢骚归发牢骚,活还是得干哈.

    从网上找了一些资料,都是特别古老的文档了.很多方法用起来并不是特别的方便.

    1.CodePlex Archive https://archive.codeplex.com/?p=csimapi2samples 其中的例子功能不全,参数都使用dynamic类型,刚开始不了解那些基础概念时,理解起来比较难.可以参考学习.

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

    里面的BurnCdDemo对ImApi2做了封装.其实例子里面的封装做的挺不错的.注释也特别全.

    在做测试的时候发现刻录功能在本机运行的非常好.在公司的测试机上却获取不到光盘大小,取到的大小是负数.对着Demo的源代码检查了半天,没找到原因.╮( ̄▽ ̄")╭,脑袋好大的.后来找到原因了,在下面的过程中会描述下.

    PS:个人不喜欢啥都做抽象.抽象,意味着要多写代码,查找问题也不方便.抽象,依赖注入,控制反转是个好东西,就是要多写许多代码.

    个人觉得,很多技术还是要看实际项目情况而使用,没有必要去为了追求使用而滥用.看起来高大上,实际多写了代码维护也不方便.

    So,自己搞个简单点的.因为就那么几个功能:获取光驱设备列表,获取光盘信息,添加媒体文件,刻录,进度通知.

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

     因工作电脑没有光驱,测试非常不方便.那我们就安装一个虚拟光驱.

    推荐一个比较好用的虚拟光驱软件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("
    ", ""); //去掉异常信息里的
    
    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#应用程序设置以管理员身份启动请参照https://www.cnblogs.com/babycool/p/3569183.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

    如有问题,欢迎留言.

  • 相关阅读:
    javascript如何处理字符串中的u
    查看postgresql的日志show queries log in PostgreSQL?
    angular7 promiss
    解决echarts的叠堆折线图数据出现坐标和值对不上的问题
    微信小程序将图片数据流添加到image标签中
    深入理解flex布局的flex-grow、flex-shrink、flex-basis
    优先级:content –> width –> flex-basis (limted by max|min-width)
    ubuntu17.10 python3.6 install plugins for AI
    tensorflow import 没找到cudnn库问题解决
    ubuntu17.10 安装ssh
  • 原文地址:https://www.cnblogs.com/arthur3k/p/10251356.html
Copyright © 2020-2023  润新知