文件压缩项目的有关问题

1、feof()与EOF

昨天突然被一位朋友问到了关于文件结尾的程序问题。在用feof()判断文件时,复制会多产生一个字符。
这个问题在大一的时候,老师上课就强调过,但那时只是模糊的记得个大概,记得这个函数如果用的不对就是会出现问题,解决是要先读一下,然后再判断,具体的什么还真实忘了。而且平常经常用的EOF,所以这个问题自己并没有一个特别好的概念。
现在写的C语言多了,应该能理解这个问题存在的原因。所以就在网上找了好多关于这个问题的解释,一看还真不少,但是好多都说的不清除,让人看完后,感觉默默糊糊的。但是还是在其中学到了不少的知识。现在就把我的理解给写出来,希望都能互相学习下。
查看 stdio.h 可以看到如下定义:
#define  EOF  (-1)
#define  _IOEOF  0x0010 
#define  feof(_stream)  ((_stream)->_flag & _IOEOF)


由此可以看出,这两种方式的原理是不同的。

在这里先说下EOF和feof()这个两个宏定义,在我们学的课本中有这样的描述。
EOF是不可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于EOF时,表示读入的已不是正常的字符而是文件结束符,但这适用对文本文件的读写。在二进制文件中,信息都是以数值方式存在的。EOF的值可能就是所要处理的二进制文件中的信息。这就出现了需要读入有用数据却被处理为“文件结束“的情况。为了解决这个问题,C提供了一个feof()函数,可以用它来判断文件是否结束。feof(fp)用于测试fp所指向的文件的当前状态是否为“文件结束”。如果是,函数则返回的值是1(真),否则为0(假)。
说了这两个的定义,肯定还对二进制文件和文本文件的区别有些模糊(唉,因为我当时就对这些搞不懂),那现在就回顾下这两个文件的概念。C语言支持的是流式文件,它把文件看作由一个一个的字符(字节)数据组成的序列。根据数据的组织和操作形式,可以分为ASCII文件和二进制文件。


ASCII文件又称为文本文件,它是在一个字节的存储单元上存放一个字符(在外存中存放的是该字符的ASCII码,每个字符将占一个字节)。
二进制文件是把内存中的数据按其在内存中的存储格式在磁盘上原样保存。 
对字符而言,由于其外存存储格式和内存表示格式相同,所以,在外存上也存放每个字符的ASCII码
但是说EOF只能用于文本文件,其实不然,这点不是特别的准确,还要看定义的变量的类型。
下面这段程序对文本文件和二进制文件都可以:
int c;
while((c=fgetc(fp)) != EOF)
{
printf("%X/n", c); 
}
如果读到了FF,由于c定义为int型,所以实际上c=0x000000FF,不等于EOF(-1=0xFFFFFFFF),因此不会误判为文件结尾。
但是如果把c定义为char类型,就有可能产生混淆了。
char c;
while((c=fgetc(fp)) != EOF)
{
printf("%X/n", c); 
}
因为文本文件中存储的是ASCII码,而ASCII码中FF代表空值(blank),一般不使用,所以如果读文件返回了FF,说明已经到了文本文件的结尾。但是如果是二进制文件,其中可能会包含FF,因此不能把读到EOF作为文件结束的条件,此时只能用feof()函数。
在VC里,只有当文件位置指针(fp->_ptr)到了文件末尾,然后再发生读/写操作时,标志位(fp->_flag)才会被置为含有_IOEOF。然后再调用feof(),才会得到文件结束的信息。
因此,如果运行如下程序:
char c;
while(!feof(fp))
{
c = fgetc(fp);
printf("%X/n", c); 
}
会发现多输出了一个FF,原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。这样就多输出了一个-1(即FF)。
正确的写法应该是:
char c;
c = fgetc(fp);
while(!feof(fp))
{
printf("%X/n", c); 
c = fgetc(fp);


2、const char *c_str();
c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.


c_str()就是把string类对象转换成和c兼容的char *类型。
这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。
注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针
比如:最好不要这样:
char* c;
string s="1234";
c = s.c_str(); //c最后指向的内容是垃圾,因为s对象被析构,其内容被处理


应该这样用:
char c[20];
string s="1234";
strcpy(c,s.c_str());
这样才不会出错,c_str()返回的是一个临时指针,不能对其进行操作


再举个例子
c_str() 以 char* 形式传回 string 内含字符串
如果一个函数要求char*参数,可以使用c_str()方法:
string s = "Hello World!";
printf("%s", s.c_str()); //输出 "Hello World!"


3、

把stream.str("");     那一行的注释去掉,再运行程序,内存就正常了


    看来stringstream似乎不打算主动释放内存(或许是为了提高效率),但如果你要在程序中用同一个流,反复读写大量的数据,将会造成大量的内存消耗,因些这时候,需要适时地清除一下缓冲 (用 stream.str("") )。


    另外不要企图用 stream.str().resize(0),或 stream.str().clear() 来清除缓冲,使用它们似乎可以让stringstream的内存消耗不要增长得那么快,但仍然不能达到清除stringstream缓冲的效果(不信做个 实验就知道了,内存的消耗还在缓慢的增长!),至于stream.flush(),则根本就起不到任何作用。


4、char *itoa(int value,char *string,int radix) 将整数value转换成字符串存入string, radix为转换时所用基数(保存到字符串中的数据的进制基数)

5、

刚开始接触C++,很多不懂的地方,翻看老大给的代码其中  year = atoi(dateStr.substr(0, 4).c_str());云里雾里。

year = atoi(dateStr.substr(0, 4).c_str());

里面包含三个函数,分别是atoi(),substr(),c_str().

百度:

atoi()函数原型为: int atoi(char *str),用途是将字符串转换成一个整数值,str是待转化成整数值的字符串.成功则返回转化后的整数值,失败返回0.
substr()函数原型为:basic string::substr(string,start,length),也可把string移到外面,为string &a,a.substr(start,length),其中a是待截取的字符串,start表示从截取开始的前一位,length表示截取长度,例如string &a="hello world",则a.substr(6,5)=world.
c_str()函数原型为:const char *c_str(),如果要将string对象,转化为char*对象,c_str()提供了这样一种方法,它返回一个客户程序可读不可改的指向字符数组的指针。

所以year=atoi(dateStr.substr(0,4).c_str())的作用就是,截取string型的对象dateStr,并转化为char*对象,然后将此字符串转换成一个整数值,赋值给year(year是int型).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值