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 ...
随机推荐
- LinQ和ADO.Net增删改查 备忘
是否些倦了 SqlConnection conn=new SqlConnection();一系列繁冗的代码? 来试试Linq吧 查: using System.Data.SqlClient; name ...
- android 多媒体数据库详解(转)
转自:http://www.2cto.com/kf/201309/242876.html 主要分为几节: 1. Android的媒体文件内部是如何存储的? 2. Andoid的媒体文件如何获取? 3. ...
- Node.js-npm【1】-常用命令
查看版本:npm -v 获取全局目录:npm config get prefix 设置全局目录npm config set prefix "D:\Program Files\nodejs\n ...
- 在DrawingVisual上绘制圆形的进度条,类似于IOS系统风格。
1.说明:在WPF中,文件下载时需要显示下载进度,由于系统自带的条型进度条比较占用空间,改用圆形的进度条,需要在DrawingVisual上呈现. 运行的效果如图: private Point Get ...
- asp.net 数据绑定 -- 时间格式
<asp:TemplateField HeaderText="日期" SortExpression="Date"> & ...
- Node.js实现CORS跨域资源共享
什么是CORS CORS(Cross-origin resource sharing),跨域资源共享,是一份浏览器技术的规范,用来避开浏览器的同源策略 简单来说就是解决跨域问题的除了jsonp外的另一 ...
- 访问本地json文件因跨域导致的问题
我使用jquery的getJSON的方法获取本地的json文件,并进行操作,获取json 数据代码如下: $.getJSON("invite_panel.json",functio ...
- 【转】logback logback.xml常用配置详解(三) <filter>
原创文章,转载请指明出处:http://aub.iteye.com/blog/1110008, 尊重他人即尊重自己 详细整理了logback常用配置, 不是官网手册的翻译版,而是使用总结,旨在更快更透 ...
- 安卓中級教程(4):ScrollView與ListView之間的高度問題
在scrollView中加插ListView是一個大難題.其中一個難題是Listview的高度難以計算,輸出效果往往強差人意,就讓我們看看當中的問題 . <LinearLayout xmlns: ...
- 10款最新流行的 jQuery 插件,值得你收藏
10款最新流行的 jQuery 插件,值得你收藏 http://www.cnblogs.com/lhb25/p/10-new-popular-jquery-plugins-check.html 你应该 ...