stdio : 标准IO
(1) 流(stream)和文件(file)
流和文件 在Turbo C2.0中是有区别的, Turbo C2.0 为编程者和被访问的设备之间提供了一层抽象的东西, 称之为"流", 而将具体的实际设备叫做文件。流是一个逻辑设备, 具有相同的行为。因此, 用来进行磁盘文件写的函数也同样可以用来进行打印机的写入。在Turbo C2.0中有两种性质的流: 文字流( text stream)和二进制(binary stream)。对磁盘来说就是文本文件和二进制文件。本软件为了便于让读者易理解Turbo C2.0语言而没有对流和文件作特别区分。
(2) 文件指针FILE
实际上FILE是一个新的数据类型。它是Turbo C2.0的基本数据类型的集合, 称之为结构指针。有关结构的概念将在第四节中详细介绍, 这里只要将FILE理解为一个包括了文件管理有关信息的数据结构, 即在打开文件时必须先定义一个文件指针。
(3) 以后介绍的函数调用格式将直接写出形式参数的数据类型和函数返回值的数据类型。例如: 上面打开文件的函数, 返回一个文件指针, 其中形式参数有两个, 均为字符型变量(字符串数组或字符串指针)。本软件不再对函数的调用格式作详细说明。
fopen();
功能: 打开文件
函数原型: FILE *fopen(const char *path, const char *mode);
参数说明: 第一个形式参数表示文件名, 可以包含路径和文件名两部分.如:
"B:TEST.DAT"
"C://TC//TEST.DAT"
如果将路径写成"C:/TC/TEST.DAT"是不正确的, 这一点要特别注意。
第二个形式参数表示打开文件的类型。关于文件类型的规定参见下表。
表 文件操作类型
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
字符 含义
────────────────────────────────────
"r" 以只读方式打开文件,该文件必须存在。
"r+" 以读/写方式打开文件,该文件必须存在。
"rb+" 以读/写方式打开一个二进制文件,只允许读/写数据。
"rt+" 以读/写方式打开一个文本文件,允许读和写。
"w" 打开只写文件,若文件存在则长度清为 0,即该文件内容消失,若不存在则创建该文件。
"w+" 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
"a" 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留(EOF 符保留)。
"a+" 以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的 EOF 符不保留)。
"wb" 以只写方式打开或新建一个二进制文件,只允许写数据。
"wb+" 以读/写方式打开或建立一个二进制文件,允许读和写。
"wt+" 以读/写方式打开或建立一个文本文件,允许读写。
"at+" 以读/写方式打开一个文本文件,允许读或在文本末追加数据。
"ab+" 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
返回值: 文件顺利打开后,指向该流的文件指针就会被返回.如果文件打开失败则返回 NULL,并把错误代码存在 errno 中
打开方式总结:各种打开方式主要有三个方面的区别
1、打开是否为二进制文件,用“b”标识。
2、读写的方式,有以下几种:只读、只写、读写、追加只写、追加读写这几种方式。
3、对文件是否必 须存在、以及存在时是清空还是追加会有不同的响应。具体判断如下图。
╭ 是 ╭ 清空
文件是否必须存在 ┤ ╭ 存在 ┤
╰ 否 ┤ ╰ 追加
╰ 不存在 ─ 新建
fclose();
功能: 关闭fopen打开的文件
头文件: #include <stdio.h>
函数原型: int fclose(FILE *stream);
返回值: 如果流成功关闭,fclose 返回 0,否则返回EOF(-1).(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF.)
注意
在文件操作时,需要注意以下几点问题:
1、在定义文件指针时,要将文件指针指向空;如 FILE *fp = NULL;
2、文件操作完成后,需要将文件关闭,一定要注意,否则会造成文件所占用内存泄露和在下次访问文件时出现问题。
3、文件关闭后,需要将文件指针指向空,这样做会防止出现游离指针,而对整个工程造成不必要的麻烦;如:fp = NULL;
perror();
功能: 用来将上一个函数发生错误的原因输出到标准设备(stderr)。
头文件: #include <stdio.h>
函数原型: void perror(const char *s);
strerror();
功能: 获取系统错误信息或打印用户程序错误信息。
头文件: #include <string.h>
函数原型: char *strerror(int errnum);
例:文件的打开与关闭
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5
6 int main()
7 {
8 FILE *fp = NULL;
9 fp = fopen("tmp","r+");
10 if(fp == NULL)
11 {
12 perror("tmp");
13 fprintf(stderr,"tmp: %s\n",strerror(errno));
14 exit(1);
15 }
16 puts("OK!");
17 fclose(fp);
18 fp = NULL;
19 return 0;
20 }
运行结果:
[root@Yelong io]# gcc fopen.c
[root@Yelong io]# ./a.out tmp
OK!
fgetc();
功能: 从文件中读取字符。
头文件: #include <stdio.h>
函数原型: int fgetc(FILE *stream);
返回值: 返回所读取的一个字节。如果读到文件末尾或者读取出错时返回EOF。
fputc();
功能: 将字符写到文件中。
头文件: #include <stdio.h>
函数原型: int fputc(int c, FILE *stream);
返回值: 在正常调用情况下,函数返回写入文件的字符的ASCII码值,出错时,返回EOF(-1)。当正确写入一个字符或一个字节的数据后,文件内部写指针会自动后移一个字节的位置。EOF是在头文件 stdio.h中定义的宏。
例:用fgetc()和fputc()实现文件的复制
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc,char **argv)
5 {
6 int ch;
7
8 FILE *fpr = NULL;
9 FILE *fpw = NULL;
10
11 if(argc < 3)
12 {
13 fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
14 exit(1);
15 }
16
17 fpr = fopen(argv[1],"r");
18 if(fpr == NULL)
19 {
20 perror("fpr");
21 exit(1);
22 }
23
24 fpw = fopen(argv[2],"w");
25 if(fpw == NULL)
26 {
27 fclose(fpr);
28 perror("fpw");
29 exit(1);
30 }
31
32 while(1)
33 {
34 ch = fgetc(fpr);
35 if(ch == EOF)
36 break;
37 fputc(ch,fpw);
38
39 }
40
41 fclose(fpw);
42 fclose(fpr);
43
44 return 0;
45 }
运行结果:
[root@Yelong io]# gcc mycpoy.c
[root@Yelong io]# ./a.out tmp hh
[root@Yelong io]# diff tmp hh
fgets();
功能: 从文件中读取字符串
头文件: #include <stdio.h>
函数原型: char *fgets(char *s, int size, FILE *stream);
参数说明: *s 字符型指针,指向用来存储所得数据的地址。
size 整型数据,指明存储数据的大小。
*stream 文件结构体指针,将要读取的文件流。
返回值: 1.成功,则返回第一个参数buf;
2.在读字符时遇到end-of-file,则eof指示器被设置,如果还没读入任何字符就遇到这种情况,则buf保持原来的内容,返回NULL;
3.如果发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变.
fputs();
功能: 向指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)
头文件: #include <stdio.h>
函数原型: int fputs(const char *s, FILE *stream);
参数说明: *s s是字符型指针,可以是字符串常量,或者存放字符串的数组首地址。
返回值: 返回值为非负整数;否则返回EOF(符号常量,其值为-1)。
例:用fgets()和fputs()实现文件的复制
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define SIZE 1024
5
6 int main(int argc,char **argv)
7 {
8 FILE *fpr = NULL;
9 FILE *fpw = NULL;
10
11 char buf[SIZE];
12
13
14 if(argc < 3)
15 {
16 fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
17 exit(1);
18 }
19
20 fpr = fopen(argv[1],"r");
21 if(fpr == NULL)
22 {
23 perror("fpr");
24 exit(1);
25 }
26
27 fpw = fopen(argv[2],"w");
28 if(fpw == NULL)
29 {
30 fclose(fpr);
31 perror("fpw");
32 exit(1);
33 }
34
35 while(fgets(buf,SIZE,fpr) != NULL)
36 fputs(buf,fpw);
37
38 fclose(fpw);
39 fclose(fpr);
40
41 return 0;
42 }
运行结果:
[root@Yelong io]# gcc mycpoy.c
[root@Yelong io]# ./a.out tmp mm
[root@Yelong io]# diff tmp mm
fread();
功能: 从文件流中读数据,最多读取nmemb个项,每个项size个字节
头文件: #include <stdio.h>
函数原型: size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数说明: *ptr 用于接收数据的内存地址
size 要读的每个数据项的字节数,单位是字节
nmemb 要读nmemb个数据项,每个数据项size个字节.
*stream 文件流
返回值: 返回真实读取的项数,若大于nmemb则意味着产生了错误。另外,产生错误后,文件位置指示器是无法确定的。若其他stream或buffer为空指针,或在unicode模式中写入的字节数为奇数,此函数设置errno为EINVAL以及返回0.
fwrite();
功能: 向文件写入一个数据块
头文件: #include <stdio.h>
函数原型: size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值: 返回实际写入的数据块数目
例:用fread()和fwrite()实现文件的复制
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define SIZE 1024
5
6 int main(int argc,char **argv)
7 {
8 FILE *fpr = NULL;
9 FILE *fpw = NULL;
10
11 char buf[SIZE];
12
13 int n = 0;
14
15
16 if(argc < 3)
17 {
18 fprintf(stderr,"Usage:%s <src_file> <dest_file>\n",argv[0]);
19 exit(1);
20 }
21
22 fpr = fopen(argv[1],"r");
23 if(fpr == NULL)
24 {
25 perror("fpr");
26 exit(1);
27 }
28
29 fpw = fopen(argv[2],"w");
30 if(fpw == NULL)
31 {
32 fclose(fpr);
33 perror("fpw");
34 exit(1);
35 }
36
37 while((n = fread(buf,1,SIZE,fpr)) > 0)
38 fwrite(buf,1,n,fpw);
39
40 fclose(fpw);
41 fclose(fpr);
42
43 return 0;
44 }
运行结果:
[root@Yelong io]# gcc mycp
oy.c
[root@Yelong io]# ./a.out tmp mm
[root@Yelong io]# diff tmp mm
printf();
功能: 向标准输出设备按规定格式输出信息
头文件: #include <stdio.h>
函数原型: int printf(const char *format, ...);
fprintf();
功能: 格式化输出到一个流/文件中
头文件: #include <stdio.h>
函数原型: int fprintf(FILE *stream, const char *format, ...);
参数说明: *stream 文件指针
*format 输出格式
scanf();
功能: 按用户指定的格式从键盘上把数据输入到指定的变量之中。
头文件: #include <stdio.h>
函数原型: int scanf(const char *format, ...);
返回值: 返回成功读入的数据项数,读入数据时遇到了“文件结束”则返回EOF。
fseek();
功能: 设置文件指针stream的位置
头文件: #include <stdio.h>
函数原型: int fseek(FILE *stream, long offset, int whence);
参数说明: *stream 文件
offset (指针偏移量)个字节的位置
whence 文件指针偏移位置(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))
返回值: 成功,返回0,失败返回-1,并设置error的值,可以用perror()函数输出错误。
ftell();
功能: 用于得到文件位置指针当前位置相对于文件首的偏移字节数,使用fseek函数后再调用函数ftell()就能非常容易地确定文件的当前位置。
头文件: #include <stdio.h>
函数原型: long ftell(FILE *stream);
约束条件: 因为ftell返回long型,根据long型的取值范围-231~231-1(-2147483648~2147483647),故对大于2.1G的文件进行操作时出错。
例:利用fseek()和ftell()实现获取文件字符个数
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc,char **argv)
5 {
6 FILE *fp = NULL;
7 int count = 0;
8
9 if(argc < 2)
10 {
11 printf("Usage...\n");
12 exit(1);
13 }
14
15 fp = fopen(argv[1],"r");
16
17 fseek(fp,0,SEEK_END);
18 ftell(fp);
19
20 printf("%ld\n",ftell(fp));
21
22 fclose(fp);
23
24 return 0;
25 }
运行结果:
[root@Yelong io]# gcc flen.c
[root@Yelong io]# ./a.out tmp
135
[root@Yelong io]# ll tmp
-rw-r--r-- 1 root root 135 7月 18 13:07 tmp
rewind();
功能: 将文件内部的位置指针重新指向一个流(数据流/文件)的开头.
头文件: #include <stdio.h>
函数原型: void rewind(FILE *stream);
ffllush();
功能: 刷新缓冲区
头文件: #include <stdio.h>
函数原型: int fflush(FILE *stream);
返回值: 如果成功刷新,fflush返回0。指定的流没有缓冲区或者只读打开时也返回0值。返回EOF指出一个错误。
缓冲区的作用:大多数情况下是好事,合并系统调用
行缓冲: 换行时候刷新,满了的时候刷新,强制刷新(标准输出是这样的,因为是终端设备)
全缓冲: 满了的时候刷新,强制刷新(默认,只要不是终端设备)
无缓冲: 如 stderr,需要立即输出的内容
setvbuf();
功能: 把缓冲区与流相关
头文件: #include <stdio.h>
函数原型: int setvbuf(FILE *stream, char *buf, int mode, size_t size);
参数说明: mode 缓冲区的类型
_IONBF unbuffered(无缓冲)
_IOLBF line buffered(行缓冲)
_IOFBF fully buffered(全缓冲)
size 缓冲区内字节的数量。
getline();
功能: 读取文件中一整行
头文件: #include <stdio.h>
函数原型: ssize_t getline(char **lineptr, size_t *n, FILE *stream);
参数说明: lineptr: 指向存放该行字符的指针,如果是NULL,则有系统帮助malloc,请在使用完成后free释放。
n: 如果是由系统malloc的指针,请填0
返回值: 成功:返回读取的字节数。失败:返回-1。
例:获取没一行的字符个数。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int main(int argc,char **argv)
6 {
7 FILE *fp = NULL;
8
9 char *linebuf = NULL;
10 size_t linesize = 0;
11
12 if(argc < 2)
13 {
14 printf("Usage...\n");
15 exit(1);
16 }
17
18 fp = fopen(argv[1],"r");
19 if(fp == NULL)
20 {
21 perror("fopen");
22 exit(1);
23 }
24
25 while(1)
26 {
27 if(getline(&linebuf,&linesize,fp) < 0)
28 break;
29 printf("%ld\n",strlen(linebuf));
30 }31 fclose(fp);
32 fp = NULL;
33 return 0;
34 }
运行结果:
[root@Yelong io]# gcc getline.c
[root@Yelong io]# ./a.out mm
19
11
9
13
atoi();
功能: 把字符串转换成整型数
头文件: #include <stdlib.h>
函数原型: int atoi(const char *nptr);
例:将字符串转换成数字
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 char ch[] = "123456";
7 printf("%d\n",atoi(ch));
8 return 0;
9
10 }
运行结果:
[root@Yelong io]# ./a.out
123456
临时文件:
1.如何在不冲突的情况下创建临时文件.
2.及时销毁临时文件.成功:返回读取的字节数。
tmpnam();
功能: 创建一个临时的文件名
头文件: #include <stdlib.h>
函数原型: char *tmpnam(char *s);
tmpfile();
功能: 以读写的方式创建一个临时的二进制文件
头文件: #include <stdlib.h>
函数原型: FILE *tmpfile(void);
例:创建一个临时文件
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 FILE *temfp;
7 temfp = tmpfile();
8 if(temfp)
9 {
10 printf("tmpfile created\n");
11 }
12 else
13 {
14 printf("tmpfile not created\n");
15 exit(1);
16 }
17 return 0;
18 }
运行结果:
[root@Yelong io]# gcc tmpfile.c
[root@Yelong io]# ./a.out
tmpfile created