30人参与 • 2025-08-17 • Asp.net
在c#开发中,文件操作通常依赖于system.io
命名空间下的类(如file
、filestream
)。然而,这些类虽然封装了丰富的功能,但在某些场景下存在以下限制:
windows api(如createfile
、readfile
、writefile
)提供了对文件系统的完全控制,是解决上述问题的终极方案。本文将通过真实项目级代码,带你从基础到高级掌握如何在c#中调用windows api实现文件操作!
函数名 | 功能描述 | 适用场景 |
---|---|---|
createfile | 创建或打开文件/设备 | 文件初始化、权限控制 |
readfile | 从文件中读取数据 | 高效读取大文件 |
writefile | 向文件中写入数据 | 实时日志记录、流式写入 |
setfilepointer | 移动文件指针 | 随机访问文件内容 |
closehandle | 关闭文件句柄 | 资源释放、异常安全处理 |
通过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 bool 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 lpdistancetomovehigh, // 高32位偏移量(通常为intptr.zero) uint dwmovemethod // 移动方式(如file_begin) );
// 文件访问模式 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; // 普通文件
public static intptr createfileexample(string filepath) { // 打开或创建文件(覆盖模式) intptr hfile = createfile( filepath, generic_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; }
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} 字节"); }
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); }
public static void closefileexample(intptr hfile) { if (!closehandle(hfile)) { throw new win32exception(marshal.getlastwin32error(), "关闭文件失败"); } }
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 (!writefile(hdest, buffer, bytesread, out byteswritten, intptr.zero)) { throw new win32exception(marshal.getlastwin32error(), "写入目标文件失败"); } } } while (bytesread > 0); // 循环直到读取完成 } finally { closehandle(hsource); closehandle(hdest); } }
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} 字节"); }
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); } }
lpoverlapped
参数实现异步读写(需结合线程或回调)。false
或0
。marshal.getlastwin32error()
获取具体错误信息。try-finally
确保文件句柄关闭。path.getfullpath()
确保路径合法性。lpsecurityattributes
参数设置文件访问权限。特性 | 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}"); } }
dwsharemode
参数(如file_share_read
)可允许多个进程同时访问文件。dwsharemode
为0并捕获error_sharing_violation
错误。lpsecurityattributes
参数设置文件访问权限(如只读、隐藏)。file_attribute_hidden
等常量设置文件属性。通过本文的实战指南,你应该已经掌握了:
windows api 是c#开发者手中的瑞士军刀,它赋予你对文件系统的完全控制权。无论是开发高性能文件处理工具,还是实现windows特有的文件管理功能,windows api都能成为你的得力助手!
cryptprotectfile
和cryptunprotectfile
实现文件级加密。setsecurityinfo
设置文件的访问控制列表(acl)。readdirectorychangesw
实时监控文件夹变化。以上就是c#中调用windows api实现文件操作的代码实战的详细内容,更多关于c# windows api文件操作的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论