您的位置:首页 > 其它

20170514Windows05_异步IO操作

2017-05-15 22:50 92 查看

异步IO操作

封装File类:

1:CreateFile在FileAPI.h里面,CreateFile有宽窄字节之分。有CreateFileW和CreateFileA。宽字符处理在tchar.h库里面。
2:CreateFile第二个参数指定打开文件的权限,如果使用GENERIC_ALL,打开的时候可能会失败,这样打开需要管理员权限。通常我们指定准确的权限比较好。
3:在文件打开之后,如果打开失败需要关闭句柄,可以将文件系统做成类的方式,析构就会自动释放。
4:tchar.h库里面有_t版本的字符串处理函数,他是自适应的,大多数都带有_s后缀的版本,他会指定长度,确保字符串操作的时候不会越界,其次可以保护我们的程序不会被别人使用shellcode注入,可能会被黑客利用这个漏洞。建议一直使用_s版本。
5:
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include <exception>
//#include <FileAPI.h>

class WindowException
{
public:
WindowException(DWORD dwErrorCode) :m_dwErrorCode_(dwErrorCode)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
nullptr, m_dwErrorCode_, 0, reinterpret_cast<LPWSTR>(&m_strErrorMsg_), 0, nullptr);
}
const TCHAR* what() const
{
return m_strErrorMsg_;
}
~WindowException()
{
//		LocalFree(m_strErrorMsg_);
}
private:
DWORD m_dwErrorCode_;
TCHAR* m_strErrorMsg_;
};

class MyFile
{
public:
MyFile(const TCHAR *strFilePath = TEXT("")) :m_hFile_(INVALID_HANDLE_VALUE)
{
SetPath(strFilePath);
}
~MyFile()
{
if (m_hFile_ != INVALID_HANDLE_VALUE)
CloseHandle(m_hFile_);
delete m_strFilePath_;
}
BOOL OpenFile(
_In_     DWORD                 dwDesiredAccess = GENERIC_READ|GENERIC_WRITE,
_In_     DWORD                 dwShareMode = FILE_SHARE_READ,
_In_     DWORD                 dwCreationDisposition = OPEN_EXISTING,
_In_     DWORD                 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr,
_In_opt_ HANDLE                hTemplateFile = nullptr
)
{
BOOL bRet = TRUE;
m_hFile_ = CreateFile(m_strFilePath_, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
if (m_hFile_ == INVALID_HANDLE_VALUE)
{
bRet = FALSE;
throw WindowException(GetLastError());
}
return bRet;
}
VOID SetPath(const TCHAR *strFilePath)
{
SIZE_T nstrlen = _tcslen(strFilePath) + sizeof(TCHAR);
m_strFilePath_ = new TCHAR[nstrlen];
_tcscpy_s(m_strFilePath_, nstrlen, strFilePath);
}
const TCHAR* GetPath()
{
return m_strFilePath_;
}

protected:
HANDLE m_hFile_;
TCHAR *m_strFilePath_;
};

int main()
{
try
{
MyFile clsFile;
clsFile.SetPath(L"Demo.txt");
clsFile.OpenFile();
}
catch (WindowException &e)
{
MessageBox(nullptr, e.what(), L"Error", MB_OK);
}

return 0;
}


6:特别值得注意的是:异常类里面的指针,在throw的时候会被析构掉(VS2013编译器会,VS2015不会),catch的时候,catch的对象的这个指针指向的位置数据是错的。可以通过写上自己的拷贝构造函数来解决。

获取文件大小:

1:获取文件之后需要对文件进行操作,取文件的大小会涉及到两种大小。
    1:文件实际物理大小:
    2:磁盘占用大小:
2:获取文件大小:GetFileSize和GetFileSizeEx。
    1:GetFileSize:编的不可用了,因为他后面的长度过短,后面放的长度是32位的字节,小文件里面可用,大文件需要用64位。
    2:GetFileSizeEx:能接受的大小事64位的数。
3:程序:
LARGE_INTEGER largeFileSize = { 0 };
GetFileSizeEx(clsFile.GetHandle(), &largeFileSize);
std::cout << "FileSize:" << largeFileSize.QuadPart << std::endl;

largeFileSize.LowPart = GetCompressedFileSize(clsFile.GetPath(), (LPDWORD)(&largeFileSize.HighPart));
std::cout << "FileCompressSize:" << largeFileSize.QuadPart << std::endl;


异步IO操作:

1:上面讲的都是同步IO,会产生阻塞,在读取文件的时候会导致卡死或者其他的。
2:异步操作:必须确保CreateFile的时候设置了FILE_FLAG_OVERLAPPED标识符。设置了这个标识符,后面的同步IO操作就可能出错(读和写)。
3:文件操作:
    1:ReadFile:读取文件。和下面的WriteFile都是同步操文件作。
    2:WriteFile:写文件,特别注意,如果读取文件之后写文件,并不是从文件的末尾写,而是从读取到的位置的下一个位置开始写入。要在其他位置写入需要自己设定游标。

文件位置修改:

1:I/O操作的时候,CreateFile会在内核里面建立一个文件内核对象,ReadFile和WriteFile等都是通过文件内核对象对文件进行一系列的操作,操作的时候,比如ReadFile,文件里面肯定有一个标识位,记录我们读取到的位置(是一个偏移量),下次读取就是读取的这个位置之后的位置的数据。这个偏移量是基于某一个点的偏移量,如果我们要对这个偏移量进行操作,可以使用SetFilePointEx来进行操作。
BOOL WINAPI SetFilePointerEx(
_In_      HANDLE         hFile,
_In_      LARGE_INTEGER  liDistanceToMove,
_Out_opt_ PLARGE_INTEGER lpNewFilePointer,
_In_      DWORD          dwMoveMethod
);


2:SetFilePointEx:
    1:返回值:BOOL,

    2:_In_ HANDLE hFile:要操作的文件的句柄

    3:_In_ LARGE_INTEGER liDistanceToMove:要移动的byte个数,需要用LARGE_INTEGER来存储。

    4:_Out_opt_ PLARGE_INTEGER lpNewFilePointer:用于接收移动后游标(记录)的位置。
    5:_In_ DWORD dwMoveMethod:移动的相对位置,可设置为FILE_BEGIN,FILE_CURRENT,FILE_END三种。

3:在读取的时候,会涉及到上面的移动操作,但是在写的时候,可能会用到(并不是常用的)移动文件位置。需要设置文件尾,使用SetEndOfFile。
4:SetEndOfFile:只需传递一个参数,文件句柄,设置之后,文件尾就不再是原来的文件尾了,他会把当前设置的文件尾以后的数据去掉,会改变源文件的大小。
    如果文件本身的大小只为24byte,我们使用SetFilePointEx该函数设置为1024方便我们读取和传输,我们可以和SetEndOfFile一起使用。在BT下载中,就是将文件设置为一块一块的,这样传输小文件,然后再组合起来会更快。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: