嵌入式之路,贵在日常点滴
---阿杰在线送代码
目录
用fopen、fread、fwrite、fseek来给一个文件写入结构体
系统调用函数属于操作系统的一部分,是为了提供给用户进行操作的接口(API函数),使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机、显示器)等进行交互。

定义:缓冲区就是内存里的一块区域,把数据先存内存里,然后一次性写入硬盘中的文件,类似于数据库的批量操作。
好处:减少对硬盘的直接操作,硬盘的执行速度为毫秒级别,内存为纳秒级别。在硬盘直接操作读写效率太低。
C语言标准库函数fopen()每打开一个文件时候,其都会对应一个单独一个缓冲区而内核缓冲区是公用的。
(2)当我们附带了权限后,打开的文件就只能按照这种权限来操作。
以上这三个常数中应当只指定一 个。下列常数是可选择的:
O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限。
O_EXCL 如果同时指定了OCREAT,而文件已经存在,则出错。
O_APPEND 每次写时都加到文件的尾端。
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。
当然也有组合使用(1.O_RDONLY |O_CREAT 只读如果不存在则创建)(O_WRONLY |O_CREAT 只写如果不存在则创建)(O_WRONLY | O_APPEND 文件存在则追加写入)
fd>0,文件打开成功且fd为文件标识符 fd<0,文件打开失败*/
- #include
- #include
- #include
- #include "stdio.h"
-
- int main()
- {
- int fd;//file description
-
- fd = open("./file1",O_RDWR);
-
- printf("fd = %d\n",fd);
-
- return 0;
- }

运行结果:

下面对flags(2)这类使用(|)进行附加使用的参数进行额外说明:
(1)O_CREAT:文件若不存在则创建
注意:需要额外说明文件操作权限参数mode
- include
- #include
- #include
- #include "stdio.h"
-
- int main()
- {
- int fd;//file description
-
- //尝试打开当前路径下的文件file1.c
- fd = open("./file1",O_RDWR);
-
- //打开失败了
- if(fd == -1){
- printf("open file1 failed,fd = %d\n",fd);
- //尝试以可读可写的方式创建并打开文件
- fd = open("./file1",O_RDWR|O_CREAT,0600);
- if(fd > 0){
- printf("create file1,fd = %d\n",fd);
- }
- }
-
-
- return 0;
- }
运行结果:可以看到已经成功创建了file1.c

(2)O_EXCL:如果同时指定了OCREAT,而文件已经存在,则出错(返回值为-1)
- #include
- #include
- #include
- #include "stdio.h"
-
- int main()
- {
- int fd;//file description
-
- fd = open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
-
- if(fd == -1){
- printf("file1 cunzai\n");
- }
-
-
- return 0;
- }
运行结果:
(3)O_APPEND:每次写时都加到文件的尾端(另起一行)
如果不使用这个参数,因为文件打开后光标是位于文件头的,写入数据会把原来的数据按长度覆盖。(本质上就是光标的问题)
原file1内容

- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
-
- int main()
- {
- int fd;//file description
- char *buf = "a jie hen shuai";
-
- fd = open("./file1",O_RDWR|O_APPEND);
-
- printf("open suscess:fd = %d\n",fd);
-
- int n_write = write(fd,buf,strlen(buf));
- if(n_write != -1){
- printf("write %d byte to file\n",n_write);
- }
-
- close(fd);
-
- return 0;
- }
运行后

若不加O_APPEND
(4)O_TRUNC清空原内容后写入
在每次打开文件写入之前,先把原有的内容清空后写入
原file1内容

- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
-
- int main()
- {
- int fd;//file description
- char *buf = "a jie hen shuai";
-
- fd = open("./file1",O_RDWR|O_TRUNC);
-
- printf("open suscess:fd = %d\n",fd);
-
- int n_write = write(fd,buf,strlen(buf));
- if(n_write != -1){
- printf("write %d byte to file\n",n_write);
- }
-
- close(fd);
-
- return 0;
- }
运行后:
1、可读 r 4
2、可写 w 2
3、执行 x 1

