Linux C语言学习(二) 标准IO库 stdio.h
Linux驱动学习(二) 标准IO库 stdio.h
其实输入与输出对于不管什么系统的设计都是异常重要的,比如设计 C 接口函数,首先要设计好输入参数、输出参数和返回值,接下来才能开始设计具体的实现过程。C 语言标准库提供的接口功能很有限,不像 Python 库。
文件FIFE指针
在调用open( )时,返回文件描述字fd,然后通过fd来对文件进行后续的IO操作。在标准I/O库中,I/O操作则是通过( FIFE *) 指针展开的。FILE 是一个结构体数据类型,它包含了标准 I/O 库函数为管理文件所需要的所有信息,包括用于实际I/O 的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。而想FIFE这样的对象结构体,我们一般称作句柄 。
Standard Streams
贴上最新版GUN/C 的libc文档链接点击此处下载
在文档P269 Input/Output on Streams中。stdio中定义了标准输入(stdin )、标准输出(stdout)、标准错误(stderr)三个宏。用户通过标准输入设备(例如键盘鼠标)与系统进行交互,进程将从标准输入(stdin)文件中得到输入数据,将正常输出数据(譬如程序中 printf 打印输出的字符串)输出到标准输出(stdout)文件,而将错误信息(譬如函数调用报错打印的信息)输出到标准错误(stderr)文件。而标准输出及标准错误文件也可能会输出到标准输出设备上,例如屏幕等等。
每个进程启动之后都会默认打开标准输入、标准输出以及标准错误,得到三个文件描述符,即 0、1、2,其中 0 代表标准输入、1 代表标准输出、2 代表标准错误;在应用编程中可以使用宏 STDIN_FILENO 、STDOUT_FILENO 和 STDERR_FILENO 分别代表 0、1、2,这些宏定义在 unistd.h 头文件中:
#define STDIN_FILENO 0This macro has value 0, which is the file descriptor for standard input.#define STDOUT_FILENO 1This macro has value 1, which is the file descriptor for standard output.#define STDERR_FILENO 2This macro has value 2, which is the file descriptor for standard error output
而0、1、2三个数字都是文件描述字fd,只能使用read、write、open等api进行I/O操作,自然不可以使用标准IO库进行文件操作。所以,在stdio.h这个标准IO库中,也相应的定义了标准输入、标准输出、标准错误的宏:
/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
/* C89/C99 say they're macros. Make them happy. */ // ......好好好,你说宏那就宏呗,开心就好
#define stdin stdin
#define stdout stdout
#define stderr stderr
fopen( )
FILE * fopen (const char *filename, const char *opentype)
libc文档P270页:
rOpen an existing file for reading only. 只读wOpen the file for writing only. If the file already exists, it is truncated to zero length. Otherwise a new file is created. 只写,如果无此文件,就创建。aOpen a file for append access; that is, writing at the end of file only. Ifthe file already exists, its initial contents are unchanged and output to the stream is appended to the end of the file. Otherwise, a new, empty file is created. 只读方法打开,在末尾追加r+Open an existing file for both reading and writing. The initial contents of the file are unchanged and the initial file position is at the beginning of the file. 允许读和写,文件必须存在。w+Open a file for both reading and writing. If the file already exists, it is truncated to zero length. Otherwise, a new file is created. 允许读和写,文件不存在则创建,存在则覆盖。a+Open or create file for both reading and appending. If the file exists, its initial contents are unchanged. Otherwise, a new file is created. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file. 允许读和追加,文件不存在则创建。
fclose(FIFE *)
关文件呗。
读写文件
在libc文档P290 Block Input/Output中,讲述了使用fwrite、fread进行文件读写。
文件读取
size_t fread (void *data, size_t size, size_t count, FILE *stream)
data :fread()将读取到的数据存放在参数 data 指向的缓冲区中;
size :fread()从文件读取 count 个数据项,每一个数据项的大小为 size 个字节,所以总共读取的数据大小为 count * size 个字节。
count :参数 nmemb 指定了读取数据项的个数。
stream :FILE 指针。
返回值 :调用成功时返回读取到的数据项的数目。
文件写入
size_t fwrite (const void *data, size_t size, size_t count, FILE *stream)
data :将参数 ptr 指向的缓冲区中的数据写入到文件中。
size :参数 size 指定了每个数据项的字节大小,与 fread()函数的 size 参数意义相同。
count :参数 count 指定了写入的数据项个数,与 fread()函数的 count 参数意义相同。
stream :FILE 指针。
返回值 :调用成功时返回写入的数据项的数目(数据项数目并不等于实际写入的字节数,除非参数 size等于 1);如果发生错误,则 fwrite()返回的值将小于参数 count(或者等于 0)。
贴上代码
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char buf[] = "Hello World!\n";
FILE *fp = NULL;
/* 打开文件 */
if (NULL == (fp = fopen("./test_file", "w"))) {
perror("fopen error");
exit(-1);
}
printf("文件打开成功!\n");
/* 写入数据 */
if (sizeof(buf) >
fwrite(buf, 1, sizeof(buf), fp)) {
printf("fwrite error\n");
fclose(fp);
exit(-1);
}
printf("数据写入成功!\n");
/* 关闭文件 */
fclose(fp);
exit(0);
}
IO格式化
无需多言,上代码,更多详见libc文档P293 Table of Output Conversions、Integer Conversions、Other Output Conversions、章节
ntf("%d\n", 5); // 打印整数 5
printf("-%10s-\n", "hello") // 设置显示宽度并左对齐:- hello-
printf("-%-10s-\n", "hello") // 设置显示宽度并右对齐:- hello-
printf("%#x\n", 0xff); // 0xff 不加#则显示ff
printf("%p\n", main); // 打印 main 函数首地址
printf("%%\n"); // 打印一个 %
int sscanf(const char *str, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
IO缓冲
在进行文件读写时,操作系统一般会从硬盘中读取到文件,然后将其放入内核缓冲区(kernel buffer cache)空间中,然后对缓冲区进行操作,意思就是使用write对文件进行操作时,并不是直接对硬盘进行操作,write操作与硬盘操作并不是同步的。若在此期间,其他进程也调用了这个文件,那将会造成混乱。内核会分配尽可能多的内核来作为文件 I/O 的内核缓冲区,但受限于物理内存的总量,如果系统可用的物理内存越多,那自然对应的内核缓冲区也就越大,操作越大的文件也要依赖于更大空间的内核缓冲。
全缓存。当填满标准I/O缓存后才执行I/O操作。磁盘上的文件通常是全缓存的。行缓存。当输入输出遇到新行符或缓存满时,才由标准I/O库执行实际I/O操作。stdin、stdout通常是行缓存的。无缓存。相当于read、write了。stderr通常是无缓存的,因为它必须尽快输出。
未完待补充