下面的示例通过读取并显示一个文本文件来演示 Windows ReadFile 函数。ReadFile 函数需要使用 unsafe 代码,因为它需要一个作为参数的指针。
传递到 Read
函数的字节数组是托管类型。这意味着公共语言运行库 (CLR) 垃圾回收器可能会随意地对数组使用的内存进行重新定位。为了防止出现这种情况,使用 fixed 来获取指向内存的指针并对它进行标记,以便垃圾回收器不会移动它。在 fixed 块的末尾,内存将自动返回,以便能够通过垃圾回收移动。
此功能称为“声明式锁定”。锁定的好处是系统开销非常小,除非在 fixed 块中发生垃圾回收(但此情况不太可能发生)。
示例
C# | ![]() |
---|---|
class FileReader { const uint GENERIC_READ = 0x80000000; const uint OPEN_EXISTING = 3; System.IntPtr handle; [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)] static extern unsafe System.IntPtr CreateFile ( string FileName, // file name uint DesiredAccess, // access mode uint ShareMode, // share mode uint SecurityAttributes, // Security Attributes uint CreationDisposition, // how to create uint FlagsAndAttributes, // file attributes int hTemplateFile // handle to template file ); [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)] static extern unsafe bool ReadFile ( System.IntPtr hFile, // handle to file void* pBuffer, // data buffer int NumberOfBytesToRead, // number of bytes to read int* pNumberOfBytesRead, // number of bytes read int Overlapped // overlapped buffer ); [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)] static extern unsafe bool CloseHandle ( System.IntPtr hObject // handle to object ); public bool Open(string FileName) { // open the existing file for reading handle = CreateFile ( FileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0 ); if (handle != System.IntPtr.Zero) { return true; } else { return false; } } public unsafe int Read(byte[] buffer, int index, int count) { int n = 0; fixed (byte* p = buffer) { if (!ReadFile(handle, p + index, count, &n, 0)) { return 0; } } return n; } public bool Close() { return CloseHandle(handle); } } class Test { static int Main(string[] args) { if (args.Length != 1) { System.Console.WriteLine("Usage : ReadFile <FileName>"); return 1; } if (!System.IO.File.Exists(args[0])) { System.Console.WriteLine("File " + args[0] + " not found."); return 1; } byte[] buffer = new byte[128]; FileReader fr = new FileReader(); if (fr.Open(args[0])) { // Assume that an ASCII file is being read. System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding(); int bytesRead; do { bytesRead = fr.Read(buffer, 0, buffer.Length); string content = Encoding.GetString(buffer, 0, bytesRead); System.Console.Write("{0}", content); } while (bytesRead > 0); fr.Close(); return 0; } else { System.Console.WriteLine("Failed to open requested file"); return 1; } } } |