创建文件的另一种方法(不可用于打开)
- int creat(const char *pathname, mode_t mode);
-
- /** mode **
- S_IRUSR 可读 宏:4
- S_IWUSR 可写 宏:2
- S_IXUSR 可执行 宏:1
- S_IRWXU 可读可写可执行 宏:7 */
简单使用示例:
- #include
- #include
- #include
- #include
- #include
-
- int main()
- {
- //可读可写
- int fd = creat("./file1.c",S_IRUSR|S_IWUSR);
- if(fd > 0){
- printf("文件创建成功\n");
- }else{
- printf("同名文件已经存在\n");
- }
- close(fd);
- return 0;
- }
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
-
- int main()
- {
- int fd;//file description
- char *buf = "a jie hen shuai!";
-
- fd = open("./file1",O_RDWR);
-
- if(fd == -1){
- printf("open file1 failed,fd = %d\n",fd);
- fd = open("./file1",O_RDWR|O_CREAT,0600);
- if(fd > 0){
- printf("create file1,fd = %d\n",fd);
- }
- }
-
- printf("create file1,fd = %d\n",fd);
- write(fd,buf,strlen(buf));
-
- close(fd);//关闭文件
-
- return 0;
- }
运行结果:


- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- int main()
- {
- int fd;//file description
- char *buf = "a jie hen shuai!";
-
- fd = open("./file1",O_RDWR);
-
- if(fd == -1){
- printf("open file1 failed,fd = %d\n",fd);
- fd = open("./file1",O_RDWR|O_CREAT,0600);
- if(fd > 0){
- printf("create file1,fd = %d\n",fd);
- }
- }
-
- printf("create file1,fd = %d\n",fd);
- int n_write = write(fd,buf,strlen(buf));
- if(n_write != -1){
- printf("write %d byte to file\n",n_write);
- }
-
- close(fd);//关闭文件
-
- fd = open("./file1",O_RDWR);//重新打开
- char *readBuf;
- readBuf = (char *)malloc(sizeof(char)*n_write + 1);
- int n_read = read(fd,readBuf,n_write);
-
- printf("read %d,contest:%s\n",n_read,readBuf);
- close(fd);
-
- return 0;
- }
运行结果:
read最需要注意的就是光标的位置,尤其是在write操作后,光标已经到达文件尾部,直接read,就会读个寂寞。解决办法是重新打开文件(不建议)使光标回到文件头。或者使用后面所提到的
lseek操作光标。
whence参数补充说明
SEEK_SET:偏移到文件头+ 设置的偏移量
SEEK_CUR:偏移到当前位置+设置的偏移量
SEEK_END:偏移到文件尾置+设置的偏移量
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- int main()
- {
- int fd;//file description
- char *buf = "a jie hen shuai!";
-
- fd = open("./file1",O_RDWR);
-
- if(fd == -1){
- printf("open file1 failed,fd = %d\n",fd);
- fd = open("./file1",O_RDWR|O_CREAT,0600);
- if(fd > 0){
- printf("create file1,fd = %d\n",fd);
- }
- }
-
- printf("create file1,fd = %d\n",fd);
- int n_write = write(fd,buf,strlen(buf));
- if(n_write != -1){
- printf("write %d byte to file\n",n_write);
- }
-
- // close(fd);
- // fd = open("./file1",O_RDWR);
-
- char *readBuf;
- readBuf = (char *)malloc(sizeof(char)*n_write + 1);
- //使得光标移动到文件的开始位置:
- lseek(fd,0,SEEK_SET);//将光标移动至首
-
- int n_read = read(fd,readBuf,n_write);
-
- printf("read %d,contest:%s\n",n_read,readBuf);
- close(fd);
-
- return 0;
- }
运行结果:

(1) 返回当前的偏移量
- int fd,ret;
- fd=open("hello1.txt",O_RDWR);
- ret=lseek(fd,0,SEEK_CUR);
- printf("%d\n",ret);
(2)返回文件大小
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- int main()
- {
- int fd;//file description
- char *buf = "a jie hen shuai!";
-
- fd = open("./file1",O_RDWR);
-
- int filesize = lseek(fd,0,SEEK_END);
- printf("file's size is :%d\n",filesize);
- close(fd);
-
- return 0;
- }
运行结果:
(3)☆扩充文件大小
特别注意扩充文件大小后 需要写入内容 否则扩充不生效
- #include
- #include
- #include
- #include
- int main()
- {
- int fd,ret;
- char a[]="JMU WELCOME";
- fd=open("hello1.txt",O_RDWR|O_CREAT,0777);
- ret=lseek(fd,1000,SEEK_END);
- write(fd,a,strlen(a));
- printf("%d\n",ret);
- return 0;
- }
int close(int fd);- int fd;
- fd=open("tmp.txt",O_RDONLY);
- close(fd);
cp src.c(源文件) des.c(目标文件)
1、 C语言参数 ./a.out argc(3个参数) argv(数组指针-》数组的数组)
#include "stdio.h" int main(int argc,char **argv) { printf("total params:%d\n",argc); printf("No.1 params :%s\n",argv[0]); printf("No.2 params :%s\n",argv[1]); printf("No.3 params :%s\n",argv[2]); return 0; } /** 参数 argc: 参数个数 **argv:二级指针,数组的指针,即这个指针里的每一项都是一个数组(字符串) **/
2、编程思路:
- (1)打开src源文件(要被复制的文件)
- (2)把源文件的内容读入buf
- (3)创建目标文件
- (4)把buf内容写入目标文件
- (5)关闭源文件与目标文件
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- int main(int argc,char **argv)
- {
- int fdSrc;//file description
- int fdDes;
- char *readBuf = NULL;
-
- if(argc != 3){ //判断是否为三个参数
- printf("pararm error\n");
- exit(-1);
- }
-
- //(1)打开src源文件(要被复制的文件)
- fdSrc = open(argv[1],O_RDWR); //打开src.c
- int size = lseek(fdSrc,0,SEEK_END);//计算存储fdSrc文件的字节大小
- lseek(fdSrc,0,SEEK_SET);//将光标移到开头
- readBuf = (char *)malloc(sizeof(char)*size + 8);
- //(2)把源文件的内容读入buf
- int n_read = read(fdSrc,readBuf,size);//读src到buf
-
- //(3)创建目标文件,如果已经存在则覆盖
- fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);//打开/创建des.c
- //(4)把buf内容写入目标文件
- int n_write = write(fdDes,readBuf,strlen(readBuf));//将buf写入到des.c
-
- //(5)关闭源文件与目标文件
- close(fdSrc);
- close(fdDes);
- return 0;
- }
运行结果:

fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);//打开/创建des.c
你是否有想过这里为什么要加上这两个额外说明吗O_CREAT:文件若不存在则创建
O_TRUNC:在每次打开文件写入之前,先把原有的内容清空后写入(否则,如果new的文件已经存在且字节数比较多时,仅仅是覆盖数据而已,多出来的字节数还是原先new的内容)
现有某配置文件如config,要求利用文件编程把LENG的值修改为5.
SPEED=3
LENG=3
SCORE=9
LEVEL=5
简单示例:
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- int main(int argc,char **argv)
- {
- int fdSrc;//file description
- char *readBuf = NULL;
-
- if(argc != 2){
- printf("pararm error\n");
- exit(-1);
- }
-
- fdSrc = open(argv[1],O_RDWR);
- int size = lseek(fdSrc,0,SEEK_END);//ji suan chu fdSrcwenjian de zi jie da xiao
- lseek(fdSrc,0,SEEK_SET);
- readBuf = (char *)malloc(sizeof(char)*size + 8);
- int n_read = read(fdSrc,readBuf,size);
-
- char *p = strstr(readBuf,"LENG=");
- if(p==NULL)
- {
- printf("not found\n");
- exit(-1);
- }
-
- p = p+strlen("LENG=");
- *p = '5';
-
- lseek(fdSrc,0,SEEK_SET);
- int n_write = write(fdSrc,readBuf,strlen(readBuf));
-
- close(fdSrc);
- return 0;
- }
运行结果:
SPEED=3
LENG=5
SCORE=9
LEVEL=5
为什么会有这一研究?
如果按照前面进行编写代码 写入文件API 和 读取文件API 操作的都是字符串,直接写入整型数编译会成功,但结果会起冲突。
非要写入整型数呢?让我们先来看看两个函数的原型
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
误区:const void *buf 一定代表着字符串,事实上,并非如此,它也可以代表一个指针 即地址
直接上代码
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- int main(int argc,char **argv)
- {
- int fd;//file description
-
- int data = 100;
- int data2 = 0;
-
- fd = open("./file1",O_RDWR);
-
- int n_write = write(fd,&data,sizeof(int));
- lseek(fd,0,SEEK_SET);//将光标回到文件内容开头,方便后续读取等操作
- int n_read = read(fd,&data2,sizeof(int));
-
- printf("read %d\n",data2);
- close(fd);
-
- return 0;
- }
运行结果:

看完结果,是不是认为这样这样操作也错误了呢
其实不然,结果并没有错误,并不影响程序的写入和读取操作,只不过人眼看起来有点不舒服,ASCII解锁出来并不是我们想象中的样子。(思想:关键是程序读取没错误)
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- struct Test
- {
- int a;
- char c;
- };
-
- int main(int argc,char **argv)
- {
- int fd;//file description
-
- struct Test data = {100,'a'};
- struct Test data2;
-
- fd = open("./file1",O_RDWR);
-
- int n_write = write(fd,&data,sizeof(struct Test));
- lseek(fd,0,SEEK_SET);
- int n_read = read(fd,&data2,sizeof(struct Test));
-
- printf("read %d,%c\n",data2.a,data2.c);
- close(fd);
-
- return 0;
- }
甚至结构体数组
- #include
- #include
- #include
- #include "stdio.h"
- #include
- #include "string.h"
- #include
-
- struct Test
- {
- int a;
- char c;
- };
-
- int main(int argc,char **argv)
- {
- int fd;//file description
-
- struct Test data[2] ={{100,'a'},{101,'b'}};
- struct Test data2[2];
-
- fd = open("./file1",O_RDWR);
-
- int n_write = write(fd,&data,sizeof(struct Test)*2);
- lseek(fd,0,SEEK_SET);
- int n_read = read(fd,&data2,sizeof(struct Test)*2);
-
- printf("read %d,%c\n",data2[0].a,data2[0].c);
- printf("read %d,%c\n",data2[1].a,data2[1].c);
- close(fd);
-
- return 0;
- }
运行结果(结果并没有错误)

