前言
- 各位师傅大家好,我是qmx_07,今天主要介绍使用windows系统编程操作读写文件
文件
CreateFile()函数讲解
-
介绍:该函数用于打开文件或者I/O流设备,文件、文件流、目录、物理磁盘、卷、控制台缓冲区、磁带驱动器、通信资源、mailslot 和管道
-
接下来我们学习一下CreateFile这个函数,需要对各参数有一定了解
函数原型:
HANDLE CreateFileA(
[in] LPCSTR lpFileName, //要打开的文件名称
[in] DWORD dwDesiredAccess,//对文件的访问权限,比如读写
[in] DWORD dwShareMode,//文件的共享权限
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,//指针
[in] DWORD dwCreationDisposition,//对已经存在的文件,或不存在的文件 进行什么操作
[in] DWORD dwFlagsAndAttributes,//文件或设备属性标志
[in, optional] HANDLE hTemplateFile//模版文件
);
简单了解参数含义,接下来进行详细讲解
这边的A 版本代表Ascii环境,W代表 Unicode环境,EX代表拓展版本函数
lpFileName
- 要创建的文件或者设备名称,假如我要在D盘创建hello.txt,该参数内容如下:
D:\\hello.txt
- 一般会将该参数限制到MAX_PATH字符为260
dwDesiredAccess
- 对文件或者设备的访问权限
- 常见的全部权限、可读、可写、可执行
dwShareMode
- 文件或者设备的共享模式,如果为NULL,则不允许共享访问
lpSecurityAttributes
- 该参数主要用作继承
- 文件操作:文件的访问权限和句柄的继承属性
- 进程创建:继承父进程的资源访问
dwCreationDisposition
- 对于已经存在的文件,或不存在的文件,做出操作
- 以上是对文件的两种状况,及作用总结
dwFlagsAndAttributes
- 设置文件的属性或标志
- 这几个文件属性比较常用
hTemplateFile
- GENERIC_READ 访问权限的模板文件的有效句柄
写文件
HANDLE hFile = CreateFile("G:\\qmx.ini", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
std::cout << "CreateFile Faild" << std::endl;
std::cout << GetLastError() << std::endl;
}
CHAR * Buffer[MAX_PATH] = { 0 };
CHAR arr[20] = "hello world!";
DWORD length = strlen(arr);
memcpy(Buffer, arr, length);
DWORD NumerOfBytesWritten = 0;
BOOL Ret = WriteFile(hFile, Buffer, length, &NumerOfBytesWritten, NULL);
if (!Ret)
{
std::cout << "WriteFile Faild" << std::endl;
std::cout << GetLastError() << std::endl;
}
CloseHandle(hFile);
- 通过CreateFile创建文件句柄(具有读写权限的普通文件打开)
- 将向写入的数据写入Buffer,利用WriteFile()写入文件
- CloseHandle() 关闭句柄
文件被成功写入
WriteFile()
函数原型:
BOOL WriteFile(
[in] HANDLE hFile, //文件或设备句柄
[in] LPCVOID lpBuffer,//缓冲区
[in] DWORD nNumberOfBytesToWrite,//写入字符的长度
[out, optional] LPDWORD lpNumberOfBytesWritten,//实际写入字符的长度
[in, out, optional] LPOVERLAPPED lpOverlapped//表示异步I/O操作
);
- 创建变量NumerOfBytesWritten,用于存储实际写入的长度,NULL 表示进行同步写入操作
- WriteFile返回值,如果函数写入失败返回False,写入成功返回True
错误码调试
- 将前面写好的文件,改为 CREATE_NEW,使用GetLastError()捕获错误码
- 在工具中的错误查找,查询错误码,能够快速了解到哪里有问题
- INVALID_HANDLE_VALUE 代表句柄失效
读取文件
HANDLE hFile = CreateFile("G:\\qmx.ini", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
std::cout << "CreateFile Faild" << std::endl;
std::cout << GetLastError() << std::endl;
}
LARGE_INTEGER FileSize;
if (!GetFileSizeEx(hFile, &FileSize))
{
std::cout << "GetFileSizeEx Failed" << std::endl;
std::cout << GetLastError() << std::endl;
}
CHAR* Buffer = new CHAR[FileSize.LowPart + 1];
memset(Buffer, 0, FileSize.LowPart + 1);
DWORD NumberOfBytesRead = 0;
BOOL Ret = ReadFile(hFile, Buffer, FileSize.LowPart, &NumberOfBytesRead, NULL);
if (!Ret)
{
std::cout << "ReadFile Faild" << std::endl;
std::cout << GetLastError() << std::endl;
}
std::cout << Buffer << std::endl;
CloseHandle(hFile);
- 通过CreateFile创建文件句柄(具有读写权限的普通文件打开)
- 创建LARGE_INTEGER类型的变量用于存储文件大小,通过GetFileSizeEx判断能否存储
- 使用ReadFile将文件数据存储到Buffer,并输出
ReadFile
- LARGE_INTEGER类型原型:
- LowPart存储着32位无符号整型,如果溢出则使用HighPart
BOOL ReadFile(
[in] HANDLE hFile,//文件或设备句柄
[out] LPVOID lpBuffer,//缓冲区
[in] DWORD nNumberOfBytesToRead,//读取长度
[out, optional] LPDWORD lpNumberOfBytesRead,//实际读取的长度
[in, out, optional] LPOVERLAPPED lpOverlapped//表示异步I/O操作
);
- 读取文件内容,通过FileSize.LowPart 获取文件读取长度,写入Buffer
- ReadFile返回值,如果函数写入失败返回False,写入成功返回True
文件随机读写
- 不从开头开始读取,需要使用setFilePointer函数
原型:
DWORD SetFilePointer(
[in] HANDLE hFile,//文件句柄
[in] LONG lDistanceToMove,//移动的步长
[in, out, optional] PLONG lpDistanceToMoveHigh,//高32位
[in] DWORD dwMoveMethod//文件指针的位置
);
- 通过setFilePointer函数移动两位步长
文件操作
移动文件
MoveFile(源文件,目标文件),用于移动文件位置
- 原理:通过读取文件内容,写入新文件,再将源文件删除
删除文件
- 通过DeleteFile(源文件)删除文件
复制文件
- CopyFile(源文件,目标文件,True) 用于复制文件
总结
- 介绍了CreateFile()、WriteFile()、ReadFile()参数详解,以及读写文件的函数使用,怎么利用错误码调试