ISO文件格式被很多虚拟光驱软件和刻录软件支持,比较典型的有WinISO ,Alcohol 120%这些软件.有的时候需要自己制作一个ISO文件的话,则需要找专门的工具;其实要做一个ISO的文件可以很简单,就是把光盘的所有数据映射到文件,只要你可以读光盘的数据就可以生成它.但是,它不是单纯的把光盘上的文件都读入,而是要把整个磁盘信息读入,那么你必须访问磁盘数据,而不是文件;
在WINDOWS下读取磁盘的方法很简单,按该方法也可以读取引导区信息;具体如下:
CreateFile("\\\\.\\"+driverName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
在.net 下,要作到这种模式的访问,使用FileStream可行不通,程序运行的时候会直接报个异常,阻止你访问Win32 设备磁盘.那么只能使用原始的做法,声明API.通过SafeFileHandle将文件句柄传递给托管的流进行读写操作.具体做法如下:
![](/Images/OutliningIndicators/ContractedBlock.gif)
使用 SafeFileHandle 类和非托管 CreateFile 函数打开 Win32 设备
1![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//// <summary>
2
/// 使用 SafeFileHandle 类和非托管 CreateFile 函数打开 Win32 设备
3
/// </summary>
4
class UnmanagedDriverLoader
5![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
6
public const short FILE_ATTRIBUTE_NORMAL = 0x80;
7
public const short INVALID_HANDLE_VALUE = -1;
8
public const uint GENERIC_READ = 0x80000000;
9
public const uint GENERIC_WRITE = 0x40000000;
10
public const uint FILE_SHARE_READ = 0x00000001;
11
public const uint CREATE_NEW = 1;
12
public const uint CREATE_ALWAYS = 2;
13
public const uint OPEN_EXISTING = 3;
14![](/Images/OutliningIndicators/InBlock.gif)
15
[DllImport("kernel32.dll", SetLastError = true)]
16
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
17
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
18
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
19![](/Images/OutliningIndicators/InBlock.gif)
20
private SafeFileHandle handleValue = null;
21![](/Images/OutliningIndicators/InBlock.gif)
22
public UnmanagedDriverLoader(string driverName)
23![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
24
Load(driverName);
25
}
26![](/Images/OutliningIndicators/InBlock.gif)
27
public void Load(string driverName)
28![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
if (driverName == null && driverName.Length == 0)
30![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
31
throw new ArgumentNullException("driverName");
32
}
33![](/Images/OutliningIndicators/InBlock.gif)
34
handleValue = CreateFile("\\\\.\\"+driverName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
35![](/Images/OutliningIndicators/InBlock.gif)
36
if (handleValue.IsInvalid)
37![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
39
}
40
}
41![](/Images/OutliningIndicators/InBlock.gif)
42
public SafeFileHandle Handle
43![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
44
get
45![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
46
if (!handleValue.IsInvalid)
47![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
48
return handleValue;
49
}
50
else
51![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
52
return null;
53
}
54
}
55
}
56
}
有了SafeFileHandle 之后,就可以使用FileStream 流来对其操作了;
首先确定磁盘的大小,再建立一个缓冲区,和一个目标文件用于写入;我建立的缓冲区是10兆,因为光驱比较快,内存也够用。
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**////10兆一个块
int bufferSize = 10240;
byte[] buffer = new byte[bufferSize];
剩下的事情就简单多了;只需要按块读入,并写到目标文件内:
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**////计算块的分页大小
long icount = (long)(GetCDROMSize(driverName) / bufferSize);
if ((GetCDROMSize(driverName) % bufferSize) != 0)
icount++;
long length = bufferSize;
![](/Images/OutliningIndicators/None.gif)
hDriver.Seek(0, SeekOrigin.Begin);
hIso.Seek(0, SeekOrigin.Begin);
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**////遍历块写到文件
for (long i = 0; i < icount; i++)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
hDriver.Read(buffer, 0, (int)length);
hIso.Write(buffer, 0, (int)length);
![](/Images/OutliningIndicators/InBlock.gif)
length = GetCDROMSize(driverName) - hDriver.Position;
![](/Images/OutliningIndicators/InBlock.gif)
if (OnProgress != null)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
OnProgress(this, 0, GetCDROMSize(driverName), hIso.Length);
}
if (length > bufferSize)
length = bufferSize;
}
![](/Images/OutliningIndicators/None.gif)
hDriver.Close();
hIso.Close();
OK,一个磁盘的镜像文件就建立好了,那么可以试试用 WinRar 或 Daemon Tools 装入试试;一切很正常。
根据以上的代码,我作了个DEMO,用于对光盘创建ISO镜像.一样很简单,可以先看看界面.
![](/images/cnblogs_com/chinasf/ISO.NET.JPG)
以下是它的源码,直接下载
/Files/Chinasf/ISO.NET.rar2006年4月29日