`

Linux系统编程学习笔记(二)C标准I/O库

阅读更多
标准I/O
Buffered I/O:
Buffered I/O可以减少系统调用的次数,提高性能。每次读一个block的整数倍可以提高效率。
1、Standard I/O:
C语言的标准IO库stdio,提供了跨平台的,user-buffering的方案。
2、文件指针:
标准I/O不直接操作文件描述符,而是使用文件指针来操作文件。
FILE *fp
打开的文件被称为流,输入流、输出流、输入/输出流
3、打开文件:
#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

mode描述了如何打开由path代表的文件:
r:打开文件,可读,流的位置在文件的开头
r+:打开文件,可读写,流的位置在文件的开头
w: 打开文件,可写,如果存在,清空。不存在创建,流的位置在文件的开头
w+:打开文件,可读写,如果存在,则清空,如果不存在则创建,流的位置在文件的开头
a:append模式,可写,如果不存在创建。流的位置在文件的末尾。
a+:append模式,可读写,如果不存在创建。流的位置在文件的末尾。
例子:
File *fp;

fp = fopen("/etc/manifest","r");
if(! fp )
	/* error */

4、通过文件 描述符打开:
#include <stdio.h>

FILE *fdopen(int fd, const char *mode);

mode的含义和fopen一样,除了w、w+不会清空文件。
例子:
FILE *fp;
int fd;

fd = open("/home/kidd/map.txt",O_RDONLY);
if(fd == -1)
  /* error */
fp = fdopen(fd,"r");
if(!fp)
 /* error */

一个可读的fd,如果fdopen设置mode是w,会如何?二者不一致会返回NULL,并设置
errno为EIVAL.

5、关闭流:
fclose可以关闭文件。
#include <stdio.h>

int fclose(FILE *fp);

buffer和没有写的数据首先被fushed。成功返回0,失败返回EOF。
6、关闭所有的流:
fcloseall关闭当前进程所有的流:
#define _GNU_SOURCE

#include<stdio.h>

int fcloseall(void);

总是返回0。
7、从流中读:
1)一次读一个字符:
fgetc:
#include <stdio.h>

int fgetc(FILE *fp);

返回读取字符转换成了int值,主要由于考虑文件结尾返回EOF,-1不在assci码范围。
int c;
while((c = fgetc(fp) != EOF){
	printf("%c\n",(char)c);
}

2)将字符压回流:
ungetc:
通过这个函数可以peek流中的字符,如果读超过了需要的字符,可以把
这个字符压回。
#include <stdio.h>

int ungetc(int c, FILE *fp);

成功返回c,失败返回EOF
3)读取一行:
fgets可以读取一行字符串:
#include <stdio.h>

char * fgets(char *str,int size, FILE *stream);

读取遇到换行或者EOF,成功返回str,失败返回NULL。
例子:
char buf[LINE_MAX];//LINE_MAX in <limits.h>du
if(!fgets(buf,LINE_MAX,fp)
	/* error */

4)读二进制数:
fread:
#include <stdio.h>

size_t fread(void *buf, size_t size, size_t nr, FILE *fp);

可以读取复杂的二进制数,比如c中的结构体。
读nr个数据,每一个大小为size字节。成功返回读取元素的个数,失败指示错误或者返回EOF,
但是如果不使用ferror()和feof()无法区分。
由于在不同机器的变量大小,对其,补齐,字节序不同,不具有跨机器性。
例子:
char buf[64];
size_t nr;

nr = fread(buf,sizeof(buf),1,fp);
if(nr == 0) 
	/* error */

8、写入流:
1)写入一个字符:
#include <stdio.h>

int fputc(int c, FILE *fp);

成功返回c,失败返回EOF。
if( fputc('p',fp) ) 
  /* error */

2)写入一个字符串:
fputs:
#include <stdio.h>

int fputs(const char *str, FILE *stream);

2)写入由\0结尾的字符串,成功返回非负数,失败返回EOF。
例子:
FILE *fp;

if(!(fp = fopen("journal.txt","a"))
  /* error */
if(fputs("The ship is made of wood.\n",fp) == EOF)
 /*error*/
if(fclose(fp) == EOF)
 /*error*/

3)写入二进制数据:
fwrtie可以将复杂的结构数据存储到文件中:
#include <stdio.h>

size_t fwrite(void *buf,size_t size, size_t nr, FILE *fp);

将右buf指向的数据写入文件fp中nr个元素,每一个元素的长度是size字节。
9、使用Buffered I/O 例子:
#include <stdio.h>

int main(void){
	FILE *in,*out;
	struct pirate{
		char name[100];
		unsigned long booty;
		unsigned int beard_len;
	}p,blackbeard = {"Edward Teach",950,48};
	
	out = fopen("data","w");

	if(! out ){
		perror("fopen");
		return 1;
	}

	if(!fwrite(&blackbeard,sizeof(struct pirate),1,out)){
		perror("fwrite");
		return 1;
	}

	if(fclose(out)){
		perror("fclose");
		return 1;
	}

	in = fopen("data","r");
	if( !in ){
		perror("fopen");
		return 1;
	}

	if(! fread(&p, sizeof(struct pirate),1,in)){
		perror("fread");
		return 1;
	}

	if(fclose(in)){
		perror("fclose");
		return 1;
	}

	printf("name=\"%s\" booty=%lu beard_len=%u\n",p.name,p.booty,p.beard_len);
	
	return 0;
}

10、Seeking a Stream
1)fseek和标准IO lseek类似:
#include <stdio.h>

int fseek(FILE *fp,long offset, int whence);

whence可以取:SEEK_SET、SEEK_CUR,SEEK_END,和lseek含义一样。
2)fsetpos:
#include <stdio.h>

int fsetpos(FILE *fp,fpos_t *pos);

和fseek将whence设置成SEEK_SET一样。
3)rewind:
将文件位置重置,相当于fseek(fp,0,SEEK_SET);
#include <stdio.h>

void rewind(FILE *fp);

rewind 没有返回值,可以通过errno来判断是否成功:
errno = 0;
rewind(stream);
if(errno)
  /* error */

11、获取当前文件流的位置:
1)ftell:
#include <stdio.h>

long ftell(FILE *stream);

成功返回位置,失败返回-1,errno被设置。
2)fgetpos:
#include <stdio.h>

int fgetpos(FILE *stream, fpos_t *pos);

成功返回0,并设置pos,失败返回-1。
12、flush a Stream:
fflush:
#include <stdio.h>

int fflush(FILE *fp);

所有由fp标示的未写入的数据写入内核的buffer中。
成功返回0,失败返回EOF,并设置errno
write都会写入用户的buffer中,fflush可以将用户buffer的数据,写入内核buffer中,
并不能保证写入磁盘。
13、错误和文件结尾:
一些标准的I/O比如fread,没有提供区分error和EOF的机制,所以检查所给的流确定遇到错误还是文件
结尾很有用。标准I/O提供了两个接口:
1)ferror:
#include <stdio.h>

int ferror(FILE *fp);

返回非0表示设置了错误,0表示没有。
2)feof
#include <stdio.h>

int feof(FILE *fp);

测试流是否设置了EOF,返回非零表示设置,0表示没有。
3)清除错误和EOF设置:
#include<stdio.h>

void clearerr(FILE *fp);

例子:
if(ferror(f))
	printf("Error on f!\n");
if(feof(f))
	printf("EOF on f!\n");
clearerr(f);

14、获得相关的文件描述符:
#include <stdio.h>

int fileno(FILE *fp);

成功返回相关的文件描述符,失败返回-1
混用标准I/O和IO系统调用并不是值得推荐的。
15、控制buffer:
a、标准I/O实现了三种用户Buffer:
1)Unbuffered:
没有缓存,数据直接交给内核。stderr默认使用这种方式。
2)Line-buffered:
buffer缓存一行,当遇到换行符则提交给内核。stdout默认使用这种方式。
3)Block-buffered
与文件相关的I/O默认都是Block-buffered。
b、设置流的buffer类型:
setvbuf:
#include <stdio.h>

int setvbuf(FILE *stream, char *buf, int mode, size_t size);

mode:
_IONBF: 没有buffer
_IOLBF: Line-buffered
_IOFBF: block-buffered/full buffered
除了_IONBF外,其他的两个,都需要用户提供一个size自己的buf。
提供的buffer在文件关闭的时候仍然要可见,否则显示的关闭操作会失败。
下面例子存在bug:
#include <stdio.h>

int main(void){
	char buf[BUFSIZ];
	
	setvbuf(stdout,buf,_IOFBF,BUFSIZ);
	printf("Arrr!\n");

	return 0;
}

程序退出的时候会隐式的关闭文件,导致失败。可以在上面程序return之前加上显示的close关闭stdout,或者
使用全局的buf。

16、格式化I/O:
1)使用可变参数族:
#include <stdio.h>

//正确返回输出的字节数,错误返回-1
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char * restrict format,...);

//调用者需要确保buf足够大,不会溢出,
int sprintf(char *restrict buf,const char * restrict format,...);
//显示指定了buf的大小,多出来的会被抛弃
int snprintf(char *restrict buf, size_t n, const char *restrict format,...);
//正确返回输出到数组buf中的字节数,错误返回-1。

2)使用va_list族:
va_list在<stdarg.h>中定义。
#include <stdio.h>
#include <stdarg.h>

int vprintf(const char *restrict format, va_list arg);
int vfprintf(FILE *restrict fp, const char * restrict format,va_list arg);
int vsprintf(char *restrict buf,const char * restrict format,va_list arg);
int vsnprintf(char *restrict buf, size_t n, const char *restrict format,va_list arg);

17、格式化输入:
1)使用可变参数族:
#include <stdio.h>

int scanf(const char *restrict format,...);
int fscanf(FILE * restrict fp, const char * restrict format,...);
int sscanf(const char *restrict buf, const char *restrict format,...);

2)使用va_list族
#include <stdio.h>
#include <stdarg.h>

int vscanf(const char *restrict format,va_list arg);
int vfscanf(FILE * restrict fp, const char * restrict format,va_list arg);
int vsscanf(const char *restrict buf, const char *restrict format,va_list arg);


参考:
1、《Linux system programming》
2、《Unix system programming》
3、《Advanced Programming in the Unix Environment》
0
1
分享到:
评论

相关推荐

    标准I/O库-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    标准I/O库-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    Linux系统编程学习笔记

    ### Linux系统编程学习笔记 #### 一、IO **1.1 标准I/O (stdio)** - **fopen/fclose**: `fopen` 用于打开或创建一个文件,并返回一个指向该文件的 `FILE *` 类型的指针。`fclose` 用于关闭由 `FILE *` 指向的文件...

    文件I/O基础-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    文件I/O基础-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    linux 系统编程 尚观 linux内核驱动开发 笔记

    【Linux 系统编程与内核驱动开发笔记】 在深入探讨Linux系统编程和内核驱动开发之前,我们首先要理解Linux操作系统的基本概念。Linux是一种自由、开放源码的类Unix操作系统,广泛应用于服务器、桌面环境以及各种...

    深入探究文件I/O-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    深入探究文件 I/O:深入了解了文件 I/O 中的一些细节,譬如文件的管理方式、 错误返回的处理、空洞文件、O_APPEND 和 O_TRUNC 标志、原子操作与竞争冒险等等

    学习《高级Linux环境编程》读书笔记(APUE读书笔记)

    5. 标准I/O库:这部分内容是关于C语言中标准I/O库的使用,包括文件流的概念,标准输入输出流stdin、stdout和stderr,标准I/O的缓冲机制,文件流的打开、读写、关闭以及定位操作。还介绍了一些格式化输入输出函数以及...

    linux编程学习笔记PDF资料下载.txt

    根据提供的文件信息,我们可以推断出这是一份关于Linux编程学习笔记的PDF资料。下面将对这份资料可能涉及的关键知识点进行详细的阐述。 ### Linux编程基础知识 #### 1. Linux操作系统概述 - **定义与特点**:Linux...

    LinuxUNIX系统编程手册

    8. **系统调用与库函数**:区别系统调用与库函数,理解系统调用接口(如syscalls.h头文件)和C语言标准库(如glibc)的关系。 9. **错误处理**:学会如何使用errno全局变量和perror()函数来识别和处理运行时错误。 ...

    UNIX系统编程学习笔记

    在进入UNIX系统编程的学习之前,我们首先需要理解UNIX的基本概念。UNIX是一种多用户、多任务的操作系统,由贝尔实验室在1960年代末开发。它以其简洁、强大的命令行接口和丰富的工具集而闻名,是许多现代操作系统设计...

    Linux C 系统编程

    Linux C系统编程是计算机科学领域中的一个重要主题,它涉及到操作系统层面的编程,主要使用C语言在Linux环境下进行。这一主题涵盖了多个关键知识点,包括文件操作、进程管理、内存管理、信号处理、网络编程以及系统...

    FrameBuffer 应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    Framebuffer 是一种显示驱动接口,在 Linux 系统中用于抽象并屏蔽不同显示设备的硬件细节。它通过设备文件(如 /dev/fbX)提供一块显示内存,使应用程序无需关心物理显存的细节。应用程序通过 mmap 将显示缓冲区映射...

    Linux网络编程socket编程学习

    自学Linux网络编程关于socket的编写,包括 server.c 和 client.c 的编写;很详细的介绍了网络套接字socket的C/S模型TCP协议的服务器端和客户端的程序函数以及编写过程;重点介绍多路I/O转接服务器的实现,包括select...

    V4L2 摄像头应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

    应用程序通过对这些设备节点进行I/O操作来配置和使用设备。 摄像头应用编程的步骤包括: 打开设备:使用open函数打开摄像头设备文件。 查询设备属性:使用ioctl()函数查询设备功能,确保其支持视频采集功能。 设置...

    C++和Linux学习笔记.zip

    5. **网络和I/O**:掌握网络编程的基本概念,如套接字编程,以及如何通过标准输入/输出和文件描述符进行I/O操作。 6. **系统调用与内核接口**:深入理解Linux内核,学习如何使用系统调用编写高效的程序。 压缩包中...

    linux学习笔记(初学者可共勉)

    文件编程是Linux编程中的关键部分,涉及到文件I/O、文件权限和文件操作。在Linux中,一切皆为文件,了解如何正确地读写文件、处理错误和重定向输出至关重要。比如,`open`函数用于打开文件,`read`和`write`用于读写...

    Linux编程精髓 部分笔记

    ### Linux编程精髓部分知识点 #### 用户级内存管理 在Linux编程中,用户级内存管理是极为重要的一个方面,它涉及...以上是对“Linux编程精髓部分笔记”所涉及知识点的详细解释和总结,希望对学习Linux编程有所帮助。

    Linux嵌入式学习笔记

    在深入探讨Linux嵌入式学习笔记的内容之前,我们先来理解一下这个领域的基本概念。Linux嵌入式系统是指将Linux操作系统内核移植到特定硬件平台上的系统,用于控制或管理设备的各种功能。这类系统广泛应用于各种领域...

Global site tag (gtag.js) - Google Analytics