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 表示一个无效或失败的文件句柄,通常用于指示文件打开或创建操作失败。当你调用诸如 CreateFileOpenFile 等文件操作函数时,如果操作失败或出现错误,这些函数通常会返回 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;
}

  

posted @   TechNomad  阅读(192)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示