在上一篇Linux编程学习笔记 | Linux IO学习[1] - 文件IO中,我总结了Linux下的文件IO。文件IO是偏底层的IO操做,在平时的平常工做中,使用文件IO的频率仍是比较低的。咱们天天使用的 printf()
就不是文件IO,而是另外一类IO - 标准IO。在这篇文章中,我将介绍Linux下的标准IO并经过实例来讲明如何使用它们。linux
要使用标准IO库,须要包含头文件 <stdio.h>
。该库为用户建立了一个链接底层系统调用的通用接口,它是ANSI C标准制定的库,所以具备可移植性(文件IO是基于Unix的POSIX标准,不可移植到Windows)。同文件IO相似,它须要先打开一个文件以创建一个访问途径,文件IO的访问途径是经过文件描述符,标准IO的访问途径是流(stream),它被实现为指向结构FILE的指针。git
同文件IO相似,在程序启动时也有3个默认的文件流:github
标准流 | 变量或宏 | 说明 |
---|---|---|
0 | stdin | 标准输入 |
1 | stdout | 标准输出 |
2 | stderr | 标准错误输出 |
标准IO的函数相对文件IO来讲要多不少,我这里主要介绍13个标准IO函数。编程
fopen()
和文件IO中的 open()
相似,用于打开文件流,函数说明以下:segmentfault
FILE *fopen(const char *restrict pathname, const char *restrict mode); args: const char *restrict pathname: 文件的路径 const char *restrict mode : 文件打开的模式 return: 返回指向文件的指针,指针不为NULL是成功,指针为NULL是失败
文件打开的模式有如下6种:函数
1. "r" or "rb" : 以只读形式打开文(文件必须存在) 2. "w" or "wb" : 以写方式打开文件并将文件长度截为0或建立一个供写的文件 3. "a" or "ab" : 以写方式打开文件并将内容写到文件末或建立一个文件 4. "r+" or "rb+" or "r+b" : 以更新的方式(读/写)打开文件(文件必须存在) 5. "w+" or "wb+" or "w+b" : 以更新的方式(读/写)打开文件并将文件长度截为0或建立一个文件 6. "a+" or "ab+" or "a+b" : 以更新的方式(读/写)打开文件并将更新内容写到文件末或建立一个文件
fopen()
和 open()
不一样, fopen()
并不能在建立文件时改变其访问权限。学习
fclose()
和文件IO中的 close()
相似,用于关闭文件流,函数说明以下:指针
int fclose(FILE *stream); args: FILE *stream: 指向被关闭文件的指针 return: 关闭文件成功返回0,关闭文件失败返回而EOF
咱们来看第一个例子,文件的打开和关闭:rest
#include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; //fp = fopen("stdio.log", "r+"); fp = fopen("stdio.log", "w+"); if (fp == NULL) { printf("File create fail...\n"); return -1; } else { printf("File create success...\n"); } fclose(fp); return 0; }
运行结果:
新建一个叫 stdio.log
的文件,并输出File create success...
若是咱们注释掉第8行,去掉第7行的注释,那么将输出 File create fail...
。code
fseek()
和文件IO中的 lseek()
相似,用于修改文件流读写的偏移量,函数说明以下:
int fseek(FILE *stream, long offset, int whence); args: FILE *stream: 指向文件的文件指针 long offset : 偏移量移动的距离 int whence : 偏移量的基址 - SEEK_SET 文件开始处 - SEEK_CUR 文件当前位置 - SEEK_END 文件结束处 return: 修改偏移量成功返回0, 修改偏移量失败返回-1
当 whence
是 SEEK_CUR
或 SEEK_END
时, offset
可正负。
fwrite()
和文件IO中的 write()
相似,函数说明以下:
size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); args: const void *restrict ptr: 写入数据在内存空间存储的地址 size_t size : 单个元素的大小 size_t nitems : 写入数据元素的个数 FILE *restrict stream : 指向写入文件的文件指针 return: 实际写入的元素个数,非负整数是成功,-1是失败
fputs()
将字符串(不包括 `\0` )写入文件,函数说明以下:
int fputs(const char *restrict s, FILE *restrict stream); args: const char *restrict s: 写入的字符串 FILE *restrict stream : 指向写入文件的文件指针 return: 写入文件的状态,非负整数是成功,EOF是失败
puts()
将字符串(不包括 `\0` )写入 stdout
,并在行末添加一个换行符,函数说明以下:
int puts(const char *s); args: const char *s: 写入的字符串 return: 写出到stdio的状态,非负整数是成功,EOF是失败
fputc()
将一个字符写入文件,函数说明以下:
int fputc(int c, FILE *stream); args: int char : 要写入的字符 FILE *stream: 指向写入文件的文件指针 return: 若是没有错误,返回写入的字符,不然返回EOF
putc()
和 fputc()
基本同样,只不过 putc()
是用宏实现而 fputc
是用函数实现。
int putc(int c, FILE *stream); args: int c : 要写入的字符 FILE *stream: 指向写入文件的文件指针 return: 若是没有错误,返回写入的字符,不然返回EOF
咱们经过例子来看看上面这几个函数的使用方法:
#include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; fp = fopen("stdio.log", "w+"); if (fp == NULL) { printf("File create fail...\n"); return -1; } else { printf("File create success...\n"); } /* fwrite() function */ char buffer_1[] = "This is fwrite DEMO..."; size_t wr_size = 0; wr_size = fwrite(buffer_1, 1, sizeof(buffer_1), fp); printf("wr_size = %d\n", wr_size); /* fputs() function */ char buffer_2[] = "\nThis is fputs DEMO...\n"; int fputs_status = 0; fputs_status = fputs(buffer_2, fp); printf("fputs_status = %d\n", wr_size); /* puts function */ char buffer_3[] = "This is puts DEMO..."; puts(buffer_3); /* fputc function */ char buffer_4[] = "This is fputc DEMO...\n"; int ret; for (int i = 0; i < sizeof(buffer_4); i++) { ret = fputc(buffer_4[i], fp); printf("%c", ret); } /* putc function */ char buffer_5[] = "This is putc DEMO...\n"; for (int i = 0; i < sizeof(buffer_5); i++) { ret = fputc(buffer_5[i], fp); printf("%c", ret); } fclose(fp); return 0; }
运行结果:
在生成的 std_io.log
文件中会输出如下内容,其中 @^
就是 `\0`
This is fwrite DEMO...^@ This is fputs DEMO... This is fputc DEMO... ^@This is putc DEMO... ^@
注意 fputs
函数并无输出 `\0` 。在终端会输出:
File create success... wr_size = 23 fputs_status = 23 This is puts DEMO... This is fputc DEMO... This is putc DEMO...
puts
函数直接将字符串输出到 stdio
。
fread()
和文件IO中的 read()
相似,函数说明以下:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); args: void *ptr : 读取数据存储的内存空间的地址 size_t size : 单个元素的大小 size_t nmemb: 读取数据元素的个数 FILE *stream: 指向读取文件的文件指针 return: 实际读取的元素个数,非负整数是成功,-1是失败
fgets()
用于读取文件中的字符串,而后将其存储到内存空间,函数说明以下:
char *fgets(char *restrict s, int n, FILE *restrict stream); args: char *restrict s : 读取后字符串存储的内存空间地址 int n : 最大读取字符数 FILE *restrict stream: 指向读取文件的文件指针 return: 若是读取没有错误且没有读入EOF,返回写入的字符串 若是读取没有错误但读入EOF,返回NULL指针 若是读取出现错误,返回NULL指针
这里须要注意下该函数将在什么时候中止读取:
若是读取的字符数量达到 n - 1
,或读取了换行符,或读取了字符串结束符,只要有一个知足则该函数会中止继续读取。
gets()
从 stdin
中读取字符串并存放在内存中,函数说明以下:
char *gets(char *s); args: char *s: 读取后字符串存储的内存空间地址 return: 若是读取没有错误且没有读入EOF,返回读取的字符串 若是读取没有错误但读入EOF,返回NULL指针 若是读取出现错误,返回NULL指针
读取操做将在读入换行符或EOF后结束。
fgetc()
从一个文件读取一个字符,函数说明以下:
int fgetc(FILE *stream); args: FILE *stream: 指向读取文件的文件指针 return: 若是读取没有错误且没有读入EOF,返回读取的字符 若是读取没有错误但读入EOF,返回EOF 若是读取出现错误,返回EOF
getc()
和 fgetc()
基本同样,只不过 getc()
是用宏实现而 fgetc()
是用函数实现。
int getc(FILE *stream); args: FILE *stream: 指向读取文件的文件指针 return: 若是读取没有错误且没有读入EOF,返回读取的字符 若是读取没有错误但读入EOF,返回EOF 若是读取出现错误,返回EOF
说完了读操做的函数,咱们也经过一个例子来看看如何使用这些函数:
#include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; fp = fopen("stdio.log", "r+"); if (fp == NULL) { printf("File open fail...\n"); return -1; } else { printf("File open success...\n"); } /* fread() function */ char buffer_1[50]; size_t rd_size = 0; rd_size = fread(buffer_1, 1, 24, fp); printf("rd_size = %d\n", rd_size); printf("fread get: %s\n", buffer_1); /* fgets() function */ char buffer_2[50]; char *fgets_status; fgets_status = fgets(buffer_2, 23, fp); printf("fgets_status = %s", fgets_status); printf("fgets get: %s", buffer_2); /* gets function */ char buffer_3[50]; gets(buffer_3); printf("gets get: %s", buffer_3); /* fgetc function */ int ret; while ((ret = fgetc(fp)) != EOF) printf("%c", ret); fclose(fp); return 0; }
在编译过程当中,编译器会警告:
warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration] gets(buffer_3); ^~~~ /tmp/cc3YWk3i.o: In function `main': fread_get.c:(.text+0x11d): warning: the `gets' function is dangerous and should not be used.
由于 gets()
函数过于危险,在C11中的 <stdio.h>
已经再也不包含 gets()
函数,所以会出现这个警告。
运行结果:
要读取的文件是以前写函数生成的 stdio.log
文件,终端输出以下。
File open success... rd_size = 24 fread get: This is fwrite DEMO... fgets_status = This is fputs DEMO... fgets get: This is fputs DEMO... test gets get: testThis is fputc DEMO... This is putc DEMO...
这篇文章主要介绍了如何使用几个基本的标准IO函数对文件进行操做,相对于文件IO而言,标准IO使用更方便,而且支持跨平台使用。同时在传输大文件时,标准IO也不比文件IO慢。文中出现的代码均可在个人github上找到。
若是以为本文对你有帮助,请多多点赞支持,谢谢!