/*****************************************************************************/
<2011_0725_0141><home><LostSpeed><LsLog\program\testcase\FileOPT V1.0.0.1>
无缓冲区写文件, 写文件完成后, 设置正确的FileTotalSize
用无缓冲区写文件的目的: 某些程序会拦截, 替换fopen操作的文件内容,
应用层无法得到真实的文件数据, 这时需要用无缓冲区读写的方式来裸读.
知识点:
* CreateFile时带上标记FILE_FLAG_NO_BUFFERING
* WriteFile时,需要写入扇区对齐或扇区倍数的块, 如果不够块大小, 在写入区先放着
在往写入区中写的时候, 不管是否写入了磁盘, 都需要自己维护写入的FileTotalSize
用来在文件完全写入后,设置正确的FileSize.
* 用GetDiskFreeSpace来得到目标文件所在驱动器的扇区大小.
* 为了提高写入速度, 应给出一个较大的缓冲区容量并按照扇区大小进行规约
* 写入完成后, 关闭文件. 再打开文件, SetFilePointer, SetEndOfFile 设置文件的正确大小
/*****************************************************************************/
// FileOPT.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <direct.h>
#include "helper/helper_file.h"
USE_NAMESPACE_LS
LS_RC BuildTestSrc(TCHAR * pcPathNameSrc, HANDLE & hFileSrc, BYTE* pucBufRd, size_t nSizeBufRd);
int _tmain(int argc, _TCHAR* argv[])
{
LS_RC lsRc = LS_RC_OK;
BYTE ucBufRd[_MAX_PATH];//从其他地方读来的数据, 每次得到之后, 循环写入文件
PBYTE pucWriteNoCache = NULL;//以扇区倍数为单位写入块
DWORD dwRdBack = 0;//从其他地方读来的数据在ucBufRd中的字节数量
TAG_WIRTE_BUF_NO_CACHE_INFO sWriteBufNoCache;//无缓冲写入的结构, 用于带多个参数, 简化函数入参数量
DWORD dwWrBack = 0;//从其他地方读来的数据在ucBufRd中的字节数量
DWORD dwWirteBufLen = 0;//无缓冲方式要按照扇区写入, 一次性写入此扇区到文件
HANDLE hFileSrc = INVALID_HANDLE_VALUE;//从hFileSrc读内容
HANDLE hFileDst = INVALID_HANDLE_VALUE;//将读到的内容写到这里hFileDst
TCHAR * pcPathNameDst = _T("c:\\tmp\\dir1\\dir2\\fileOptTest.txt");//要写入内容的文件
/** 假设写入的数据来源于磁盘上已经存在的文件 c:\\testForRd.txt, 这个文件的大小为 2345 */
TCHAR * pcPathNameSrc = _T("c:\\testForRd.txt");
lsRc = LsCreateFileEngrossNoCache(pcPathNameDst, hFileDst);
if(LS_RC_OK != lsRc)
{
goto __tmain_END;
}
//得到无缓冲方式写时,以扇区倍数为大小的块长度
lsRc = LsGetWriteBufferLenForWirteFileNoCache(pcPathNameDst, sizeof(ucBufRd), dwWirteBufLen);
if(LS_RC_OK != lsRc)
{
goto __tmain_END;
}
/**
* 只开1个,2个扇区, 明显慢了, 120M的文件写完,超过了1分钟
* 按扇区倍数规约到1M, 试验表明, 10秒钟左右, 120M就写完了~
* 117 MB (123,456,789 字节)
*/
lsRc = LsGetSectorMultiple(1024 * 1024, dwWirteBufLen, dwWirteBufLen);
if(LS_RC_OK != lsRc)
{
goto __tmain_END;
}
pucWriteNoCache = new BYTE[dwWirteBufLen];//按扇区倍数为单位的写入块
if(!pucWriteNoCache)
{
lsRc = MakeLsErrSn(LS_RC_MEMORY_ALLOC);
goto __tmain_END;
}
//建立一个数据来源, 用于读取此数据来源写到pcPathNameDst
lsRc = BuildTestSrc(pcPathNameSrc, hFileSrc, &ucBufRd[0], sizeof(ucBufRd));
lsRc = LsOpenFileForRead(pcPathNameSrc, hFileSrc);
if(LS_RC_OK != lsRc)
{
goto __tmain_END;
}
//read src write to dst, write by no cache!
ZeroMemory(&sWriteBufNoCache, sizeof(TAG_WIRTE_BUF_NO_CACHE_INFO));
sWriteBufNoCache.dwLenBufNoCache = dwWirteBufLen;
sWriteBufNoCache.dwPosToWrite = 0;//由LsWriteFileNoCache决定
sWriteBufNoCache.hFileToWrite = hFileDst;
sWriteBufNoCache.llTotalWriteIn = 0;
sWriteBufNoCache.pBufNoCache = pucWriteNoCache;
sWriteBufNoCache.pBufToWrite = ucBufRd;
while(ReadFile(hFileSrc, ucBufRd, sizeof(ucBufRd), &dwRdBack, NULL))
{
if(dwRdBack <= 0)
{
break;//已经读完了
}
sWriteBufNoCache.dwLenToWrite = dwRdBack;//由ReadFile来决定
sWriteBufNoCache.dwLenWrBack = 0;//由LsWriteFileNoCache决定
lsRc = LsWriteFileNoCache(sWriteBufNoCache);
if((LS_RC_OK != lsRc) || (dwRdBack != sWriteBufNoCache.dwLenWrBack))
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto __tmain_END;
}
}
lsRc = LsWriteFileNoCache_FulshData(sWriteBufNoCache);
if(LS_RC_OK != lsRc)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto __tmain_END;
}
LsCloseHandle(hFileDst);
/** 在关闭文件后, 重新打开文件, 设置文件实际size */
lsRc = LsOpenFileForWrite(pcPathNameDst, hFileDst);
if(LS_RC_OK != lsRc)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto __tmain_END;
}
lsRc = LsSetFilePointer(sWriteBufNoCache);
if(LS_RC_OK != lsRc)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto __tmain_END;
}
__tmain_END:
LsCloseHandle(hFileSrc);
LsCloseHandle(hFileDst);
LsDelete(pucWriteNoCache);
if(LS_RC_OK == lsRc)
{
}
else
{
_tprintf(_T("sir: some error was happen, please check the progam\n"));
getchar();
}
return 0;
}
LS_RC BuildTestSrc(TCHAR * pcPathNameSrc, HANDLE & hFileSrc, BYTE* pucBufRd, size_t nSizeBufRd)
{
LS_RC lsRc = LS_RC_OK;
DWORD dwSizeRdBack = 27;//每次写入pcPathNameSrc的测试内容长度, 随便一个非特殊,非对齐的长度
DWORD dwSizeWrBack = 0;//每次写入pcPathNameSrc dwSizeRdBack长度后, 返回的写入长度
size_t nTotalWrite = 0;//总共写入的字节数
size_t n = 0;
BOOL bStopWriteSrc = FALSE;
LONGLONG llSizeWirteToSrc = 123456789;//写入pcPathNameSrc的测试内容总长度, 123456789是100多M的大小
lsRc = LsCreateFile(pcPathNameSrc, hFileSrc);
if(LS_RC_OK != lsRc)
{
goto _BuildTestSrc_END;
}
for(n = 0; n < nSizeBufRd; n++)
{
*(pucBufRd + n) = (BYTE)(n % 0xff);
}
bStopWriteSrc = FALSE;//为最后一次写测试文件src准备的
while(llSizeWirteToSrc > 0)
{
if(llSizeWirteToSrc >= dwSizeRdBack)
{
llSizeWirteToSrc -= dwSizeRdBack;
}
else
{
dwSizeRdBack = (DWORD)llSizeWirteToSrc;
bStopWriteSrc = TRUE;
}
if(!WriteFile(hFileSrc, pucBufRd, dwSizeRdBack, &dwSizeWrBack, NULL))
{
//带缓冲方式写得时候, 不需要扇区对齐写, 写多少都是成功的, 且(dwSizeWrBack == dwSizeRdBack)
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto _BuildTestSrc_END;
}
nTotalWrite += dwSizeWrBack;
if(dwSizeRdBack != dwSizeWrBack)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto _BuildTestSrc_END;
}
if(bStopWriteSrc)
{
break;
}
}
_BuildTestSrc_END:
LsCloseHandle(hFileSrc);
return lsRc;
}
/**
* @file helper_file.h
*/
#ifndef _HELPER_FILE_H_
#define _HELPER_FILE_H_
#include "helper_common.h"
#include "define/define_error.h"
#include "define/define_struct_file.h"
LS_NAMESPACE_BEGIN
LS_RC LsFindFile(CONST TCHAR * pcFileName);
LS_RC LsCreateFile(TCHAR * pcFileName, HANDLE &hFile); /**< 建立文件, 传出文件句柄 */
LS_RC LsOpenFileForAppend(TCHAR * pcFileName, HANDLE &hFile); /**< 打开现存文件去写, 传出文件句柄 */
LS_RC LsOpenFileForRead(TCHAR * pcFileName, HANDLE &hFile); /**< 打开现存文件去读, 传出文件句柄 */
LS_RC LsOpenFileForWrite(TCHAR * pcFileName, HANDLE &hFile); /**< 打开现存文件去写, 传出文件句柄 */
LS_RC LsCloseHandle(HANDLE &hFile); /**< 关闭文件件 */
LS_RC LsDelete(PBYTE & pBuf); /**< if (pBuf == TRUE), delete it */
LS_RC LsWriteFile(HANDLE &hFile, LPCVOID pcBuf, DWORD dwSizeBuf); /**< 写入文件内容 */
/*
WriteFile(hTempFile, buffer, dwBytesRead,
&dwBytesWritten, NULL);
*/
/** 独占方式文件操作 */
LS_RC LsGetFullPathFromPathName(TCHAR * pcPathName, tstring & strPath);/**< 从全路径文件名中, 得到全路径 */
LS_RC LsCreateFullPath(TCHAR * pcFullPath);/**< 建立给定的全路径目录 */
LS_RC LsCreateFullPath(TCHAR * pcDriverName, std::vector<tstring> & vecPath);/**< 按照驱动器名称和目录的vector, 建立全路径目录 */
LS_RC LsSplitPathToVector(TCHAR * pcFullPath, std::vector<tstring> & vecPath);
LS_RC LsCreateFileEngrossNoCache(TCHAR * pcPathName, HANDLE & hFile); /**< 以独占无缓存方式建立文件 */
/**
* @fn LS_RC LsGetPathDiskInfo(TCHAR * pcPathName)
* @brief 得到路径中的磁盘信息, 如果pcPathName是全路径文件名, 分解出路径作为查询条件
*/
LS_RC LsGetPathDiskInfo(TCHAR * pcPathName, TAG_PATH_INFO & pathInfo);
/** 切分路径信息到pathInfo */
LS_RC LsSplitPath(TCHAR * pcPathName, TAG_PATH_INFO & pathInfo);
/** 从PcPathName中得到盘符, 查询磁盘空间, 填充DiskFreeSapce */
LS_RC LsGetFreeDiskSapce(TCHAR * pcPathName, TAG_DISK_FREE_SPACE & DiskFreeSapce);
/** 根据一次写入的最大字节数, 计算写缓冲区的大小
* 独占无缓存方式写文件, 一次要写入磁盘扇区的倍数大小才能成功
*/
LS_RC LsGetWriteBufferLenForWirteFileNoCache(TCHAR * pcPathName, DWORD dwBytesOnceWriteMax, DWORD & dwWirteBufLen);
/** 以扇区倍数为界限, 向给定容量规约
* 即取最靠近给定容量的扇区倍数的字节数
*/
LS_RC LsGetSectorMultiple(DWORD dwBytesUpperLimit, DWORD dwByteSectorBase, DWORD &dwSectorMultiple);
/** 无缓冲方式的块写入
* 返回下一次写入的位置dwPosToWrite, 总共写入的字节数(用来写入完成后, 设置文件size)
*/
LS_RC LsWriteFileNoCache(TAG_WIRTE_BUF_NO_CACHE_INFO & sWriteBufNoCache);
/** 最后一次的写, 然后调用关闭文件句柄 */
LS_RC LsWriteFileNoCache_FulshData(TAG_WIRTE_BUF_NO_CACHE_INFO & sWriteBufNoCache);
/** 设置文件指针 */
LS_RC LsSetFilePointer(TAG_WIRTE_BUF_NO_CACHE_INFO & sWriteBufNoCache);
/** 得Windows路径 */
LS_RC LsGetWinOsPath(tstring & strPathName);
LS_NAMESPACE_END
#endif
/**
* @file helper_flie.cpp
*/
#include <windows.h>
#include "helper_string.h"
#include "define/define_error.h"
#include "helper/helper_file.h"
LS_NAMESPACE_BEGIN
LS_RC LsFindFile(CONST TCHAR * pcFileName)
{
tstring::size_type nPos = 0;
tstring::size_type nPosUnknown = -1;
LS_RC lsRc = LS_RC_OK;
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
tstring strFileName;
strFileName = pcFileName;
nPos = strFileName.rfind(_T('\\'));
if((nPosUnknown != nPos) && (_T('\\') == strFileName.at(strFileName.length() - 1)))
{
/** 要查找的文件不能带 "\\" */
strFileName.replace(nPos, 1, _T("\0"));
}
hFind = FindFirstFile(strFileName.c_str(), &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_NOT_FIND);
goto _LsFindFile_END;
}
else
{
//_tprintf(_T("The first file found is %s\n"), FindFileData.cFileName);
FindClose(hFind);
}
_LsFindFile_END:
return lsRc;
}
LS_RC LsCreateFile(TCHAR * pcFileName, HANDLE &hFile)
{/** 建立文件传出文件指针 */
LS_RC lsRc = LS_RC_OK;
hFile = CreateFile(pcFileName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_CREATE);
goto _LsCreateFile_END;
}
_LsCreateFile_END:
return lsRc;
}
LS_RC LsOpenFileForAppend(TCHAR * pcFileName, HANDLE &hFile)
{/** 建立文件传出文件指针 */
LS_RC lsRc = LS_RC_OK;
LARGE_INTEGER FileSize;
hFile = CreateFile(pcFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_OPEN);
goto _LsOpenFileForAppend_END;
}
/** 如果是已经存在的日志文件, 移动到文件末尾, 形成附加日志的效果 */
if(GetFileSizeEx(hFile, &FileSize) && (FileSize.QuadPart > 0))
{
//_llseek((HFILE)hFile, 0, SEEK_END);//这种用法有个警告 :(
SetFilePointer(hFile, 0, NULL, FILE_END);
}
_LsOpenFileForAppend_END:
return lsRc;
}
LS_RC LsOpenFileForRead(TCHAR * pcFileName, HANDLE &hFile)
{/** 建立文件传出文件指针 */
LS_RC lsRc = LS_RC_OK;
hFile = CreateFile(pcFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_OPEN);
goto _LsOpenFileForAppend_END;
}
_LsOpenFileForAppend_END:
return lsRc;
}
LS_RC LsOpenFileForWrite(TCHAR * pcFileName, HANDLE &hFile)
{/**< 打开现存文件去写, 传出文件句柄 */
LS_RC lsRc = LS_RC_OK;
hFile = CreateFile(pcFileName,
GENERIC_READ | GENERIC_WRITE,
NULL,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_OPEN);
goto END;
}
END:
return lsRc;
}
LS_RC LsWriteFile(HANDLE &hFile, LPCVOID pcBuf, DWORD dwSizeBuf)
{
LS_RC lsRc = LS_RC_OK;
BOOL bWriteOK = TRUE;
DWORD dwBytesWritten = 0; /**< 总共写入的字节数 */
DWORD dwBytesWrittenOnce = 0; /**< 一次写操作完成后, 已经写入的字节数 */
if(INVALID_HANDLE_VALUE == hFile)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_INVALID_HANDLE);
goto _LsWriteFile_END;
}
do
{
bWriteOK = ::WriteFile(hFile, (PBYTE)pcBuf + dwBytesWritten, dwSizeBuf - dwBytesWritten, &dwBytesWrittenOnce, NULL);
if(!bWriteOK)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto _LsWriteFile_END;
}
dwBytesWritten += dwBytesWrittenOnce;
}while((dwSizeBuf - dwBytesWritten) > 0);
_LsWriteFile_END:
return lsRc;
}
LS_RC LsCloseHandle(HANDLE &hFile)
{
LS_RC lsRc = LS_RC_OK;
BOOL bCloseOK = TRUE;
if(INVALID_HANDLE_VALUE != hFile)
{
bCloseOK = CloseHandle(hFile);
if(bCloseOK)
{
hFile = INVALID_HANDLE_VALUE;
}
else
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_CLOSE);
goto _LsCloseFile_END;
}
}
_LsCloseFile_END:
return lsRc;
}
LS_RC LsDelete(PBYTE & pBuf)
{
if(pBuf)
{
delete pBuf;
pBuf = NULL;
}
return LS_RC_OK;
}
LS_RC LsCreateFileEngrossNoCache(TCHAR * pcPathName, HANDLE & hFile)
{
LS_RC lsRc = LS_RC_OK;
hFile = INVALID_HANDLE_VALUE;
lsRc = LsCreateFullPath(pcPathName);
if(LS_RC_OK != lsRc)
{
goto _LsCreateFileEngross_END;
}
hFile = CreateFile(
pcPathName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_FLAG_NO_BUFFERING,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_CREATE);
}
_LsCreateFileEngross_END:
return lsRc;
}
LS_RC LsGetPathDiskInfo(TCHAR * pcPathName, TAG_PATH_INFO & pathInfo)
{
LS_RC lsRc = LS_RC_OK;
lsRc = LsSplitPath(pcPathName, pathInfo);
if(LS_RC_OK != lsRc)
{
goto _LsGetPathDiskInfo_END;
}
_LsGetPathDiskInfo_END:
return lsRc;
}
LS_RC LsSplitPath(TCHAR * pcPathName, TAG_PATH_INFO & pathInfo)
{
LS_RC lsRc = LS_RC_OK;
if(!pathInfo.IsValid())
{
lsRc = MakeLsErrSn(LS_RC_PARAM_STRUCT_INVALID);
goto _LsSplitPath_END;
}
_tcscpy_s(pathInfo.PathInfo.path_buffer, SIZE_OF(pathInfo.PathInfo.path_buffer), pcPathName);
_tsplitpath_s(pathInfo.PathInfo.path_buffer,
pathInfo.PathInfo.drive, SIZE_OF(pathInfo.PathInfo.drive),
pathInfo.PathInfo.dir, SIZE_OF(pathInfo.PathInfo.dir),
pathInfo.PathInfo.fname, SIZE_OF(pathInfo.PathInfo.fname),
pathInfo.PathInfo.ext, SIZE_OF(pathInfo.PathInfo.ext));
_LsSplitPath_END:
return lsRc;
}
LS_RC LsGetFreeDiskSapce(TCHAR * pcPathName, TAG_DISK_FREE_SPACE & DiskFreeSapce)
{
BOOL bRc = TRUE;
LS_RC lsRc = LS_RC_OK;
TAG_PATH_INFO pathInfo;
ZeroMemory(&pathInfo, sizeof(TAG_PATH_INFO));
ZeroMemory(&DiskFreeSapce, sizeof(TAG_DISK_FREE_SPACE));
lsRc = LsSplitPath(pcPathName, pathInfo);
if(LS_RC_OK != lsRc)
{
goto _LsGetFreeDiskSapce_END;
}
_tcscpy_s(DiskFreeSapce.DiskFreeSpace.cRootPathName, SIZE_OF(DiskFreeSapce.DiskFreeSpace.cRootPathName), pathInfo.PathInfo.drive);
_tcscat_s(DiskFreeSapce.DiskFreeSpace.cRootPathName, SIZE_OF(DiskFreeSapce.DiskFreeSpace.cRootPathName), pathInfo.PathInfo.dir);
/** 给定的全路径必须存在 */
lsRc = LsFindFile(DiskFreeSapce.DiskFreeSpace.cRootPathName);
if(LS_RC_OK != lsRc)
{
goto _LsGetFreeDiskSapce_END;
}
bRc = GetDiskFreeSpace(DiskFreeSapce.DiskFreeSpace.cRootPathName,
&DiskFreeSapce.DiskFreeSpace.dwSectorsPerCluster,
&DiskFreeSapce.DiskFreeSpace.dwBytesPerSector,
&DiskFreeSapce.DiskFreeSpace.dwNumberOfFreeClusters,
&DiskFreeSapce.DiskFreeSpace.dwTotalNumberOfClusters);
if(!bRc)
{
lsRc = MakeLsErrSn(LS_RC_GET_SYSTEM_INFO);
goto _LsGetFreeDiskSapce_END;
}
bRc = GetDiskFreeSpaceEx(DiskFreeSapce.DiskFreeSpace.cRootPathName,
&DiskFreeSapce.DiskFreeSpace.ullFreeBytesAvailable,
&DiskFreeSapce.DiskFreeSpace.ullTotalNumberOfBytes,
&DiskFreeSapce.DiskFreeSpace.ullTotalNumberOfFreeBytes);
if(!bRc)
{
lsRc = MakeLsErrSn(LS_RC_GET_SYSTEM_INFO);
goto _LsGetFreeDiskSapce_END;
}
_LsGetFreeDiskSapce_END:
return lsRc;
}
LS_RC LsGetWriteBufferLenForWirteFileNoCache(TCHAR * pcPathName, DWORD dwBytesOnceWriteMax, DWORD & dwWirteBufLen)
{
LS_RC lsRc = LS_RC_OK;
CONST DWORD dwInValid = -1;
TAG_DISK_FREE_SPACE DiskFreeSpace;
DWORD dwBytesPerSector = 0;/**< pcPathName所在磁盘每扇区size */
DWORD dwSectorCnt = 0;/**< 写nBytesOnceWriteMax所需的扇区数量 */
size_t nBytesModSector = 0;/**< 写nBytesOnceWriteMax所需的扇区数量之外的零头 */
if(dwInValid == dwBytesOnceWriteMax)
{
lsRc = MakeLsErrSn(LS_RC_PARAM_INVALID);
goto _LsGetWriteBufferLenForWirteFileNoCache_END;
}
ZeroMemory(&DiskFreeSpace, sizeof(TAG_DISK_FREE_SPACE));
lsRc = LsGetFreeDiskSapce(pcPathName, DiskFreeSpace);
if(LS_RC_OK != lsRc)
{
goto _LsGetWriteBufferLenForWirteFileNoCache_END;
}
dwBytesPerSector = DiskFreeSpace.DiskFreeSpace.dwBytesPerSector;
nBytesModSector = dwBytesOnceWriteMax % dwBytesPerSector;
dwSectorCnt = (dwBytesOnceWriteMax - nBytesModSector) / dwBytesPerSector;
if(nBytesModSector > 0)
{
dwSectorCnt++;
}
dwWirteBufLen = dwBytesPerSector * dwSectorCnt;
_LsGetWriteBufferLenForWirteFileNoCache_END:
return lsRc;
}
LS_RC LsGetSectorMultiple(DWORD dwBytesUpperLimit, DWORD dwByteSectorBase, DWORD &dwSectorMultiple)
{
LS_RC lsRc = LS_RC_OK;
DWORD dwMod = dwByteSectorBase % dwBytesUpperLimit;
DWORD dwMultiple = (dwBytesUpperLimit - dwMod) / dwByteSectorBase;
dwSectorMultiple = dwMultiple * dwByteSectorBase;
END:
return lsRc;
}
LS_RC LsGetWinOsPath(tstring & strPathName)
{
LS_RC lsRc = LS_RC_OK;
TCHAR cInfoBuf[LS_INFO_BUFFER_SIZE];
ZeroMemory(cInfoBuf, sizeof(cInfoBuf));
if(!GetWindowsDirectory(cInfoBuf, LS_INFO_BUFFER_SIZE))
{
lsRc = MakeLsErrSn(LS_RC_GET_SYSTEM_INFO);
goto _LsGetWinOsPath_END;
}
strPathName = cInfoBuf;
_LsGetWinOsPath_END:
return lsRc;
}
LS_RC LsGetFullPathFromPathName(TCHAR * pcPathName, tstring & strPath)
{
/**< 从全路径文件名中, 得到全路径 */
LS_RC lsRc = LS_RC_OK;
return lsRc;
}
LS_RC LsCreateFullPath(TCHAR * pcFullPath)
{
/**< 建立给定的全路径目录 */
LS_RC lsRc = LS_RC_OK;
TAG_PATH_INFO pathInfo;
tstring strFullPath;
std::vector<tstring> vecPath;
ZeroMemory(&pathInfo, sizeof(TAG_PATH_INFO));
lsRc = LsSplitPath(pcFullPath, pathInfo);
if(LS_RC_OK != lsRc)
{
goto END;
}
/** 给出的磁盘名称必须是物理存在的, 这个不能手工建立 */
lsRc = LsFindFile(pathInfo.PathInfo.drive);
if(LS_RC_OK != lsRc)
{
goto END;
}
/** 如果全路径已经存在, 不再去分析, 建立全路径 */
strFullPath = pathInfo.PathInfo.drive;
strFullPath += _T('\\');
strFullPath += pathInfo.PathInfo.dir;
lsRc = LsFindFile(strFullPath.c_str());
if(LS_RC_OK == lsRc)
{
goto END;
}
/** 切分全路径到vector */
lsRc = LsSplitPathToVector(pathInfo.PathInfo.dir, vecPath);
if(LS_RC_OK != lsRc)
{
goto END;
}
/** 建立多级目录 */
lsRc = LsCreateFullPath(pathInfo.PathInfo.drive, vecPath);
if(LS_RC_OK != lsRc)
{
goto END;
}
END:
return lsRc;
}
LS_RC LsCreateFullPath(TCHAR * pcDriverName, std::vector<tstring> & vecPath)
{
INT iRc = 0;
INT iLastErr = 0;
LS_RC lsRc = LS_RC_OK;
tstring strDir = pcDriverName;
std::vector<tstring>::iterator it = vecPath.begin();
for(it = vecPath.begin(); it != vecPath.end(); it++)
{
if(_T('\\') != strDir.at(strDir.length() - 1))
{
strDir += '\\';
}
strDir += *it;
iRc = _tmkdir(strDir.c_str());
//_tmkdir返回的东西不对啊, 和MSDN上说得不一样, 先忽略
// iLastErr = GetLastError();
// if((0 != iRc) && (EEXIST != GetLastError()))
// {
// lsRc = MakeLsErrSn(LS_RC_ERR_FILE_CREATE);
// goto _LsCreateFullPath_pcDriverName_vecPath_END;
// }
/** 换种方法判断是否建立文件夹成功, 原来就存在, 也算成功 */
lsRc = LsFindFile(strDir.c_str());
if(LS_RC_OK != lsRc)
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_CREATE);
goto END;
}
}
END:
return lsRc;
}
LS_RC LsSplitPathToVector(TCHAR * pcFullPath, std::vector<tstring> & vecPath)
{
LS_RC lsRc = LS_RC_OK;
tstring strFullPath = pcFullPath;
tstring strSubDirName = _T("");
size_t nPosFind = 0;
size_t nPosBegin = -1;
size_t nPosEnd = -1;
size_t nSize = _tcslen(strFullPath.c_str());
do
{
nPosFind = strFullPath.find(_T('\\'), nPosFind);
if(nPosFind != -1)
{
nPosBegin = nPosEnd;
nPosEnd = nPosFind;
if((nPosBegin != nPosEnd) && (-1 != nPosBegin) && (-1 != nPosEnd) && (nPosEnd > nPosBegin))
{
strSubDirName = strFullPath.substr(nPosBegin + 1, nPosEnd - nPosBegin - 1);
vecPath.push_back(strSubDirName.c_str());
}
}
nPosFind++;
}
while((nPosFind != -1) && (nPosFind < nSize));
return lsRc;
}
LS_RC LsWriteFileNoCache(TAG_WIRTE_BUF_NO_CACHE_INFO & sWriteBufNoCache)
{
LS_RC lsRc = LS_RC_OK;
DWORD dwLenWriteOnce = 0;
DWORD dwLenWriteBack = 0;
DWORD dwPosToWriteSrc = 0;//源缓冲区要写入到块的位置
//如果要写入的长度 + 块写入当前位置 >= 无缓冲写入块长度, 向文件中循环写入块
while((sWriteBufNoCache.dwLenToWrite + sWriteBufNoCache.dwPosToWrite) >= sWriteBufNoCache.dwLenBufNoCache)
{
dwLenWriteOnce = sWriteBufNoCache.dwLenBufNoCache - sWriteBufNoCache.dwPosToWrite;
memcpy(sWriteBufNoCache.pBufNoCache + sWriteBufNoCache.dwPosToWrite, sWriteBufNoCache.pBufToWrite, dwLenWriteOnce);
dwPosToWriteSrc += dwLenWriteOnce;
sWriteBufNoCache.dwLenToWrite -= dwLenWriteOnce;
sWriteBufNoCache.dwPosToWrite = 0;
if(!WriteFile(sWriteBufNoCache.hFileToWrite, sWriteBufNoCache.pBufNoCache, sWriteBufNoCache.dwLenBufNoCache, &dwLenWriteBack, NULL))
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto END;
}
/** 将数据写进文件, 要不一个空文件摆在那半天没动静, 像挂掉了一样 */
if(!FlushFileBuffers(sWriteBufNoCache.hFileToWrite))
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto END;
}
sWriteBufNoCache.dwLenWrBack += dwLenWriteOnce;
sWriteBufNoCache.llTotalWriteIn += dwLenWriteOnce;
}
//移动不足一块的数据到写入块, 更新给调用者的回答
memcpy(sWriteBufNoCache.pBufNoCache + sWriteBufNoCache.dwPosToWrite, sWriteBufNoCache.pBufToWrite + dwPosToWriteSrc, sWriteBufNoCache.dwLenToWrite);
sWriteBufNoCache.dwPosToWrite += sWriteBufNoCache.dwLenToWrite; //更新无缓冲块当前写入位置, 用于下次写入
sWriteBufNoCache.dwLenWrBack += sWriteBufNoCache.dwLenToWrite; //更新调用者本次调用写入数量
sWriteBufNoCache.llTotalWriteIn += sWriteBufNoCache.dwLenToWrite; //更新总写入数量, 用于确定文件总Size
END:
return lsRc;
}
/** 最后一次的写, 然后调用关闭文件句柄 */
LS_RC LsWriteFileNoCache_FulshData(TAG_WIRTE_BUF_NO_CACHE_INFO & sWriteBufNoCache)
{
LS_RC lsRc = LS_RC_OK;
DWORD dwLenWriteOnce = 0;
DWORD dwLenWriteBack = 0;
dwLenWriteOnce = sWriteBufNoCache.dwLenBufNoCache - sWriteBufNoCache.dwPosToWrite;
if(dwLenWriteOnce > 0)
{
sWriteBufNoCache.dwPosToWrite = 0;
if(!WriteFile(sWriteBufNoCache.hFileToWrite, sWriteBufNoCache.pBufNoCache, sWriteBufNoCache.dwLenBufNoCache, &dwLenWriteBack, NULL))
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto END;
}
sWriteBufNoCache.dwLenWrBack += dwLenWriteOnce;
/**
* 在LsWriteFileNoCache中, 已经对每次写入的字节数做了回应, 已经是正确的总长度,
* 最后一次写入不再更新 sWriteBufNoCache.llTotalWriteIn
*/
//sWriteBufNoCache.llTotalWriteIn += dwLenWriteOnce;
}
END:
return lsRc;
}
LS_RC LsSetFilePointer(TAG_WIRTE_BUF_NO_CACHE_INFO & sWriteBufNoCache)
{
LS_RC lsRc = LS_RC_OK;
//LONG_MAX 0x7fffffff long
LONG lDistanceToMove = (LONG)(sWriteBufNoCache.llTotalWriteIn & LONG_MAX);
LONG lDistanceToMoveHigh = (LONG)(sWriteBufNoCache.llTotalWriteIn >> 31);
LONGLONG ullFileSize = sWriteBufNoCache.llTotalWriteIn;
if(INVALID_SET_FILE_POINTER == SetFilePointer(sWriteBufNoCache.hFileToWrite, lDistanceToMove, &lDistanceToMoveHigh, FILE_BEGIN))
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto END;
}
if(!SetEndOfFile(sWriteBufNoCache.hFileToWrite))
{
lsRc = MakeLsErrSn(LS_RC_ERR_FILE_WRITE);
goto END;
}
END:
return lsRc;
}
LS_NAMESPACE_END
还没有封装成类, 不是很好用.
demo上传位置: FileOptNoCache_V2011_0725_0202.rar
http://download.csdn.net/source/3466635
<2011_0801>
遇到了奇怪问题,无缓冲区读文件时总是失败. 最后发现, 无缓冲区读,也是要读扇区倍数的字节数. 用无缓冲区方法写文件时,写完扇区倍数字节完成后,因为文件一般都不是扇区倍数字节的,最后要用SetFilePointer和EndOfFile来确定正确的文件Size. 读这种带零头的文件时,实际操作时怎样的呢? 有时间再做实验。 无缓冲区读写,不知道什么样的实际场景非要使用无缓冲区读写。 真不方便。