使用c标准库函数实现小文件逆序存储逻辑是:
1.用fopen函数成功打开源文件和目标文件,源文件用只读方式(r)打开,目标文件用追加写入(a)的方式打开;
2.循环使用fseek定位文件指针(fopen的返回值),从SEEK_END(文件末尾)位置开始,每次多向前偏移一个字节,知道fseek返回一个非0值结束;(fseek能改变文件指针)
3.每次定位成功后,读取一个字符(fread)到缓冲区,读取成功后将缓冲区数据写入(fwrite)目标文件指针。
这边要注意4个函数的返回值,这些返回值是程序每一步执行的判断标志
fopen返回一个文件指针,返回NULL表示文件打开失败;
fseek返回一个整数,成功定位返回0,否则返回非0值;
fread返回读取的字符数。
测试代码如下:
#include
#include
#include
#include
using namespace std;
void ReverseCopy(const char* pSrcFile, const char* pDestFile)
{
if(!pSrcFile || !pDestFile) return;
time_t tBegin = time(0);
FILE* pSrc = fopen(pSrcFile, "r");
if(!pSrc) return;
FILE* pDest = fopen(pDestFile, "a");
if(!pDest)
{
fclose(pSrc);
return;
}
TCHAR ch[1] = {0};
int nElementSize = sizeof(TCHAR);
long lSeek = -nElementSize;
while(fseek(pSrc, lSeek, SEEK_END) == 0)
{
if(fread(ch, nElementSize, 1, pSrc) > 0)
{
fwrite(ch, nElementSize, 1, pDest);
}
lSeek -= nElementSize;
}
fclose(pDest);
fclose(pSrc);
time_t tEnd = time(0);
cout<<"File op time = "<
经过测试,该方法的性能也存在问题,不适合大文件.
修改:
以上方法只支持windows中ANSI编码的纯中文文本文件,因为UNICODE编码的工程中TCHAR为双字节,每次读取两个字节作为一个字符,遇到英文字符就会出现乱码,现在根据中文字符与英文字符的编码特点做以下修改。ANSI编码的文件中,中文字符(2个字节)高字节最高位为1,英文字符(1个字节)最高位为0,所以每次读取两个字节,与0x00008000作与运算,结果为真时,则将两个字节作为一个中文字符写入目标文件,否则,只写入高字节。ReverseCopy函数修改如下:
void ReverseCopy(const char* pSrcFile, const char* pDestFile)
{
if(!pSrcFile || !pDestFile) return;
time_t tBegin = time(0);
FILE* pSrc = fopen(pSrcFile, "r");
if(!pSrc) return;
FILE* pDest = fopen(pDestFile, "a");
if(!pDest)
{
fclose(pSrc);
return;
}
const int nflagChinese = 0x00008000;
const int nWordSize = sizeof(WORD);
const int nCharSize = 1;
WORD ch[1] = {0};
long lSeek = -2;
bool bLastIsEn = false;//记录上次写入的是中文字符函数英文字符,如果是英文,那文件可能只剩一个字节,没法再向前seek两个字节
while(fseek(pSrc, lSeek, SEEK_END) == 0)
{
if(fread(ch, nWordSize, 1, pSrc) > 0)
{
WORD wCh = ch[0];
if(wCh & nflagChinese)//检查是否为中文字符
{
fwrite(ch, nWordSize, 1, pDest);
lSeek -= 2;
bLastIsEn = false;
}
else
{//高字节为英文,只写入高字节
BYTE b = HIBYTE(wCh);
fwrite(&b, 1, 1, pDest);
lSeek -= 1;
bLastIsEn = true;
}
}
}
if(bLastIsEn && fseek(pSrc, ++lSeek, SEEK_END) == 0)
{//读取最后一个英文字节
char lastCh[1] = {0};
if(fread(lastCh, 1, 1, pSrc) > 0)
fwrite(lastCh, 1, 1, pDest);
}
fclose(pDest);
fclose(pSrc);
time_t tEnd = time(0);
cout<<"File op time = "<