开发者

C#中调用Windows API实现文件操作的代码实战

开发者 https://www.devze.com 2025-08-19 11:08 出处:网络 作者: 墨夶
目录为何选择Windows API?一、Windows API文件操作的核心函数1. 核心API函数概览二、C#中调用Windows API的基础准备1. P/Invoke声明2. 常量定义三、基础操作:文件的创建与读写1. 创建文件2. 写入数据3. 读取数据4.
目录
  • 为何选择Windows API?
  • 一、Windows API文件操作的核心函数
    • 1. 核心API函数概览
  • 二、C#中调用Windows API的基础准备
    • 1. P/Invoke声明
    • 2. 常量定义
  • 三、基础操作:文件的创建与读写
    • 1. 创建文件
    • 2. 写入数据
    • 3. 读取数据
    • 4. 关闭文件
    • 5. 完整示例:文件复制
  • 四、高级操作:文件指针控制与随机访问
    • 1. 移动文件指针
    • 2. 随机读写示例
  • 五、性能优化与异常处理
    • 1. 使用缓冲区优化读写
    • 2. 错误处理最佳实践
    • 3. 路径处理技巧
  • 六、与.NET IO类的对比
    • 七、实战场景:文件备份工具
      • 八、注意事项与常见问题
        • 1. 文件锁定问题
        • 2. 编码问题
        • 3. 文件属性与权限
      • 九、 Windows API的无限可能
        • Windows API的更多可能性

          为何选择Windows API?

          在C#开发中,文件操作通常依赖于System.IO命名空间下的类(如FileFileStream)。然而,这些类虽然封装了丰富的功能,但在某些场景下存在以下限制:

          • 性能瓶颈:对于高频文件读写或大文件处理,托管代码可能无法满足实时性需求。
          • 底层控制缺失:无法直接操作文件句柄、文件锁、文件属性等底层功能。
          • 跨平台兼容性问题:某些Windows特有的文件操作(如文件加密、访问控制列表)无法通过标准IO类实现。

          Windows API(如CreateFileReadFileWriteFile)提供了对文件系统的完全控制,是解决上述问题的终极方案。本文将通过真实项目级代码,带你从基础到高级掌握如何在C#中调用Windows API实现文件操作!

          一、Windows API文件操作的核心函数

          1. 核心API函数概览

          函数名功能描述适用场景
          CreateFile创建或打开文件/设备文件初始化、权限控制
          ReadFile从文件中读取数据高效读取大文件
          WriteFile向文件中写入数据实时日志记录、流式写入
          SetFilePointer移动文件指针随机访问文件内容
          CloseHandle关闭文件句柄资源释放、异常安全处理

          二、C#中调用Windows API的基础准备

          1. P/Invoke声明

          通过DllImport导入Windows API函数,并定义其参数和返回值。

          using System;
          using System.Runtime.InteropServices;
          using System.Text;
          
          // 导入kernel32.dll中的核心文件API
          [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
          public static extern IntPtr CreateFile(
              string lpFileName,               // 文件路径
              uint dwDesiredAccess,            // 访问模式(读/写/执行)
              uint dwShareMode,                // 共享模式
              IntPtr lpSecurityAttributes,     // 安全属性(通常为IntPtr.Zero)
              uint dwCreationDisposition,      // 创建/打开方式
              uint dwFlagsAndAttributes,       // 文件属性(如FILE_ATTRIBUTE_NORMAL)
              IntPtr hTemplateFile             // 模板文件句柄(通常为IntPtr.Zero)
          );
          
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern boopythonl ReadFile(
              IntPtr hFile,                    // 文件句柄
              byte[] lpBuffer,                 // 读取缓冲区
              uint nNumberOfBytesToRead,       // 要读取的字节数
              out uint lpNumberOfBytesRead,    // 实际读取的字节数
              IntPtr lpOverlapped              // 异步操作参数(同步操作设为IntPtr.Zero)
          );
          
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool WriteFile(
              IntPtr hFile,                    // 文件句柄
              byte[] lpBuffer,                 // 写入缓冲区
              uint nNumberOfBytesToWrite,      // 要写入的字节数
              out uint lpNumberOfBytesWritten, // 实际写入的字节数
              IntPtr lpOverlapped              // 异步操作参数(同步操作设为IntPtr.Zero)
          );
          
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool CloseHandle(IntPtr hObject); // 关闭句柄
          
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern uint SetFilePointer(
              IntPtr hFile,                    // 文件句柄
              int lDistanceToMove,             // 移动偏移量(正负均可)
              IntPtr lpDistanceToMoveHi编程客栈gh,     // 高32位偏移量(通常为IntPtr.Zero)
              uint dwMoveMethod                // 移动方式(如FILE_BEGIN)
          );
          

          2. 常量定义

          // 文件访问模式
          public const uint GENERIC_READ = 0x80000000;
          public const uint GENERIC_WRITE = 0x40000000;
          
          // 文件共享模式
          public const uint FILE_SHARE_READ = 0x00000001;
          public const uint FILE_SHARE_WRITE = 0x00000002;
          
          // 文件创建方式
          public const uint CREATE_NEW = 1;           // 创建新文件(失败条件:文件已存在)
          public const uint CREATE_ALWAYS = 2;        // 总是创建(覆盖已有文件)
          public const uint OPEN_EXISTING = 3;        // 打开已有文件(失败条件:文件不存在)
          
          // 文件移动方式
          public const uint FILE_BEGIN = 0;           // 从文件开头移动
          public const uint FILE_CURRENT = 1;         // 从当前位置移动
          public const uint FILE_END = 2;             // 从文件末尾移动
          
          // 文件属性
          public const uint FILE_ATTRIBUTE_NORMAL = 0x80; // 普通文件
          

          三、基础操作:文件的创建与读写

          1. 创建文件

          public static IntPtr CreateFileExample(string filePath) {
              // 打开或创建文件(覆盖模式)
              IntPtr hFile = CreateFile(
                  filePath,
                  GENERpythonIC_WRITE,                  // 写入权限
                  0,                              // 不共享
                  IntPtr.Zero,
                  CREATE_ALWAYS,                  // 总是创建新文件
                  FILE_ATTRIBUTE_NORMAL,
                  IntPtr.Zero
              );
          
              if (hFile == IntPtr.Zero || hFile == new IntPtr(-1)) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "创建文件失败");
              }
          
              return hFile;
          }
          

          2. 写入数据

          public static void WriteFileExample(IntPtr hFile, string data) {
              byte[] buffer = Encoding.UTF8.GetBytes(data); // 将字符串转为字节数组
              uint bytesWritten;
          
              bool success = WriteFile(
                  hFile,
                  buffer,
                  (uint)buffer.Length,
                  out bytesWritten,
                  IntPtr.Zero
              );
          
              if (!success) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "写入文件失败");
              }
          
              Console.WriteLine($"成功写入 {bytesWritten} 字节");
          }
          

          3. 读取数据

          public static string ReadFileExample(IntPtr hFile, int bufferSize = 1024) {
              byte[] buffer = new byte[bufferSize];
              uint bytesRead;
          
              bool success = ReadFile(
                  hFile,
                  buffer,
                  (uint)bufferSize,
                  out bytesRead,
                  IntPtr.Zero
              );
          
              if (!success) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "读取文件失败");
              }
          
              return Encoding.UTF8.GetString(buffer, 0, (int)bytesRead);
          }
          

          4. 关闭文件

          public static void CloseFileExample(IntPtr hFile) {
              if (!CloseHandle(hFile)) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "关闭文件失败");
              }
          }
          

          5. 完整示例:文件复制

          public static void CopyFileUsingAPI(string sourcePath, 编程客栈string destPath) {
              IntPtr hSource = CreateFile(
                  sourcePath,
                  GENERIC_READ,
                  FILE_SHARE_READ,
                  IntPtr.Zero,
                  OPEN_EXISTING,
                  FILE_ATTRIBUTE_NORMAL,
                  IntPtr.Zero
              );
          
              if (hSource == IntPtr.Zero || hSource == new IntPtr(-1)) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "打开源文件失败");
              }
          
              IntPtr hDest = CreateFileExample(destPath);
          
              try {
                  byte[] buffer = new byte[4096]; // 4KB缓冲区
                  uint bytesRead;
          
                  do {
                      // 读取源文件
                      if (!ReadFile(hSource, buffer, (uint)buffer.Length, out bytesRead, IntPtr.Zero)) {
                          throw new Win32Exception(Marshal.GetLastWin32Error(), "读取源文件失败");
                      }
          
                      if (bytesRead > 0) {
                          // 写入目标文件
                          uint bytesWritten;
                          if (!Write编程File(hDest, buffer, bytesRead, out bytesWritten, IntPtr.Zero)) {
                              throw new Win32Exception(Marshal.GetLastWin32Error(), "写入目标文件失败");
                          }
                      }
                  } while (bytesRead > 0); // 循环直到读取完成
              } finally {
                  CloseHandle(hSource);
                  CloseHandle(hDest);
              }
          }
          

          四、高级操作:文件指针控制与随机访问

          1. 移动文件指针

          public static void MoveFilePointerExample(IntPtr hFile, int offset, uint moveMethod) {
              uint newpointer = SetFilePointer(
                  hFile,
                  offset,
                  IntPtr.Zero,
                  moveMethod
              );
          
              if (newPointer == 0xFFFFFFFF) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "移动文件指针失败");
              }
          
              Console.WriteLine($"文件指针新位置: {newPointer} 字节");
          }
          

          2. 随机读写示例

          public static void RandoMACcessExample(string filePath) {
              IntPtr hFile = CreateFile(
                  filePath,
                  GENERIC_READ | GENERIC_WRITE,
                  0,
                  IntPtr.Zero,
                  OPEN_EXISTING,
                  FILE_ATTRIBUTE_NORMAL,
                  IntPtr.Zero
              );
          
              if (hFile == IntPtr.Zero || hFile == new IntPtr(-1)) {
                  throw new Win32Exception(Marshal.GetLastWin32Error(), "打开文件失败");
              }
          
              try {
                  // 移动指针到文件开头
                  MoveFilePointerExample(hFile, 0, FILE_BEGIN);
          
                  // 读取前10字节
                  byte[] buffer = new byte[10];
                  uint bytesRead;
                  ReadFile(hFile, buffer, 10, out bytesRead, IntPtr.Zero);
                  Console.WriteLine($"前10字节内容: {Encoding.UTF8.GetString(buffer, 0, (int)bytesRead)}");
          
                  // 移动指针到文件末尾
                  MoveFilePointerExample(hFile, 0, FILE_END);
          
                  // 写入新内容到末尾
                  string newData = " - 附加内容";
                  byte[] newBuffer = Encoding.UTF8.GetBytes(newData);
                  uint bytesWritten;
                  WriteFile(hFile, newBuffer, (uint)newBuffer.Length, out bytesWritten, IntPtr.Zero);
                  Console.WriteLine($"成功追加 {bytesWritten} 字节");
              } finally {
                  CloseHandle(hFile);
              }
          }
          

          五、性能优化与异常处理

          1. 使用缓冲区优化读写

          • 大文件处理:增大缓冲区大小(如4KB或8KB)可减少系统调用次数。
          • 异步操作:通过lpOverlapped参数实现异步读写(需结合线程或回调)。

          2. 错误处理最佳实践

          • 始终检查返回值:Windows API函数失败时返回false0
          • 获取错误码:通过Marshal.GetLastWin32Error()获取具体错误信息。
          • 资源释放:使用try-finally确保文件句柄关闭。

          3. 路径处理技巧

          • 绝对路径:使用Path.GetFullPath()确保路径合法性。
          • 权限控制:通过lpSecurityAttributes参数设置文件访问权限。

          六、与.NET IO类的对比

          特性Windows API.NET System.IO 类
          性能更快(直接调用内核)封装后略有性能损耗
          底层控制完全控制文件句柄、指针等封装简化,但灵活性受限
          易用性需手动管理资源和错误提供高级封装(如File.Copy)
          跨平台仅限Windows跨平台支持(通过.NET Core)

          七、实战场景:文件备份工具

          public static void BackupFile(string source, string backup) {
              try {
                  // 创建备份文件
                  IntPtr hBackup = CreateFileExample(backup);
          
                  // 打开源文件
                  IntPtr hSource = CreateFile(
                      source,
                      GENERIC_READ,
                      FILE_SHARE_READ,
                      IntPtr.Zero,
                      OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      IntPtr.Zero
                  );
          
                  if (hSource == IntPtr.Zero || hSource == new IntPtr(-1)) {
                      throw new Win32Exception(Marshal.GetLastWin32Error(), "打开源文件失败");
                  }
          
                  try {
                      byte[] buffer = new byte[8192]; // 8KB缓冲区
                      uint bytesRead;
          
                      do {
                          // 读取源文件
                          if (!ReadFile(hSource, buffer, (uint)buffer.Length, out bytesRead, IntPtr.Zero)) {
                              throw new Win32Exception(Marshal.GetLastWin32Error(), "读取源文件失败");
                          }
          
                          if (bytesRead > 0) {
                              // 写入备份文件
                              uint bytesWritten;
                              if (!WriteFile(hBackup, buffer, bytesRead, out bytesWritten, IntPtr.Zero)) {
                                  throw new Win32Exception(Marshal.GetLastWin32Error(), "写入备份文件失败");
                              }
                          }
                      } while (bytesRead > 0);
          
                      Console.WriteLine("文件备份完成!");
                  } finally {
                      CloseHandle(hSource);
                      CloseHandle(hBackup);
                  }
              } catch (Exception ex) {
                  Console.WriteLine($"备份失败: {ex.Message}");
              }
          }
          

          八、注意事项与常见问题

          1. 文件锁定问题

          • 共享模式:设置dwShareMode参数(如FILE_SHARE_READ)可允许多个进程同时访问文件。
          • 独占访问:若需独占文件,设置dwShareMode为0并捕获ERROR_SHARING_VIOLATION错误。

          2. 编码问题

          • 文本文件:确保使用正确的编码(如UTF-8)读写数据。
          • 二进制文件:直接操作字节数组,无需编码转换。

          3. 文件属性与权限

          • 权限控制:通过lpSecurityAttributes参数设置文件访问权限(如只读、隐藏)。
          • 文件属性:使用FILE_ATTRIBUTE_HIDDEN等常量设置文件属性。

          九、 Windows API的无限可能

          通过本文的实战指南,你应该已经掌握了:

          1. 如何通过P/Invoke调用Windows API实现文件操作
          2. 如何高效读写文件并控制文件指针
          3. 如何处理错误和优化性能

          Windows API 是C#开发者手中的瑞士军刀,它赋予你对文件系统的完全控制权。无论是开发高性能文件处理工具,还是实现Windows特有的文件管理功能,Windows API都能成为你的得力助手!

          Windows API的更多可能性

          • 文件加密:使用CryptProtectFileCryptUnprotectFile实现文件级加密。
          • 访问控制:通过SetSecurityInfo设置文件的访问控制列表(ACL)。
          • 文件监控:使用ReadDirectoryChangesW实时监控文件夹变化。

          以上就是C#中调用Windows API实现文件操作的代码实战的详细内容,更多关于C# Windows API文件操作的资料请关注编程客栈(www.devze.com)其它相关文章!

          0

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          关注公众号