fopen,fread和fwrite
在最近的编程练习和写东西的过程中,常常用到了fopen和fread两个函数来读取本地文件。之前使用这两个函数时,一直没有出现过什么问题。也是因为没有出现问题,对这两个函数的用法的一些细节没有很了解,所以导致这次使用出现了问题。
这次在尝试写一个简单C编译器的过程中,第一步就是需要从本地读取需要编译的源码文件,于是自然又想到了这两个函数。但是在使用过程中,出现了一些奇怪的问题。具体问题就是:将本地文件读取到内存中,在控制台输出读到的文件内容,结果发现控制台输出中读到的数据不对,末尾数据多了部分字符。
程序源码如下:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#define MAX_SIZE 256*1024 char src[MAX_SIZE]; int main(int argc ,char** argv)
{
char file_name[];
printf("input file name:");
scanf("%s",file_name);
int line=;
FILE * fp=NULL;
int i=;
if((fp=fopen(file_name,"r"))<)
{
printf("open file fail!\n");
return -;
}
memset(src,,sizeof(MAX_SIZE));
if ((i=fread(src,,MAX_SIZE-,fp))&&i<)
{
printf("read return %d\n",i);
}
printf("%s",src);
system("pause");
return ;
}
需要读取的文件是test.cpp(放在工程源码目录下),文件中的内容如下:
#include <iostream>
using namespace std; int main()
{
cout<<"hello world"<<endl;
return ;
}
在VS或者Dev中编译运行源码,结果如下图所示:

其中画红框部分即为多读的数据。为什么会出现这样的问题?
源码的逻辑过程很简单没有什么错误,那就是在函数的使用上有问题。这里与文件读取有关的就是fopen和fread这两个函数。先来看看fopen函数的原型及参数:
FILE * fopen(const char * path,const char * mode);
第一个参数显然是需要打开的文件路径。第二个参数是文件打开的方式,具体就是控制打开的文件的读取权限和文本方式打开还是二进制文件打开。而该函数的返回值是一个FILE结构体指针。
关于上面产生的错误,其实就是由于文件打开方式不适造成的,这个可能也是很多人容易忽略的。因为觉得只要调用了fopen函数并且加个if判断文件打开成功就没问题了。但是其实第二个参数也会带来问题。回头看看源码中fopen的调用方法,发现第二个参数是"r",即以只读方式打开文件(更多参数自行百度),但是并没有指明是以文本方式打开还是以二进制方式打开。其实,当没有显示声明文件打开方式的时候,该函数默认使用文本方式打开文件,即参数"r"其实等同于"rt"(r:read的缩写、t:txt的缩写)。也正是因为这个原因,造成了上面的错误。在这里,只要把fopen的第二个参数改成"rb",即以二进制文件打开文件,就不会出现上面的错误了。而以文本方式打开文件,可能是因为做了一些字符替换,于是导致了上述的错误。
在这里,可以去了解一下什么是文本文件,什么是二进制文件。文件以文本方式打开和以二进制方式打开有什么区别?
再来看看fread函数。fread从一个文件流中读数据,最多读取count个元素,每个元素size字节,如果调用成功返回实际读取到的元素个数,如果不成功或读到文件末尾返回 0。其函数原型及参数如下:
size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
buffer:接收数据的内存地址
size:每个数据项的字节数,单位是字节。
count:要读取count个数据项,每个数据项size个字节。
stream:输入流
返回值是size_t类型,这也是一个值得留意的地方。
看完上面的参数,来稍微解释一下fread是怎么进行的。fread最多读取size*count个字节,但是不是一次读取完,而是每次读取size个字节,一共读count次。当某次读取不足size字节时,则读到了文件末尾,并返回一共成功读了几次size字节。下面举个例子说明:假设fp指向一个5个字节的文件,调用fread函数将文件内容读到buffer:
int i=fread(buffer,,,fp);
上面的调用表示最多读取10次,每次读取2个字节,而文件只有5个字节,那么i的值是多少?答案是2.第一次读取两个字节,第二次再读取两个字节,到了第三次,只剩下一个字节了,不足一个size的大小,所以这次不进行计数,因此返回值是2,而不是3.
同样的,fread对应的函数fwrite有着类似的参数和执行过程。
fopen,fread和fwrite的更多相关文章
- open/fopen read/fread write/fwrite区别
fopen /open区别 UNIX环境下的C 对二进制流文件的读写有两套班子:1) fopen,fread,fwrite ; 2) open, read, write这里简单的介绍一下他们的区别.1 ...
- fopen\fread\fwrite\fscanf\fprintf\fseek\feof\rewind\fgets\fputc等系列函数使用总结
转载自:http://blog.csdn.net/xidianzhimeng/article/details/23541289 1 fopen 函数原型:FILE * fopen(const char ...
- fopen\fread\fwrite\fseed函数的使用
使用 <stdio.h> 头文件中的 fopen() 函数即可打开文件,它的用法为: FILE *fopen(char *filename, char *mode); filename为文 ...
- 函数fgets和fputs、fread和fwrite、fscanf和fprintf用法小结 (转)
函数fgets和fputs.fread和fwrite.fscanf和fprintf用法小结 字符串读写函数fgets和fputs 一.读字符串函数fgets函数的功能是从指定的文件中读一个字符串到字符 ...
- Matlab 用fread、fwrite实现大文件读写
最近在分析一个35G的大数据文件,猛一看,是不是很吓人啊,不过还好,师兄写文件的格式非常规范,读取数据来也就很方便了,主要是使用了读写文件的两个函数fread和fwrite,下面用matlab简单尝试 ...
- C++之函数fgetc和fputc、fgets和fputs、fread和fwrite、fscanf和fprintf用法小结
#include <iostream> #include <cstdio> #include <cstdlib> using namespace std; int ...
- C语言中的fread和fwrite
C语言中的fread和fwrite是专门用来操作文件的方法. 1. fread负责从打开的文件指针中读取文件内容. 函数原型:size_t fread(void *p, size_t size, si ...
- fread 和 fwrite 函数用法示例以及注意事项
1.函数功能 用来读写一个数据块. 2.一般调用形式 fread(buffer,size,count,fp); fwrite(buffer,size,count,fp); 3.说明 ( ...
- fread和fwrite的使用
fread和fwrite的使用 fread和fwrite一般用于二进制文件的输入/输出,要不然你打开fwrite写入的文件就是乱码. 1.fread和fwrite函数 数据块I/O fread与fwr ...
随机推荐
- 《DSP using MATLAB》示例Example5.13
- Node.js exports与module.exports的关系
今天搜索module.exports时看到CNode社区上发的Hack Sparrow一篇相关文章的链接 Node.js Module – exports vs module.exports 一篇5年 ...
- wordpress 安装 "Table Prefix" must not be empty.
时隔一年了,一年没有写代码了.又重拾代码,心情无法言表啊.互联网还是有机会的. 安装wordpress怎么装 setp2了就 报 "Table Prefix" must not b ...
- ArcEngine 岛状多边形内部环的获取
ArcEngine岛状多边形获取其内部环 查阅了帮助文档相关接口,内部环的获方法get_InteriorRingBag() 需要外部环作为参数.而外部环可以直接通过ExteriorRingBag属性获 ...
- 2016huasacm暑假集训训练三 G - 还是畅通工程
题目链接:http://acm.hust.edu.cn/vjudge/contest/123674#problem/G 这题和上一道题差不多,还更简单点,直接用prim算法就行,直接贴AC代码: im ...
- IOS网络第三天 - 01-网络文件下载(0922略)
01 数据的安全01 - 密码加密 02 数据的安全02 - 加密过程 01 -数据的安全01 - 本地存储和代码安全 04-网络状态监控 05-真机演示 06-小文件下载 07-大文件下载01-基本 ...
- 【转】logback logback.xml常用配置详解(二)<appender>
原创文章,转载请指明出处:http://aub.iteye.com/blog/1101260, 尊重他人即尊重自己 详细整理了logback常用配置, 不是官网手册的翻译版,而是使用总结,旨在更快更透 ...
- 安卓中級教程(4):ScrollView與ListView之間的高度問題
在scrollView中加插ListView是一個大難題.其中一個難題是Listview的高度難以計算,輸出效果往往強差人意,就讓我們看看當中的問題 . <LinearLayout xmlns: ...
- 宿主机远程桌面连接vmware中的虚拟机
参考了:http://jingyan.baidu.com/article/3052f5a1e8c56397f21f8674.html 感谢~ 宿主机安装了vmware,vmware中安装虚拟机,怎 ...
- 来回切换页面并关闭其他tab
要下班了,就先把这个方法copy上来.反正自己能看懂. public void checkSchemaDetail(String logext, String expectRes){ String c ...