Win32编程之文件设备(九)
一、文件的创建
CreateFile
是一个 Windows API 函数,用于创建或打开文件、设备、目录或管道。它是 Windows 操作系统中文件和 I/O 操作的基础之一。CreateFile
允许你指定文件的访问方式、共享模式、创建选项等,并返回一个文件句柄,通过该句柄可以执行读取、写入、关闭等操作。
以下是 CreateFile
函数的基本签名:
1 2 3 4 5 6 7 8 9 | HANDLE CreateFile( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); |
下面是各个参数的介绍:
lpFileName
:要创建或打开的文件的路径或名称。dwDesiredAccess
:指定对文件的访问权限,如 GENERIC_READ、GENERIC_WRITE、GENERIC_EXECUTE 等。dwShareMode
:指定其他进程是否可以同时访问该文件,如 FILE_SHARE_READ、FILE_SHARE_WRITE 等。lpSecurityAttributes
:指定一个SECURITY_ATTRIBUTES
结构,用于指定文件的安全属性,通常为NULL
。dwCreationDisposition
:指定文件的创建方式,如 CREATE_NEW、CREATE_ALWAYS、OPEN_EXISTING 等。dwFlagsAndAttributes
:指定文件的其他属性和标志,如 FILE_ATTRIBUTE_NORMAL、FILE_FLAG_WRITE_THROUGH 等。hTemplateFile
:可选参数,通常为NULL
。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <Windows.h> #include <iostream> int main() { HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "CreateFile failed!" << GetLastError() << std::endl; return 0; } std::cout << "CreateFile success!" << std::endl; CloseHandle(hFile); return 1; } |
INVALID_HANDLE_VALUE
是一个 Windows API 中定义的常量,用于表示无效的文件句柄(handle)。在 Windows 操作系统中,文件句柄是用于标识打开的文件、设备、管道等对象的一种标识符。INVALID_HANDLE_VALUE
表示一个无效或失败的文件句柄,通常用于指示文件打开或创建操作失败。当你调用诸如 CreateFile
、OpenFile
等文件操作函数时,如果操作失败或出现错误,这些函数通常会返回 INVALID_HANDLE_VALUE
来表示操作未成功。这可以作为错误处理的一部分,你可以检查函数的返回值是否等于 INVALID_HANDLE_VALUE
,如果是,则表示操作失败,然后可以使用 GetLastError
函数获取具体的错误代码,以便进行适当的错误处理。
二、文件的写入
1.WriteFile函数的介绍和使用
WriteFile
函数是 Windows API 中用于将数据写入文件或其他输出设备的函数。它通常用于将数据写入已经打开的文件句柄。
WriteFile
函数的基本签名:
1 2 3 4 5 6 7 | BOOL WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ); |
下面是各个参数的介绍:
hFile
:要写入的文件句柄,该句柄必须是已经打开的,并且具有适当的写入权限。lpBuffer
:一个指向包含要写入数据的缓冲区的指针。nNumberOfBytesToWrite
:要写入的字节数。lpNumberOfBytesWritten
:一个指向 DWORD 类型的指针,用于接收实际写入的字节数。可以为NULL
,表示不需要这个信息。lpOverlapped
:一个指向OVERLAPPED
结构的指针,通常用于异步 I/O 操作,可以为NULL
,表示同步操作。
2.FlushFileBuffers()函数的介绍和使用
FlushFileBuffers
函数是 Windows API 中用于刷新文件缓冲区的函数。它通常用于确保文件的写入操作已经完成,而不仅仅是将数据写入文件缓冲区。在某些情况下,文件写入操作可能会被操作系统延迟以提高性能,但 FlushFileBuffers
可以用来强制将缓冲区中的数据写入物理存储介质,例如硬盘,以确保数据不会丢失。
1 2 3 | BOOL FlushFileBuffers( HANDLE hFile ); |
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include <Windows.h> #include <stdio.h> #include <iostream> int main() { char buffer[] = "hello world" ; DWORD writeCount = 0; HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "CreateFile failed!" << GetLastError() << std::endl; return 0; } std::cout << "CreateFile success!" << std::endl; BOOL ret = WriteFile(hFile, buffer, strlen (buffer), &writeCount, NULL); if (!ret) { CloseHandle(hFile); std::cout << "WriteFile failed!" << std::endl; return 0; } std::cout << "WriteFile success!" << std::endl; if (!FlushFileBuffers(hFile)) { std::cout << "FlushFileBuffers failed!" << GetLastError() << std::endl; CloseHandle(hFile); return 0; } std::cout << "FlushFileBuffers success!" << std::endl; CloseHandle(hFile); return 1; } |
三、文件的读取
ReadFile
函数是 Windows API 中用于从文件、设备或管道中读取数据的函数。它通常用于从已打开的文件句柄中读取数据。
以下是 ReadFile
函数的基本签名:
1 2 3 4 5 6 7 | BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ); |
下面是各个参数的介绍:
hFile
:要读取数据的文件句柄,该句柄必须是已经打开的,并且具有适当的读取权限。lpBuffer
:一个指向用于接收读取数据的缓冲区的指针。nNumberOfBytesToRead
:要读取的字节数。lpNumberOfBytesRead
:一个指向 DWORD 类型的指针,用于接收实际读取的字节数。可以为NULL
,表示不需要这个信息。lpOverlapped
:一个指向OVERLAPPED
结构的指针,通常用于异步 I/O 操作,可以为NULL
,表示同步操作。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <Windows.h> #include <stdio.h> #include <iostream> int main() { char buffer[255] = {0}; DWORD readCount = 0; HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ , 0, NULL, OPEN_EXISTING, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "CreateFile failed!" << GetLastError() << std::endl; return 0; } BOOL ret = ReadFile(hFile, buffer, 255, &readCount, NULL); if (!ret) { CloseHandle(hFile); std::cout << "ReadFile failed!" << std::endl; return 0; } CloseHandle(hFile); std::cout << "read byte length:" << readCount << std::endl; std::cout << "buffer:" << buffer << std::endl; return 1; } |
四、解决UNICODE编码的问题
(1).文件的写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <Windows.h> #include <stdio.h> #include <iostream> int main() { wchar_t buffer[] = TEXT( "世界您好" ); DWORD writeCount = 0; HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "CreateFile failed!" << GetLastError() << std::endl; return 0; } std::cout << "CreateFile success!" << std::endl; wchar_t head = 0xfeff; BOOL ret = WriteFile(hFile, &head, sizeof (head), NULL, NULL); if (!ret) { CloseHandle(hFile); std::cout << "WriteFile failed!" << std::endl; return 0; } ret = WriteFile(hFile, buffer, wcslen(buffer)*2, &writeCount, NULL); if (!ret) { CloseHandle(hFile); std::cout << "WriteFile failed!" << std::endl; return 0; } std::cout << "WriteFile success!" << std::endl; if (!FlushFileBuffers(hFile)) { std::cout << "FlushFileBuffers failed!" << GetLastError() << std::endl; CloseHandle(hFile); return 0; } std::cout << "FlushFileBuffers success!" << std::endl; CloseHandle(hFile); return 1; } |
(2).文件的读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <Windows.h> #include <stdio.h> #include <iostream> #include <locale.h> int main() { wchar_t buffer[255] = {0}; DWORD readCount = 0; HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ , 0, NULL, OPEN_EXISTING, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "CreateFile failed!" << GetLastError() << std::endl; return 0; } LARGE_INTEGER liMove; liMove.QuadPart = 2; //文件指针向前移动两位 SetFilePointerEx(hFile, liMove, NULL, FILE_BEGIN); BOOL ret = ReadFile(hFile, buffer, 255, &readCount, NULL); if (!ret) { CloseHandle(hFile); std::cout << "ReadFile failed!" << std::endl; return 0; } CloseHandle(hFile); _wsetlocale(LC_ALL, L "chs" ); //setlocale(LC_ALL, "chs"); wprintf(L "%s" , buffer); return 1; } |
五、获取文件的大小
(1).GetFileSize函数的介绍和使用
GetFileSize
函数是 Windows API 中用于获取文件的大小(以字节为单位)的函数。它允许你查询已打开的文件或指定文件路径的大小。
以下是 GetFileSize
函数的基本签名:
1 2 3 4 | DWORD GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh ); |
参数解释如下:
hFile
:要获取大小的文件句柄,该句柄必须是已经打开的文件或设备的句柄。lpFileSizeHigh
:一个指向DWORD
类型的指针,用于接收文件大小的高位部分。可以为NULL
,表示不需要这个信息。
GetFileSize
函数返回文件的大小(以字节为单位),如果文件大小超过 DWORD
可表示的范围,lpFileSizeHigh
会被用来存储高位部分的大小。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <Windows.h> #include <stdio.h> int main() { HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ, 0, NULL, OPEN_EXISTING, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf ( "无法打开文件。错误码:%d\n" , GetLastError()); return 0; } DWORD fileSize = 0; DWORD fileSizeHigh = 0; //高位部分大小 fileSize = GetFileSize(hFile, &fileSizeHigh); if (fileSize == INVALID_FILE_SIZE) { printf ( "获取文件大小失败。错误码:%d\n" , GetLastError()); CloseHandle(hFile); return 1; } if (fileSizeHigh > 0) { printf ( "文件大小超过 DWORD 范围,高位部分大小:%d,低位部分大小:%d\n" , fileSizeHigh, fileSize); } else { printf ( "文件大小:%d 字节\n" , fileSize); } CloseHandle(hFile); return 1; } |
(2).GetFileSizeEx函数的介绍和使用
GetFileSizeEx
函数是 Windows API 中用于获取文件大小的函数,它可以返回一个 64 位整数,适用于大文件,因为它不受 DWORD
类型大小的限制。
以下是 GetFileSizeEx
函数的基本签名:
1 2 3 4 | BOOL GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize ); |
参数解释如下:
hFile
:要获取大小的文件句柄,该句柄必须是已经打开的文件或设备的句柄。lpFileSize
:一个指向LARGE_INTEGER
结构的指针,用于接收文件大小。
GetFileSizeEx
函数返回一个布尔值,如果成功获取文件大小,则返回 TRUE
,否则返回 FALSE
。文件大小将存储在 lpFileSize
中。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <Windows.h> #include <stdio.h> int main() { HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_READ, 0, NULL, OPEN_EXISTING, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf ( "无法打开文件。错误码:%d\n" , GetLastError()); return 0; } LARGE_INTEGER fileSize; if (!GetFileSizeEx(hFile, &fileSize)) { printf ( "获取文件大小失败。错误码:%d\n" , GetLastError()); CloseHandle(hFile); return 1; } printf ( "文件大小:%lld 字节\n" , fileSize.QuadPart); CloseHandle(hFile); return 1; } |
六、设置文件指针和文件尾
(1).SetFilePointerEx函数的介绍和使用
SetFilePointerEx
函数是 Windows API 中用于设置文件指针位置的函数。它允许你在已打开的文件中移动文件指针到指定的位置,以便进行读取或写入操作。与 SetFilePointer
不同,SetFilePointerEx
可以处理大文件,因为它使用 LARGE_INTEGER
结构来表示文件指针位置。以下是 SetFilePointerEx
函数的基本签名:
1 2 3 4 5 6 | BOOL SetFilePointerEx( HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod ); |
参数解释如下:
hFile
:要设置文件指针位置的文件句柄,该句柄必须是已经打开的文件或设备的句柄。liDistanceToMove
:一个LARGE_INTEGER
结构,表示要移动的距离。正值向文件的尾部移动,负值向文件的起始位置移动。lpNewFilePointer
:一个指向LARGE_INTEGER
结构的指针,用于接收新的文件指针位置。可以为NULL
,表示不需要这个信息。dwMoveMethod
:指定移动文件指针的方式,可以是以下值之一:FILE_BEGIN
:从文件的起始位置开始移动。FILE_CURRENT
:从当前文件指针位置开始移动。FILE_END
:从文件的尾部开始移动。
SetFilePointerEx
函数返回一个布尔值,如果成功设置文件指针位置,则返回 TRUE
,否则返回 FALSE
。
(2).SetEndOfFile函数介绍和使用
SetEndOfFile
函数是 Windows API 中用于设置文件的结束位置(文件大小)的函数。它通常用于调整文件的大小,可以用来扩展或缩小文件。
以下是 SetEndOfFile
函数的基本签名:
1 2 3 | BOOL SetEndOfFile( HANDLE hFile ); |
参数解释如下:
hFile
:要设置结束位置的文件句柄,该句柄必须是已经打开的文件或设备的句柄。
SetEndOfFile
函数返回一个布尔值,如果成功设置文件的结束位置,则返回 TRUE
,否则返回 FALSE
。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <Windows.h> #include <stdio.h> int main() { HANDLE hFile = CreateFile(TEXT( "test.txt" ), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, NULL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf ( "无法打开文件。错误码:%d\n" , GetLastError()); return 0; } LARGE_INTEGER liMove; liMove.QuadPart = 1024; SetFilePointerEx(hFile, liMove, NULL, FILE_END); SetEndOfFile(hFile); CloseHandle(hFile); return 1; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?