牛骨文教育服务平台(让学习变的简单)
博文笔记

windows编程之文件操作

创建时间:2016-06-15 投稿人: 浏览次数:1777
总所周知,C/C++标准库里边,有fread,fopen等文件操作,而在windows环境下,微软当然也给我们提供了这样的API,而且比C/C++运行库更好用,效率更高。 首先,要进行文件操作,你得打开一个文件或者创建一个文件,而CreateFile这个API就是用来打开和创建一个文件(因为在操作系统看来,系统上的所有东西都是一个个文件,因此,那些串口,硬盘都可以用CreateFile打开)。
HANDLE CreateFile(  
  LPCTSTR lpFileName,       		      // 文件名
  DWORD dwDesiredAccess,                      // 访问权限
  DWORD dwShareMode,                          // 共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性,一般为0
  DWORD dwCreationDisposition,                // 怎样创建
  DWORD dwFlagsAndAttributes,                 // 文件属性和标志,若读写是要用到异步方式,则设为FILE_FLAG_OVERLAPPED
  HANDLE hTemplateFile                        // 模板创建文件的句柄,一般用不到,给0
);

若该函数失败,返回INVALID_HANDLE_VALUE,不返回NULL。成功返回文件的句柄。 打开完文件之后,就可以进行读写了,这涉及到ReadFile和WriteFile两个API,他们的声明如下:
BOOL ReadFile(  
  HANDLE hFile,                // 文件的句柄
  LPVOID lpBuffer,             // 用于接收数据的缓冲区
  DWORD nNumberOfBytesToRead,  // 指定读多少字节
  LPDWORD lpNumberOfBytesRead, // 接收读取的字节数
  LPOVERLAPPED lpOverlapped    // 若该参不为NULL,则为异步方式读取
);
BOOL WriteFile(  
  HANDLE hFile,                    // 文件的句柄
  LPCVOID lpBuffer,                // 指向要写入到文件的缓冲区
  DWORD nNumberOfBytesToWrite,     // 要写的字节数
  LPDWORD lpNumberOfBytesWritten,  // 已写入的字节数的指针
  LPOVERLAPPED lpOverlapped        // 是否已异步方式进行写入
);
在读写的时候我们可以指定从哪里开始读或写,我们可以调用SetFilePointer这个函数,其声明如下:
DWORD SetFilePointer(  
  HANDLE hFile,                // 文件句柄
  LONG lDistanceToMove,        // 移动的字节数,低32位
  PLONG lpDistanceToMoveHigh,  // 若移动的字节数超过4GB,则高32位在此指定
  DWORD dwMoveMethod           // 在哪开始偏移,开头,结尾,当前
);
若要读写整个文件,我们可以先获取一下整个文件的大小,我们可以调用GetFileSize这个函数,声明 如下:
DWORD GetFileSize(  
  HANDLE hFile,           // 文件的句柄
  LPDWORD lpFileSizeHigh  // 若文件大小超过4GB的大小,则该参数不应为0
);
若你要进行异步方式读或写,则应该指定OVERLAPPED这个结构体,声明如下:
typedef struct _OVERLAPPED {
    ULONG_PTR Internal;		//状态码(该参不能以命名进行理解,这是微软当时遗留的问题,最开始,微软并不是状态码,后来把它改了,命名却遗留了下来)
    ULONG_PTR InternalHigh;	//指定了总共写入或读取的字节数(该参和上一个参数一样,都是微软的遗留问题)
    union {
        struct {
            DWORD Offset;	//偏移量,从哪里开始读写,低32位
            DWORD OffsetHigh;	//偏移量,从哪里开始读写,高32位
        } DUMMYSTRUCTNAME;
        PVOID Pointer;		//指向文件的位置,操作系统使用
    } DUMMYUNIONNAME;

    HANDLE  hEvent;		//系统的内核事件句柄
} OVERLAPPED, *LPOVERLAPPED;
下面是一段简单的代码,对以上进行练习:

#include <windows.h>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hfile = CreateFile(_T("test.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,FILE_FLAG_OVERLAPPED, 0);
	if (hfile == INVALID_HANDLE_VALUE)
	{
		printf("open file error
");
		return -1;
	}
	
	DWORD dwSize = 0;
	DWORD dwSizeHigh = 0;
	//获取文件的大小
	dwSize = GetFileSize(hfile, &dwSizeHigh);
	// 创建缓冲区
	byte * buf = new byte[dwSize+dwSizeHigh+1];
	// 清空缓冲区
	ZeroMemory(buf, dwSize + dwSizeHigh + 1);
	//从开头进行读写
	SetFilePointer(hfile, 0, 0, FILE_BEGIN);
	DWORD dwRead = 0;

	// 使用异步方式读取文件
	OVERLAPPED ov = { 0 }; 
	ov.Offset = 2; // 读取的偏移 2 
	ov.OffsetHigh = 0;
	ov.hEvent = CreateEvent(0, true, false, 0); //创建一个事件内核对象
	//读文件
	ReadFile(hfile, buf, dwSize + dwSizeHigh, &dwRead, &ov);
	//因为是以异步方式进行读取的,所以dwRead读取的字节数应为0
	if (dwRead == dwSize)
	{
		printf("read file");
	}
	//我们要等待所有的文件大小读完,应调用下面这个等待函数
	WaitForSingleObject(ov.hEvent,  INFINITE); // INFINITE代表无限等待
	//应为偏移量为2,所以读取的字节数应与文件的大小少2个字节
	if (ov.InternalHigh != dwSize -2)
	{
		printf("read failed
");
		return -1;
	}
	//将读取的内容输出
	printf("%s
", buf);
	CloseHandle(hfile); // 关闭句柄
	return 0;
}


声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。