本文主要是C语言——标准I/O基本操作的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
点击查看相关文件下载
一、文件打开与关闭
1. 基本函数
1.1 fopen()
在 linux 下可以使用 man 3 fopen 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
FILE *fopen(char *filename, char *mode);
|
【函数说明】该函数。
【函数参数】
- filename :为文件名(可以包含文件路径),为字符串型。
- mode :打开方式,为字符串型。
点击查看详细的 mode
(1)mode的取值
控制读写权限的字符串(必须写) |
打开方式 | 说明 |
"r" | 以只读方式打开文件。只允许读取,不允许写入,文件必须存在,否则打开失败。 |
"w" | 以写入方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 |
"a" | 以追加方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 |
"r+" | 以读写方式打开文件。既可以读取也可以写入。文件必须存在,否则打开失败。 |
"w+" | 以写入/更新方式打开文件,相当于w和r+叠加的效果。既可以读取也可以写入。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 |
"a+" | 以追加/更新方式打开文件,相当于a和r+叠加的效果。既可以读取也可以写入。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 |
控制读写方式的字符串,与上边连用(可以省略) |
"t" | 文本文件。如果不写,默认为"t"。 |
"b" | 二进制文件。 |
【说明】读写权限和读写方式可以组合使用,但是必须将读写方式放在读写权限的中间或者尾部。例如, “rb” 、 “r+b” 、 “rb+” 。
【注意】对于 Windows 平台,确保换行符不会有所影响,最好用 “t” 来打开文本文件,用 “b” 来打开二进制文件。对于 Linux 平台,则没什么区别。
(2)打开标准 I/O 的六种不同方式
限制 | r | w | a | r+ | w+ | a+ |
文件已存在 | √ | | | √ | | |
删除文件以前内容 | | √ | | | √ | |
流可以读 | √ | | | √ | √ | √ |
流可以写 | | √ | √ | √ | √ | √ |
流可以在尾部写 | | | √ | | | √ |
【返回值】 返回值是一个文件句柄指针,函数获取的文件信息后,包括文件名、文件状态、当前读写位置等,将这些信息保存到一个 FILE 类型的结构体变量中,然后将该变量的地址返回。打开文件出错时,将返回一个空指针,也就是 NULL 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6
| #include <stdio.h>
FILE *fp; fp = fopen("file_name","mode");
|
【注意事项】 none
1.2 fclose()
在 linux 下可以使用 man 3 fclose命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fclose(FILE *stream);
|
【函数说明】该函数关闭一个打开的文件。
【函数参数】
- stream :FILE类型指针变量,表示打开的文件的文件句柄。
【返回值】返回值是一个整数,文件正常关闭时,返回 0 ;如果返回非 0 值则表示有错误发生。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6
| #include <stdio.h>
int ret; ret = fclose(fp);
|
【注意事项】 none
2. 使用实例
点击查看详情
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
#include <stdio.h> #include <errno.h> #include <string.h>
int main(int argc,char*argv[]) { FILE * fp; int fpget; fp = fopen("1f_open.txt", "r"); if(fp == NULL) { printf("Open file Failed\n"); perror("fopen"); printf("fopen:%s\n", strerror(errno)); } else { printf("Open file success\n"); perror("fopen"); printf("fopen:%s\n", strerror(errno)); fpget = fclose(fp); if(fpget == 0) { printf("file close success\n"); perror("fclose"); printf("fclose:%s\n", strerror(errno)); } else { perror("fclose"); printf("fclose:%s\n", strerror(errno)); } } return 0; }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
然后,终端会有以下信息显示(想要打开的文件不存在):
1 2 3
| Open file Failed fopen: No such file or directory fopen:No such file or directory
|
二、文件读写
1. 按字符读写
1.1 fgetc()
在 linux 下可以使用 man 3 fgetc 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fgetc(FILE *stream);
|
【函数说明】该函数读取文件中的一个字符。。
【函数参数】
- stream :FILE类型指针变量,表示打开的文件的文件句柄。
【返回值】返回值是 int 类型不是 char 类型,主要是为了扩展返回值的范围。读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回 EOF 。
点击查看 EOF 说明
EOF 是 end of file 的缩写,表示文件末尾,是在 stdio.h 中定义的宏,它的值是一个负数,往往是 -1 ,但是不绝对是 -1 ,也可以是其他负数,这要看编译器的规定。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7
| #include <stdio.h>
char ch; FILE *fp = fopen("file_name", "r"); ch = fgetc(fp);
|
【注意事项】
(1)在文件内部有一个位置指针(并非 C 语言中的指针,仅仅是一个标志),用来指向当前读写到的位置,也就是读写到第几个字节。在文件打开时,该指针总是指向文件的第一个字节。使用 fgetc() 函数后,该指针会向后移动一个字节,所以可以连续多次使用 fgetc() 读取多个字符。
(2)如何区分 EOF 是读取完毕还是读取出错?
点击查看区分方法
读取完毕和读取出错都会返回 EOF ,此时我们可以借助下边的两个函数来确定到底是哪种情况:
1 2
| int feof(FILE *stream); int ferror(FILE *stream);
|
上边的两个函数都在 stdio.h 文件中,使用之前需要加上这个头文件。
1.2 fputc()
在 linux 下可以使用 man 3 fputc 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fputc(int c, FILE *stream);
|
【函数说明】该函数向指定的文件中写入一个字符。
【函数参数】
- c :为需要写入的字符。
- stream :FILE类型指针变量,表示打开的文件的文件句柄。
【返回值】 返回值是一个 int 型整数,写入成功时返回写入的字符,失败时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8
| #include <stdio.h>
char ch = 'a'; int ret; FILE *fp = fopen("file_name", "w"); ret = fputc(ch, fp);
|
【注意事项】 每写入一个字符,文件内部位置指针向后移动一个字节。
1.3 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
#include <stdio.h>
void test_fgetc(); void test_fputc();
int main(int argc,char*argv[]) { test_fputc(); return 0; }
void test_fgetc() { FILE * fp; int rec; fp = fopen("01fget_put.txt", "r"); if(fp == NULL) { perror("fopen"); return; } rec = fgetc(fp); printf("get char:%c\n", rec); rec = fgetc(fp); printf("get char:%c\n", rec); rec = fgetc(fp); printf("get char:%c\n", rec); if(rec == -1) { perror("fgetc"); fclose(fp); return; } fclose(fp); }
void test_fputc() { FILE * fp; int rec; int wrc; fp = fopen("01fget_put.txt", "a+"); if(fp == NULL) { perror("fopen"); return; } wrc = 'H'; rec = fputc(wrc,fp); if(rec == -1) { perror("fputc"); fclose(fp); return; } putchar(wrc); putchar('\n'); fclose(fp); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
2. 按行读写
2.1 fgets()
在 linux 下可以使用 man 3 fgets()命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
|
【函数说明】该函数读取文件一行中指定大小字节的数据,至多读取一行。
【函数参数】
【返回值】 回值是 char 类型的指针,读取成功时返回字符数组首地址,也即 s ;读取失败时返回 NULL ;如果开始读取时文件内部指针已经指向了文件末尾,那么将读取不到任何字符,也返回 NULL 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9
| #include <stdio.h>
FILE * fp; char * ret; char buff[100]; fp = fopen("file_name", "r"); ret = fgets(buff, 20, fp);
|
【注意事项】
(1)读取到的字符串会在末尾自动添加 ‘\0’ , size 个字符也包括 ‘\0’ 。即实际只读取到了 size-1 个字符,如果希望读取 32 个字符, size 的值应该为 33 。
(2)在读取到 size-1 个字符之前如果出现了换行,或者读到了文件末尾,则读取结束。这就意味着,不管 size 的值多大, fgets() 最多只能读取一行数据,不能跨行。
(3) fgets() 遇到换行时,会将换行符一并读取到当前字符串(若是在 size 字节内遇到换行的话)。
2.2 fputs()
在 linux 下可以使用 man 3 fputs 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fputs(const char *s, FILE *stream);
|
【函数说明】该函数向指定的文件中写入一个字符串。
【函数参数】
- s :为要写入的字符串。
- stream :为文件指针变量。
【返回值】 返回值是一个 int 型整数,写入成功时返回非负数,失败时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8
| #include <stdio.h>
FILE * fp; int rec; fp = fopen("file_name", "a+"); rec = fputs("string",fp);
|
【注意事项】fputs 将缓冲区s中的字符串输出到 stream ,不追加 ‘\n’ 。
2.3 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
#include <stdio.h>
void test_fgets(); void test_fputs();
int main(int argc,char*argv[]) { test_fputs(); return 0; }
void test_fgets() { FILE * fp; char * ret; char buff[100]; fp = fopen("02fgets_puts.txt", "r"); if(fp == NULL) { perror("fopen"); return; } ret = fgets(buff, 20, fp); printf("buff=%s\n",buff); ret = fgets(buff, 20, fp); printf("buff=%s\n",buff); if(ret == NULL) { perror("fgets"); fclose(fp); return; } fclose(fp); }
void test_fputs() { FILE * fp; int rec; fp = fopen("02fgets_puts.txt", "a+"); if(fp == NULL) { perror("fopen"); return; } rec = fputs("\nHello World!",fp); if(rec == -1) { perror("fputs"); fclose(fp); return; } fclose(fp); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
3. 按数据块读写
3.1 fread()
在 linux 下可以使用 man 3 fread 命令查看该函数的帮助手册。
1 2 3 4 5 6
| #include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
|
【函数说明】该函数从指定文件中读取块数据。即若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。
【函数参数】
【返回值】 返回值是 size_t 类型,读取成功时返回成功读取的块数,也即 nmemb 。若如果返回值小于 nmemb (一般是 EOF ),则可能读到了文件末尾,也可能发生了错误,可以用 ferror() 或 feof() 检测。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9 10
| #include <stdio.h>
FILE * fp; char * buff; size_t ret; fp = fopen("03fread_write.txt", "r"); buff=(char*)malloc(100); ret = fread(buff, 10, 1, fp);
|
【注意事项】 fread() 函数可以读取多行,即它遇到 ‘\n’ 的时候也会进行读取。
3.2 fwrite()
在 linux 下可以使用 man 3 fwrite 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
【函数说明】该函数向指定的文件中写入一个块数据。
【函数参数】
【返回值】返回值是一个 size_t 类型,写入成功时返回成功写入的块数,也即 nmemb 。若如果返回值小于 nmemb (一般是 EOF ),则是发生了错误。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9
| #include <stdio.h>
struct student stu = {"fanhua", 18, "male"}; FILE * fp; size_t ret; fp = fopen("file_name", "w"); ret = fwrite(&stu, sizeof(stu), 1, fp);
|
【注意事项】 数据写入完毕后,位置指针在文件的末尾,要想读取数据,必须将文件指针移动到文件开头,如何移动,后边会有说明。
3.3 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
#include <stdio.h> #include <stdlib.h>
struct student { char name[16]; int age; char sex[8]; };
void test_fread(); void test_fwrite();
int main(int argc,char*argv[]) { test_fread(); return 0; }
void test_fread() { FILE * fp; char * buff; size_t ret; fp = fopen("03fread_write.txt", "r"); if(fp == NULL) { perror("fopen"); return; } buff=(char*)malloc(100); if(buff == NULL) { printf("buff malloc failed\n"); return; } ret = fread(buff, 30, 1, fp); if(ret == -1) { perror("fread"); fclose(fp); free(buff); return; } printf("buff=%s\n", buff); fclose(fp); free(buff); }
void test_fwrite() { struct student stu = {"fanhua", 18, "male"}; struct student stu1; FILE * fp; size_t ret; fp = fopen("03fread_write.bin", "w"); if(fp == NULL) { perror("fopen"); return; } ret = fwrite(&stu, sizeof(stu), 1, fp); if(ret == -1) { perror("fwrite"); fclose(fp); return; } else { printf("write struct student success!\n"); } fclose(fp);
fp = fopen("03fread_write.bin","r"); if(fp == NULL) { perror("fopen"); return; } ret = fread(&stu1, sizeof(stu), 1, fp); if(ret == -1) { perror("fread"); fclose(fp); return; } printf("name=%s,age=%d,sex=%s\n",stu1.name,stu1.age,stu1.sex); fclose(fp); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
三、流的操作
1. 流的刷新
其实我们在前边进行文件的写入操作时可以观察一下,若是程序没有执行完毕的时候,我们打开相应的文件,会发现文件中依然什么数据都没有,只有等程序结束,关闭文件后,文件中才会有内容,当我们对文件进行写入的时候,只是将内容写入了缓冲区,却并没有直接写入磁盘文件,当然我们可以执行关闭文件的语句来使数据写入磁盘文件,但是关闭后我们就不能再对这个文件进行操作了,不想关闭文件,又想将数据写入磁盘,怎么做呢?我们可以使用 fflush 函数来实现。
1.1 fflush()
在 linux 下可以使用 man 3 fflush命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fflush(FILE *stream);
|
【函数说明】该函数清空文件缓冲区,如果文件是以写的方式打开 的,则把缓冲区内容写入文件。
【函数参数】
【返回值】 返回值是 int 类型,成功返回 0 ,失败返回 EOF ,错误代码存于 errno 中。指定的流没有缓冲区或者只读打开时也返回 0 值。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9 10
| #include <stdio.h>
FILE * fp; char * buff; size_t ret; fp = fopen("03fread_write.txt", "r"); buff=(char*)malloc(100); ret = fread(buff, 10, 1, fp);
|
【注意事项】 fflush() 也可用于标准输入( stdin )和标准输出( stdout ),用来清空标准输入输出缓冲区。
1.2 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
#include <stdio.h> #include <unistd.h>
void test_none_fflush_stdout(); void test_fflush_stdout(); void test_none_fflush_file(); void test_fflush_file();
int main(int argc,char*argv[]) { test_fflush_stdout(); return 0; }
void test_none_fflush_stdout() { printf("qidaink\n"); printf("fanhua"); while(1) { sleep(1); } }
void test_fflush_stdout() { printf("qidaink\n"); printf("fanhua"); fflush(stdout); while(1) { sleep(1); } }
void test_none_fflush_file() { FILE * fp; fp = fopen("01fflush.txt", "w"); if(fp == NULL) { perror("fopen"); return; } fwrite("Hello World!", 12, 1, fp); while(1) { sleep(1); }
}
void test_fflush_file() { FILE * fp; fp = fopen("01fflush.txt", "w"); if(fp == NULL) { perror("fopen"); return; } fwrite("Hello World!", 12, 1, fp); fflush(fp); while(1) { sleep(1); }
}
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
2. 流的定位
有时候我们想从任意位置开始读写文件怎么办?其实当我们进行文件读写的时候,内部是有一个文件指针的,记录着已经打开的文件的许或者写的位置。
2.1 ftell()
在 linux 下可以使用 man 3 ftell 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
long ftell(FILE *stream);
|
【函数说明】该函数返回给定流 stream
的当前文件读写指针的位置。
【函数参数】
【返回值】 返回值是long
类型,返回的是位置标识符的当前值,出错时返回EOF
。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6
| #include <stdio.h>
FILE * fp; printf("ftell(fp)=%ld\n", ftell(fp));
|
【注意事项】 只适用2G
以下的文件。
2.2 fseek()
在 linux 下可以使用 man 3 fseek 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
|
【函数说明】该函数设置流 stream
的文件位置为给定的偏移offset
。
【函数参数】
stream
:文件指针变量。
offset
:相对 whence
的偏移量,以字节为单位,可正可负。
whence
:添加偏移 offset 的位置。
点击查看 whence 参数
常量 | 描述 |
SEEK_SET | 文件的开头 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件的末尾 |
【返回值】 返回值是一个int
类型,成功时返回0
,出错时返回EOF
。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5
| #include <stdio.h>
fseek(fp, 3, SEEK_SET);
|
【注意事项】
(1)追加模式(如a
模式)打开的文件 fseek
无效。
(2)只适用2G
以下的文件。
2.3 rewind()
在 linux 下可以使用 man 3 rewind 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
void rewind(FILE *stream);
|
【函数说明】该函数将流定位到文件开始位置。
【函数参数】
【返回值】 none
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5
| #include <stdio.h>
rewind(fp);
|
【注意事项】
(1)rewind(fp)
; 相当于 fseek(fp,0,SEEK_SET);
(2)只适用2G
以下的文件。
2.4 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
#include <stdio.h>
void test_ftell(); void test_fseek(); void test_rewind();
int main(int argc,char*argv[]) { test_fseek(); return 0; }
void test_ftell() { FILE * fp; int rec; fp = fopen("02fposition.txt", "r"); if(fp == NULL) { perror("fopen"); return; } rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); if(rec == -1) { perror("fgetc"); fclose(fp); return; } fclose(fp); }
void test_fseek() { FILE * fp; int rec; fp = fopen("02fposition.txt", "r"); if(fp == NULL) { perror("fopen"); return; } rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); fseek(fp, 3, SEEK_SET); printf("fseek: ftell(fp)=%ld\n", ftell(fp)); rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); if(rec == -1) { perror("fgetc"); fclose(fp); return; } fclose(fp); }
void test_rewind() { FILE * fp; int rec; fp = fopen("02fposition.txt", "r"); if(fp == NULL) { perror("fopen"); return; } rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); rewind(fp); printf("rewind: ftell(fp)=%ld\n", ftell(fp)); rec = fgetc(fp); printf("get char:%c ftell(fp)=%ld\n", rec, ftell(fp)); if(rec == -1) { perror("fgetc"); fclose(fp); return; } fclose(fp); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
3. 流的错误判断
很多对流进行操作的函数在失败或者到达文件末尾的时候,都可能会返回EOF
,那怎么区分呢?可以使用下边两个函数进行判断:
1 2 3 4
| #include <stdio.h>
int ferror(FILE *stream); int feof(FILE *stream);
|
四、格式化输入输出
1. 格式化输出
格式化输出就是将数据按照一定的格式输出到文件或者字符串。
1.1 fprintf()
在 linux 下可以使用 man 3 fprintf 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fprintf(FILE *stream, const char *format, ...);
|
【函数说明】该函数格式化写入数据到文件。
【函数参数】
stream
:文件指针变量。
format
:格式化字符串,与printf
一致,format
标签属性是
1
| %[flags][width][.precision][length]specifier
|
【返回值】返回值是int
类型,成功时返回输出的字符个数;出错时返回EOF
。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8
| #include <stdio.h>
FILE * fp; size_t ret; fp = fopen("file_name", "w"); ret = fprintf(fp, "%d-%d-%d", 2022, 5, 4);
|
【注意事项】 如果将 fp
设置为 stdout
,那么 fprintf()
函数将会向显示器输出内容,与 printf
的作用相同。
1.2 sprintf()
在 linux 下可以使用 man 3 sprintf命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int sprintf(char *str, const char *format, ...);
|
【函数说明】该函数向指定的字符串中格式化写入数据。
【函数参数】
str
:指向一个字符数组的指针,该数组存储了 C
字符串。。
format
:格式化字符串,与printf
一致,format
标签属性是:
1
| %[flags][width][.precision][length]specifier
|
【返回值】返回值是int
类型,如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符,如果失败,则返回EOF
。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6
| #include <stdio.h>
char buff[100]= { 0 }; sprintf(buff,"%d-%d-%d", 2022, 5, 4);
|
【注意事项】 none
1.3 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
#include <stdio.h> #include <stdlib.h>
void test_sprintf(); void test_fprintf();
int main(int argc,char*argv[]) { test_sprintf(); return 0; }
void test_fprintf() { FILE * fp; size_t ret; fp = fopen("03fprintf_sprintf.txt", "w"); if(fp == NULL) { perror("fopen"); return; } ret = fprintf(fp, "%d-%d-%d", 2022, 5, 4); if(ret == -1) { perror("fwrite"); fclose(fp); return; } else { printf("write struct student success!\n"); } }
void test_sprintf() { char buff[100]= { 0 }; sprintf(buff,"%d-%d-%d", 2022, 5, 4); printf("%s\n", buff); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
2. 格式化输入
格式化输入就是按照一定的格式从文件或者字符串读取指定的格式数据。
2.1 fscanf()
在 linux 下可以使用 man 3 fscanf 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int fscanf(FILE *stream, const char *format, ...);
|
【函数说明】该函数从流stream
读取格式化输入,即从文件格式化读取数据。
【函数参数】
stream
:文件指针变量。
format
:格式化字符串,与scanf
一致,format
标签属性是:
1
| %[flags][width][.precision][length]specifier
|
【返回值】返回值是int
类型,如果成功,该函数返回成功匹配和赋值的个数,如果到达文件末尾或发生读错误,则返回 EOF
。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8
| #include <stdio.h>
FILE * fp; int year, month, day; fp = fopen("file_name", "r"); fscanf(fp,"%d-%d-%d",&year, &month, &day);
|
【注意事项】如果将 fp
设置为 stdin
,那么 fscanf()
函数将会从键盘读取数据,与 scanf
的作用相同。
2.2 sscanf()
在 linux 下可以使用 man 3 sscanf 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <stdio.h>
int sscanf(const char *str, const char *format, ...);
|
【函数说明】该函数从字符串读取格式化输入。
【函数参数】
str
:是格式化输入数据的来源。
format
:格式化字符串,与scanf
一致,format
标签属性是:
1
| %[flags][width][.precision][length]specifier
|
【返回值】返回值是int
类型,如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF
。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7
| #include <stdio.h>
char buff[100] = "2022-5-4"; int syear, smonth, sday; sscanf(buff,"%d-%d-%d",&syear, &smonth, &sday);
|
【注意事项】 none
2.3 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
#include <stdio.h> #include <stdlib.h>
void test_sscanf(); void test_fscanf();
int main(int argc,char*argv[]) { test_fscanf(); return 0; }
void test_sscanf() { int syear; int smonth; int sday;
char buff[100] = "2022-5-4";
sscanf(buff,"%d-%d-%d",&syear, &smonth, &sday);
printf("%s\n", buff); }
void test_fscanf() { FILE * fp;
int year; int month; int day;
fp = fopen("04fscanf_sscanf.txt", "r"); if(fp == NULL) { perror("fopen"); return; } fscanf(fp,"%d-%d-%d",&year, &month, &day);
printf("%d,%d,%d\n", year, month, day);
fclose(fp); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|