1.对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时。用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。
按照惯例,UNIX shell使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合。STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO这几个宏代替了0、1、2这几个数。
在Linux下,对文件的操作都是通过文件描述符来进行的。linux进程默认会打开三个文件描述符,分别是
0 stdin 标准输入 对应设备:键盘
#include #include #include #include "stdio.h" #include #include "string.h" #include int main(int argc,char **argv) { int fd;//file description char readBuf[128]; int n_read = read(0,readBuf,5); int n_write = write(1,readBuf,strlen(readBuf)); printf("\ndone\n"); return 0; }运行结果:
![]()
2.文件描述符,这个数字在一个进程中表示一个特定含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果要操作这个动态文件,只需要用这个文件描述符区分。
3.文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。
open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1.
1.在linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后是close关闭文件即可。
2.我们对文件进行操作时,一定要先打开文件,打开成功之后才能操作,如果打开失败,就不用进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏。
3.文件平时是存放在块设备中的文件系统文件中的,我们把这种文件叫静态文件,当我们去open打开一个文件时,linux内核做到操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(叫动态文件)。
静态文件:存放于磁盘,未被打开的文件
动态文件:当使用
open后,在linux内核会产生一个结构体来记录文件的信息,例如fd,buf,信息节点.此时的read,write都是对动态文件进行操作,当close时,才把缓存区所有的数据写回磁盘中。
4.打开文件以后,以后对这个文件的读写操作,都是针对内存中的这一份动态文件的,而不是针对静态文件的。当然我们对动态文件进行读写以后,此时内存中动态文件和块设备文件中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。
5.为什么这么设计,不直接对块设备直接操作。
块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。
对于这两个名字很类似的函数,对于很多初学者来说,不容易搞清楚它们有什么不同,只知道按照函数用法使用。如果能很好的区分两者,相信大家对于C语言和UNIX系统(包括LINUX)有更深入的了解。
在网上查找了一些资料,但是感觉不够全面,一些答案只是从某个角度阐述,所以让人觉得,这个也对,那个也对。但到底谁的表述更正确呢?其实都是对的,只是解释的视角不同罢了。下面结合个人的理解做一些梳理。
从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:
open 是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。fopen 是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。
这一点从上面的来源就可以推断出来,`fopen`是C标准函数,因此拥有良好的移植性;而`open`是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数`CreateFile`。
open 返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。
fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。open, close, read, write, getc, getchar, putc, putchar等。一句话总结一下,就是open无缓冲,fopen有缓冲。前者与read, write等配合使用, 后者与fread,fwrite等配合使用。
使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:read,write);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。
这样一总结梳理,相信大家对于两个函数及系列函数有了一个更全面清晰的认识,也应该知道在什么场合下使用什么样的函数更合适,效率更高。
使用给定的模式 mode 打开 filename 所指向的文件。
#include
FILE *fopen(const char *path, const char *mode);//返回的是文件标识符
fopen函数用的是标准C语言库,第一个参数是文件路径,第二个参数是文件权限。
/** 返回值 **/
打开成功,指向该流的文件指针就会被返回。
打开失败,则返回 NULL,并把错误代码存在 error 中。
/** 参数 **/
mode: "r" 只读 文件必须存在
"w" 只写 文件创建,若存在则清空
"a" 只读 打开或创建,在文件末尾追加
带有"+"的 可读可写
带有"b"的 二进制文件
r:以只读方式打开文件,该文件必须存在。
r+:以读/写方式打开文件,该文件必须存在。
rb+:以读/写方式打开一个二进制文件,只允许读/写数据。
rt+:以读/写方式打开一个文本文件,允许读和写。
w:打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
w+:打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
a:以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF 符保留)。
a+:以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。
wb:以只写方式打开或新建一个二进制文件,只允许写数据。
wb+:以读/写方式打开或新建一个二进制文件,允许读和写。
wt+:以读/写方式打开或新建一个文本文件,允许读和写。
at+:以读/写方式打开一个文本文件,允许读或在文本末追加数据。
ab+:以读/写方式打开一个二进制文件,允许读或在文件末追加数据。
从给定流 stream 读取数据到 ptr 所指向的数组中。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
/** 参数 **/
ptr 指向带有最小尺寸 size*nmemb 字节的内存块的指针。(buf缓冲区)
size 要读取的每个元素的大小,以字节为单位。
nmemb 元素的个数,每个元素的大小为 size 字节。
stream 流
/** 返回值 **/
成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。
如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。
把 ptr 所指向的数组中的数据写入到给定流 stream 中。
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
/** 参数遇返回值和fread一样 **/
或者换种容易理解点的
参数一:要往文件写入的内容,是字符串格式
参数二:一次写入的字节数
参数三:写多少次
参数四:目标文件标识符
操作文件指针的位置
int fseek(FILE *stream, long int offset, int whence)
/* 参数 */
offset 相对 whence 的偏移量,以字节为单位。
whence 文件指针的位置
SEEK_SET 文件的开头
SEEK_CUR 文件指针的当前位置
SEEK_END 文件的末尾
/* 参数 */
如果成功,则该函数返回零,否则返回非零值。
简单示例
- #include "stdio.h"
- #include "stdlib.h"
- #include "string.h"
-
- int main()
- {
- //以可读可写的方式创建文件,若存在则清空原文件
- FILE* fp = fopen("./fopenTest","w+");
- char* str = "chen li chen mei wo shuai";
-
- //向文件流中写入字符串
- fwrite(str,sizeof(char),strlen(str),fp);
-
- //文件指针回头才能读取
- fseek(fp,0,SEEK_SET);
-
- char* readBuf = (char *)malloc(strlen(str));
- memset(readBuf,'\0',strlen(str));
-
- fread(readBuf,sizeof(char),strlen(str),fp);
-
- //打印出读取到的readBuf
- printf("read:%s\n",readBuf);
-
- fclose(fp);
-
- return 0;
- }
运行结果:
![]()
等效于
- #include "stdio.h"
- #include "stdlib.h"
- #include "string.h"
-
- int main()
- {
- FILE* fp = fopen("./fopenTest","w+");
- char* str = "chen li chen mei wo shuai";
-
- fwrite(str,sizeof(char)*strlen(str),1,fp);
-
- fseek(fp,0,SEEK_SET);
-
- char* readBuf = (char *)malloc(strlen(str));
- memset(readBuf,'\0',strlen(str));
-
- fread(readBuf,sizeof(char)*strlen(str),1,fp);
-
- printf("read:%s\n",readBuf);
-
- fclose(fp);
-
- return 0;
- }
补充,研究一下fread和fwrite返回的值
- #include "stdio.h"
- #include "stdlib.h"
- #include "string.h"
-
- int main()
- {
- FILE* fp = fopen("./fopenTest","w+");
- char* str = "chen li chen mei wo shuai";
-
- int nwrite = fwrite(str,sizeof(char)*strlen(str),1,fp);
-
- fseek(fp,0,SEEK_SET);
-
- char* readBuf = (char *)malloc(strlen(str));
- memset(readBuf,'\0',strlen(str));
-
- int nread = fread(readBuf,sizeof(char)*strlen(str),1,fp);
-
- printf("read:%s\n",readBuf);
- printf("read=%d,write=%d\n",nread,nwrite);
-
- fclose(fp);
-
- return 0;
- }
运行结果:
得出结论:
写返回的值取决于第三个参数
读返回的值就不一定了
int nread = fread(readBuf,sizeof(char)*strlen(str),1,fp);
nread = 1
int nread = fread(readBuf,sizeof(char)*strlen(str),100,fp);
nread = 1
int nread = fread(readBuf,sizeof(char),strlen(str),fp);
nread = 25
- #include
- #include
-
- struct data
- {
- int a;
- char b;
- };
-
- int main()
- {
- FILE* fp;
-
- struct data test2 = {1,'q'};
- struct data test1;
-
- fp = fopen("./file2","w+");//返回文件标识符
-
- fwrite(&test2,sizeof(struct data),1,fp);//每次写多少数据,写多少次
-
- fseek(fp,0,SEEK_SET);//光标移到文件头
-
- fread(&test1,sizeof(struct data),1,fp);
- fclose(fp);
-
- printf("test1.a = %d test1.b = %c\n",test1.a,test1.b);
- return 0;
- }
描述
C 库函数 int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
参数
- char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
- stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。
返回值
如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
- #include "stdio.h"
-
- int main()
- {
- FILE *fp;
-
- fp = fopen("./test.txt","w+");
- fputc('a',fp);
-
- fclose(fp);
-
- return 0;
- }
运行结果:
写多个字符
- #include "stdio.h"
- #include "string.h"
-
- int main()
- {
- FILE *fp;
- int i;
- char *str = "chenlichen mei wo shuai";
- int len = strlen(str);
-
- fp = fopen("./test.txt","w+");
- for(i=0;i
- fputc(*str,fp);
- str++;
- }
-
- fclose(fp);
-
- return 0;
- }
for(i=0;i
fputc(*str,fp);
str++;
}
这样可以吗
显然是不可以的,每次str都在变,for里面的条件就一直在变
fgetc
描述
C 库函数 int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
参数
- stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。
返回值
该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
feof
描述
C 库函数 int feof(FILE *stream) 测试给定流 stream 的文件结束标识符。
参数
- stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
返回值
当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。
- #include "stdio.h"
- #include "string.h"
-
- int main()
- {
- FILE *fp;
- char c;
-
- fp = fopen("./test.txt","r");
-
- while(!feof(fp)){
- c = fgetc(fp);
-
- printf("%c",c);
- }
-
- fclose(fp);
-
- return 0;
- }