# 异步IO操作
CreateFile 使用
VS2015 新建win32 控制台应用程序 WindowsFileDemo
win32控制台写窗口程序
需要加入头文件 #include <fileAPI.h> 就可以来使用CreateFile
分别有 CreateFileA CreateFileW 窄字节 宽字节
1 HANDLE WINAPI CreateFile( 2 _In_ LPCTSTR lpFileName, 3 _In_ DWORD dwDesiredAccess, 4 _In_ DWORD dwShareMode, 5 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, 6 _In_ DWORD dwCreationDisposition, 7 _In_ DWORD dwFlagsAndAttributes, 8 _In_opt_ HANDLE hTemplateFile 9 );
//第一个参数 LPCTSTR lpFileName 文件名
//第二个参数 DWORD dwDesiredAccess 访问权限
GENERIC_ALL 所有权限 需要管理员权限 否则可能打开失败
GENERIC_EXECUTE 文件是否存在
GENERIC_READ 读
GENERIC_WRITE 写
GENERIC_READ | GENERIC_WRITE 组合
//第三个参数 DWORD dwShareMode 打开后是否共享 不需要共享的话就写入0
0
FILE_SHARE_DELETE
FILE_SHARE_READ
FILE_SHARE_WRITE
//第四个参数 lpSecurityAttributes 一般填写nullpte
用来设定一个指向包含两个不同但相关的数据成员:一个可选的安全描述符和一个布尔值来决定是否由子进程返回的句柄可以被继承。
//第五个参数 DWORD dwCreationDisposition 打开方式
CREATE_NEW 创建文件;如文件存在则会出错
CREATE_ALWAYS 创建文件,会改写前一个文件
OPEN_EXISTING 文件必须已经存在。由设备提出要求
OPEN_ALWAYS 如文件不存在则创建它
TRUNCATE_EXISTING 将现有文件缩短为零长度
//第六个参数 dwFlagsAndAttributesLong, 一个或多个下述常数
FILE_ATTRIBUTE_ARCHIVE 标记归档属性
FILE_ATTRIBUTE_COMPRESSED 将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式
FILE_ATTRIBUTE_NORMAL 默认属性
FILE_ATTRIBUTE_HIDDEN 隐藏文件或目录
FILE_ATTRIBUTE_READONLY 文件为只读
FILE_ATTRIBUTE_SYSTEM 文件为系统文件
FILE_FLAG_WRITE_THROUGH 操作系统不得推迟对文件的写操作
FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作
FILE_FLAG_NO_BUFFERING 禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块
FILE_FLAG_RANDOM_ACCESS 针对随机访问对文件缓冲进行优化
FILE_FLAG_SEQUENTIAL_SCAN 针对连续访问对文件缓冲进行优化
FILE_FLAG_DELETE_ON_CLOSE 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件
也可在Windows NT下组合使用下述常数标记:
SECURITY_ANONYMOUS,
SECURITY_IDENTIFICATION,
SECURITY_IMPERSONATION,
SECURITY_DELEGATION,
SECURITY_CONTEXT_TRACKING,
SECURITY_EFFECTIVE_ONLY
//第七个参数 HANDLE hTemplateFile
hTemplateFile,hTemplateFile为一个文件或设备句柄,表示按这个参数给出的句柄为模板创建文件(就是将该句柄文件拷贝到lpFileName指定的路径,然后再打开)。
它将指定该文件的属性扩展到新创建的文件上面,这个参数可用于将某个新文件的属性设置成与现有文件一样,并且这样会忽略dwAttrsAndFlags。
通常这个参数设置为NULL,为空表示不使用模板,一般为空。
返回值
如执行成功,则返回文件句柄。
INVALID_HANDLE_VALUE表示出错,会设置GetLastError。
即使函数成功,但若文件存在,且指定了CREATE_ALWAYS 或 OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS
FormatMessage 函数
● FormatMessage是一个Windows API函数。它的功能就是将GetLastError函数得到的错误信息(这个错误信息是数字代号)转化成字符串信息的函数。
DWORD WINAPI FormatMessage (
DWORD dwFlags, // source and processing options
LPCVOID lpSource, // message source
DWORD dwMessageId, // message identifier
DWORD dwLanguageId, // language identifier
LPTSTR lpBuffer, // message buffer
DWORD nSize, // maximum size of message buffer
va_list *Arguments // array of message inserts
);
○ dwFlags
标志位,决定如何说明lpSource参数,dwFlags的低位制定如何处理换行功能在输出缓冲区,也决定最大宽度的格式化输出行。[1]
○ lpSource
根据dwFlags标志而定
○ dwMessageId
请求的消息的标识符。当dwFlags标志为FORMAT_MESSAGE_FROM_STRING时会被忽略。[1]
○ dwLanguageId
请求的消息的语言标识符。
○ LPTSTR lpBuffer
接收错误信息描述的缓冲区指针。
○ nSize
如果FORMAT_MESSAGE_ALLOCATE_BUFFER标志没有被指定,这个参数必须指定为输出缓冲区的大小,如果指定,这个参数指定为分配给输出缓冲区的最小数。[1]
○ Arguments
保存格式化信息中的插入值的一个数组。
LocalFree 函数
○ 功能:释放局部内存对象并使句柄失效
● hMem:局部内存对象的句柄,通过函数LocalAlloc或LocalReAlloc返回的。
○ 返回值
● 函数执行成功返回NULL,否则返回内存对象的句柄,要获得详细错误信息,调用GetLastError函数。
在Windows系统中, 文件大小分为以下两种:
物理大小
GetFileSize 已弃用, 因为对于小文件还可以, 但是大文件会超过输出参数的范围
DWORD WINAPI GetFileSize(
_In_ HANDLE hFile, //文件句柄
_Out_opt_ LPDWORD lpFileSizeHigh //文件大小 输出参数
);
GetFileSizeEx
占用大小
BOOL WINAPI GetFileSizeEx(
_In_ HANDLE hFile, //文件句柄
_Out_ PLARGE_INTEGER lpFileSize //文件大小 输出参数
ReadFile
BOOL ReadFile(
HANDLE hFile, //文件的句柄
LPVOID lpBuffer, //用于保存读入数据的一个缓冲区
DWORD nNumberOfBytesToRead, //要读入的字节数
LPDWORD lpNumberOfBytesRead, //指向实际读取字节数的指针
LPOVERLAPPED lpOverlapped //结构体指针
//如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。
//该结构定义了一次异步读取操作。否则,应将这个参数设为NULL
);
返回值: 成功返回非0
同步下, 如果返回值不等于0.
异步下, 参数5(lpOverlapped)不为NULL时, 当读到文件结尾时, 返回值为FALSE, GetLastError为ERROR_HANDLE_EOF.
WriteFile
BOOL WriteFile(
HANDLE hFile, //文件句柄
LPCVOID lpBuffer, //数据缓存区指针
DWORD nNumberOfBytesToWrite, //你要写的字节数
LPDWORD lpNumberOfBytesWritten, //用于保存实际写入字节数的存储区域的指针
LPOVERLAPPED lpOverlapped//OVERLAPPED //结构体指针
);
返回值:
成功返回非0的值
1 #include <iostream> 2 #include <tchar.h> 3 #include <windows.h> 4 #include <exception> 5 6 //class WindowsException:public std::exception 7 class WindowsException 8 { 9 public: 10 WindowsException(DWORD dwErrorCode):m_dwErrorCode(dwErrorCode) 11 { 12 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 13 nullptr, m_dwErrorCode, 0, reinterpret_cast<LPWSTR>(&m_strErrorMsg), 0, nullptr); 14 } 15 ~WindowsException() 16 { 17 LocalFree(m_strErrorMsg); 18 } 19 const TCHAR* what() const 20 { 21 return m_strErrorMsg; 22 } 23 24 private: 25 DWORD m_dwErrorCode; 26 TCHAR* m_strErrorMsg; 27 }; 28 29 30 class MyFile 31 { 32 public: 33 //默认构造函数 34 MyFile(const TCHAR *strFilePath = TEXT("")):m_hFile(INVALID_HANDLE_VALUE) 35 { 36 SetPath(strFilePath); 37 } 38 39 //默认析构函数 40 ~MyFile() 41 { 42 if (m_hFile != INVALID_HANDLE_VALUE) 43 { 44 CloseHandle(m_hFile); 45 } 46 } 47 48 //打开文件操作 49 BOOL OpenFile(DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, 50 _In_ DWORD dwShareMode = FILE_SHARE_READ, 51 _In_ DWORD dwCreationDisposition = OPEN_ALWAYS, 52 _In_ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, 53 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, 54 _In_opt_ HANDLE hTemplateFile = nullptr 55 ) 56 { 57 BOOL bRet = TRUE; 58 m_hFile = CreateFile(m_strFilePath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 59 if (m_hFile == INVALID_HANDLE_VALUE) //如果 60 { 61 bRet = FALSE; 62 throw WindowsException(GetLastError()); 63 } 64 return bRet; 65 } 66 67 //设置文件路径 68 VOID SetPath(const TCHAR *strFilePath) 69 { 70 SIZE_T nstrLen = _tcslen(strFilePath) + sizeof(TCHAR); 71 m_strFilePath = new TCHAR[nstrLen]; 72 _tcscpy_s(m_strFilePath, nstrLen, strFilePath); 73 } 74 75 //获取文件路径 76 const TCHAR *GetPath() const 77 { 78 return m_strFilePath; 79 } 80 81 const HANDLE GetHandle() const 82 { 83 return m_hFile; 84 } 85 86 private: 87 HANDLE m_hFile; 88 TCHAR *m_strFilePath; 89 90 }; 91 92 93 int main() 94 { 95 try 96 { 97 MyFile clsFile; 98 clsFile.SetPath(TEXT("demo.txt")); 99 clsFile.OpenFile(); 100 101 //取大小 102 // 物理大小 103 LARGE_INTEGER largeFileSize = { 0 }; 104 GetFileSizeEx(clsFile.GetHandle(), &largeFileSize); 105 std::cout << "File Size:" << largeFileSize.QuadPart << std::endl; 106 107 // 磁盘上占用的大小 108 largeFileSize.LowPart = GetCompressedFileSize(clsFile.GetPath(), (LPDWORD)(&(largeFileSize.HighPart))); 109 std::cout << "File Compressed Size:" << largeFileSize.QuadPart << std::endl; 110 111 //同步I/O FILE_FLAG_OVERLAPPED 112 //这个标志位 是否是进行异步IO操作 113 //如果做同步I/0确保不要有这个标志位 114 //读 115 BYTE bBuffer[MAXBYTE] = { 0 }; 116 DWORD dwReadSize = 0; 117 118 //64位的值操作的偏移量 119 LARGE_INTEGER largeBegin = { 0 }; 120 largeFileSize.LowPart = 100; 121 122 //移动文件位置 123 SetFilePointerEx(clsFile.GetHandle(), largeFileSize, nullptr, FILE_BEGIN); 124 125 if (ReadFile(clsFile.GetHandle(), bBuffer, MAXBYTE, &dwReadSize, nullptr)) 126 std::cout << (char*)bBuffer << std::endl << std::endl <<"读取长度:" <<dwReadSize << std::endl; 127 //写 128 DWORD dwWitre = 0; 129 if (WriteFile(clsFile.GetHandle(), bBuffer, MAXBYTE, &dwWitre, nullptr)) 130 std::cout << "写入成功!" << std::endl; 131 132 //文件本身大小是22 设置位1024 133 //设置文件尾 134 largeFileSize.QuadPart = 1024; 135 SetFilePointerEx(clsFile.GetHandle(), largeFileSize, nullptr, FILE_BEGIN); 136 SetEndOfFile(clsFile.GetHandle()); 137 } 138 catch (WindowsException &exception) 139 { 140 MessageBoxW(nullptr, exception.what(), exception.what(), MB_OK); 141 } 142 143 /* 144 HANDLE hFile = CreateFileW(L"Demo.txt", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,nullptr); 145 if (hFile == INVALID_HANDLE_VALUE) 146 { 147 MessageBox(nullptr, L"Error", L"Error", MB_OK); 148 } 149 CloseHandle(hFile); 150 */ 151 system("pause"); 152 return 0; 153 }