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

来源:互联网 发布:算法导论13章答案 编辑:程序博客网 时间:2024/04/28 07:38

使用c标准库函数实现小文件逆序存储逻辑是:

1.用fopen函数成功打开源文件和目标文件,源文件用只读方式(r)打开,目标文件用追加写入(a)的方式打开;

2.循环使用fseek定位文件指针(fopen的返回值),从SEEK_END(文件末尾)位置开始,每次多向前偏移一个字节,知道fseek返回一个非0值结束;(fseek能改变文件指针)

3.每次定位成功后,读取一个字符(fread)到缓冲区,读取成功后将缓冲区数据写入(fwrite)目标文件指针。

这边要注意4个函数的返回值,这些返回值是程序每一步执行的判断标志

fopen返回一个文件指针,返回NULL表示文件打开失败;

fseek返回一个整数,成功定位返回0,否则返回非0值;

fread返回读取的字符数。

测试代码如下:

#include <iostream>#include <ctime>#include <fstream>#include <tchar.h>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 = "<<tEnd - tBegin<<endl;}int main(){ReverseCopy("in.txt", "c_out.txt");return 0;}


经过测试,该方法的性能也存在问题,不适合大文件.

 

修改:

以上方法只支持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 = "<<tEnd - tBegin<<endl;}


 

原创粉丝点击