逆序存储文件(二)——使用c标准库函数fopen,fseek,fread,fwrite

使用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 = "<


 

你可能感兴趣的:(其他)