封装File类
我们在进行文件操作时,会有两个版本,一个带_s的版本,一个不带_s的版本,带_s的版本多传递了一个size_t的参数,这个参数有两个功能:
- 进行文件操作的时候不会越界;
- 不会被别人使用shellcode进行注入,造成被黑客攻击。
所以在Windows下编程,建议使用_s版本。
先看原始的例子
#include <iostream>
#include <Windows.h>
#include <tchar.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);
}
~WindowException()
{
LocalFree(m_strErrorMsg);
}
const TCHAR *What() const
{
return 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()
{
CloseFile();
}
BOOL OpenFile(DWORD dwDesiredAccess = GENERIC_READ|GENERIC_WRITE,
DWORD dwShareMode = FILE_SHARE_READ,
DWORD dwCreationDisposition = OPEN_ALWAYS,
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL,
LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr,
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 CloseFile()
{
if (m_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
}
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() const
{
return m_strFilePath;
}
const HANDLE GetFileHandle() const
{
return m_hFile;
}
private:
HANDLE m_hFile;
TCHAR *m_strFilePath;
};
int main()
{
try
{
MyFile my_file;
my_file.SetPath(TEXT("Demo.txt"));
my_file.OpenFile();
// 1 取文件大小
// 1.1 物理大小
LARGE_INTEGER file_size = { 0 };
GetFileSizeEx(my_file.GetFileHandle(), &file_size);
std::cout << "file size:" << file_size.QuadPart << std::endl;
// 1.2 磁盘上占用的大小
file_size.LowPart = GetCompressedFileSize(my_file.GetPath(), reinterpret_cast<LPDWORD>(&(file_size.HighPart)));
std::cout << "compress file size:" << file_size.QuadPart << std::endl;
// 2. 同步IO
// 2.1 读
BYTE bBuf[MAXBYTE] = { 0 };
DWORD dwNumberofBytesRead = 0;
// 用64位的值来记录当前文件操作的偏移量
LARGE_INTEGER largeBegin = { 0 };
file_size.LowPart = 100;
SetFilePointerEx(my_file.GetFileHandle(), file_size, nullptr, FILE_BEGIN);
ReadFile(my_file.GetFileHandle(), bBuf, MAXBYTE, &dwNumberofBytesRead, nullptr);
bBuf[MAXBYTE - 1] = '\0';
std::cout << reinterpret_cast<char *>(bBuf) << "写入的大小为:" << dwNumberofBytesRead << std::endl;
// 3. 写
DWORD dwNumberofBytesWritten = 0;
WriteFile(my_file.GetFileHandle(), bBuf, MAXBYTE, &dwNumberofBytesWritten, nullptr);
std::cout << "写入成功!" << std::endl;
// 文件本身大小为22 我想设置为1024
// 设置文件尾
file_size.QuadPart = 1024;
SetFilePointerEx(my_file.GetFileHandle(), file_size, nullptr, FILE_BEGIN);
// 上面的文件操作是在做BT下载的时候用的比较多,把里面的文件分成一块一块的部分,将文件大小设置为目标文件大小
SetEndOfFile(my_file.GetFileHandle());
my_file.CloseFile();
}
catch(WindowException &exception)
{
MessageBox(nullptr, exception.What(), L"提示", MB_OK);
}
return 0;
}
运行结果: