Unix 标准I/O总结和与文件I/O的比较

我们可以将文件I/O视为系统调用,内核要执行I/O操作,这里涉及到页缓存(高速缓存区)的概念,文件I/O执不执行与缓存区有关。

而标准I/O是对系统I/O调用的封装,标准I/O也有缓存区、行缓存的概念。正是由于这二级的缓存模式。导致标准I/O的效率很低。

当打开一个流时,标准I/O函数fopen返回一个指向FILE对象的指针。该对象通常是一个结构,它包含了标准I/O库为管理该流所需的所有信息,包括:用于实际I/O的文件描述符、指向用于该缓冲区的指针、缓冲区的长度、当前在缓冲区的字符数以及出错标志等。为引用一个流,需将FILE指针作为参数传递给每个标准I/O函数。

对于标准输入、标准输出和标准出错,他们的文件描述符对应STFIN_FILENO、STDOUT_FILENO和STDERR_FILENO。这三个标准I/O流通过预定义stdin、stdout和stderr加以引用。这三个文件指针以及标准I/O函数都定义在头文件<stdio.h>中。

缓冲

标准I/O库提供缓冲的目的是尽可能减少使用read和write调用次数。提供了三种类型的缓冲:

1) 全缓冲:需在填满标准I/O缓冲区后才进行实际I/O操作。

2) 行缓冲:当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。

3) 不带缓冲:标准I/O库不对字符进行缓冲存储。

一般而言,标准出错是不带缓冲的,打开终端设备的流是行缓冲的,其他所有流则是全缓冲的。当流是全缓冲,但该缓冲区是局部填写时,可用fflush函数冲洗。

可调用下面的函数更改缓冲区类型:

#include <stdio.h>

void setbuf(FILE *stream, char *buf);

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

任何时候,我们都可以强制冲洗一个流:

#include <stdio.h>

int fflush(FILE *stream);

此函数将使该流所有未写的数据都被传送至内核。作为一个特例,如若fp是NULL,则此函数将导致所有输出流被冲洗。

打开流

#include <stdio.h>

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

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

FILE *freopen(const char *path, const char*mode, FILE *stream);

这三个函数的区别是:

1) fopen打开一个指定的文件。

2) fropen在一个指定的留上打开一个指定的文件,如若该流已经打开,则先关闭该流。如若该流已经定向,则fopen清除该定向。此函数一般用于将一直指定的文件打开为一个预定义的流:标准输入、标准输出或标准错误。

3) fdopen获取一个现有的文件描述符,并使一个标准的I/O流与该描述符相结合。此函数常用于由创建管道和网络通信函数返回的描述符。因为这些特殊类型的文件不能用标准I/Ofopen函数打开,所有我们必须先调用设备专用函数以获得一个文件描述符,然后用fopen使一个标准I/O与该描述符相关联。

其中的mode参数可以用是以下15种不同的值:

r或rb: 为读打开

w或wb: 把文件截短至0长,或为写而创建

a或ab: 添加;为在文件写打开,或为写打开

r+或r+b或rb+: 为读和写打开

w+或w+b或wb+: 把文件截短至0,或为读和写打开

a+或a+b或ab+: 为在文件尾端读和写而打开或创建

#include <stdio.h>

int fclose(FILE *fp);

在文件被关闭之前,冲洗缓冲区中的输出数据。如果标准I/O库已经为该流自动分配了一个缓冲区,则释放缓冲区。

读和写流

一旦打开了流,则可在三种不同类型的非格式化I/O中进行选择,对其读、写操作:

1) 每次一个字符是I/O。一次读或写一个字符,如果流是带缓冲区的,则标准I/O函数会处理所有缓冲。

2) 每次一行的I/O。如果想要一次读或写一行,则使用fgets和fputs。每行都以一个换行符终止。当调用fgets时,应说明能处理的最大行长。

3) 直接I/O。fread和fwrite函数支持这种类型的I/O。

每次一个字符I/O

输入函数:

#include <stdio.h>

int getc(FILE *stream);

int fgetc(FILE *stream);

int getchar(void);

getchar()等价于getc(stdin)。getc和fgetc区别在于getc可被实现为宏,而fgetc则不能实现为宏。

不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分出错和到达文件尾端,必须调用ferror和feof函数。

#include <stdio.h>

int feof(FILE *stream);

int ferror(FILE *stream);

这两个函数的返回值:若条件为真则返回非0值,否则返回0。

每个流在FILE对象中维持了两个标志:出错标志和文件结束标志

调用clearerr则清除这两个标志。

void clearerr(FILE *stream);

从流读取数据后,可以调用ungetc将字符再压入回流中。

int ungetc(int c, FILE *stream);

压入回流中的字符以后又可以从流中读出,但读出的字符顺序与压送回的顺序相反。

对于输出函数:

#include <stdio.h>

int putc(int c, FILE *stream);

int fputc(int c, FILE *stream);

int putchar(int c);

与输入函数一样putchar(c)等效于putc(c, stdout)。putc可实现为宏。

每次一行I/O

#include <stdio.h>

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

char *gets(char *s);

fgets从指定的流读,必须指定缓冲区长度size。此函数一直读到下一个换行符为止,但是不超过n-1个字符,读入的字符被送入缓冲区。该缓冲区以null字符结尾。如若改行(包括最后一个换行符)的字符数超过n-1,则fgets只返回一个不完整的行,但是缓冲区总是以null字符结尾。对fgets的下一次调用会继续读改行。

gets从标准输入读。它是一个不推荐的函数,因为不能指定缓冲区长度,可能造成缓冲区溢出,写到缓冲区之后的存储空间中,从而产生不可预料的后果。

fputs和puts提供每次输出一行的功能。

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

int puts(const char *s);

二进制I/O

#include <stdio.h>

size_t fread(void *ptr, size_t size,size_t nmemb, FILE *stream);

size_t fwrite(const void *ptr, size_tsize, size_t nmemb, FILE *stream);

以上两个函数可一次读或写整个结构。

定位流

有三种方法定位标准I/O流

1) ftell和fseek。这两个函数要求文件的位置可以存放到一个长整形中。

2) ftello和fseeko。他们可以使文件文件偏移量不一定使用长整形。他们用off_t数据类型代替了长整形。

3) fgetpos和fsetpos。他们使用抽象数据类型fpos_t记录文件的位置。这种数据累心可以定义为记录一个文件的位置所需的长度。

#include <stdio.h>

int fseek(FILE *stream, long offset, intwhence);

long ftell(FILE *stream);

int fseeko(FILE *stream, off_t offset, intwhence);

off_t ftello(FILE *stream);

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

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

格式化I/O

输出:

#include <stdio.h>

int printf(const char *format, ...);

int fprintf(FILE *stream, const char*format, ...);

int sprintf(char *str, const char *format,...);

int snprintf(char *str, size_t size, constchar *format, ...);

输入:

#include <stdio.h>

int scanf(const char *format, ...);

int fscanf(FILE *stream, const char*format, ...);

int sscanf(const char *str, const char*format, ...);

fileno函数

标准I/O库最终都要调用I/O系统调用函数。每个标准I/O流都有一个与其相关联的文件描述符,可以对一个流调用fileno函数以获得其描述符。

int fileno(FILE *stream);

临时文件

#include <stdio.h>

char *tmpnam(char *s);

FILE *tmpfile(void);

tmpnam函数产生一个与现有文件名不同的一个有效路径名字字符串。每次调用它,它都产生一个不同的路径名,最多调用TMP_MAX次。

tmpfile创建一个临时二进制文件。

此外还有两个类似的函数:

#include <stdio.h>

char *tempnam(const char *dir, const char*pfx);

int mkstemp(char *template);

时间: 2024-08-06 22:38:33

Unix 标准I/O总结和与文件I/O的比较的相关文章

UNIX标准及实现

UNIX 标准 ISO C:意图是提供C程序的可移植性,使得它能够适合于大量不同的操作系统. 该标准不仅定义了C程序设计语言的语法和语义,还定义了标准库 POSIX(Portable Operating System Interface): 指的是可移植操作系统接口.该标准的目的是提升应用程序在各种UNIX系统环境之间的可移植性.它定义了"符合POSIX"的操作系统必须提供的各种服务. POSIX 包含了 ISO C 标准库函数 SUS(Single Unix Specificatio

Unix文件系统学习笔记之二: 文件描述符、inode和打开文件表

Unix文件系统学习笔记之二: 文件描述符.inode和打开文件表 系统盘上数据的布局 文件系统无非是关于数据在磁盘上的组织以及存储空间管理的,为此,首先需要知道磁盘上数据的总体布局方式.以Unix为例,最重要的一张表如下: Unix 进程管理中和用户文件.io 最相关的数据结构:usr 数据结构 The procstructure does not record information related to file access.  However the userstructure con

《UNIX环境高级编程》读书笔记 —— 文件 I/O

一.打开或创建一个文件 #include <fcntl.h> int open(const char *pathname, int oflag, .../*mode_t mode*/); 返回值:若成功则返回文件描述符,若出错则返回-1 oflag选项: O_RDONLY O_WRONLY O_RDWR 以上三个常量中必须指定一个,且只能指定一个. 以下常量都是可选的: O_APPED     每次写时追加到文件尾 O_CREAT     若文件不存在,则创建 O_EXCL      若同时指

JavaScript标准Selection操作,对页面文件选取操作

一.简介 selection是对当前激活选中区(即高亮文本)进行操作. 在非IE浏览器(Firefox.Safari.Chrome.Opera)下可以使用window.getSelection()获得selection对象,本文讲述的是标准的selection操作方法.文中绝大部分内容来自 https://developer.mozilla.org/en/DOM/Selection 二.术语 以下几个名词是英文文档中的几个名词. 1.anchor:选中区域的“起点”. 2.focus:选中区域的

Unix环境高级编程学习笔记(三):标准I/O , 系统数据文件和信息

1 标准I/O函数不同于read,write函数,是其在流上进行操作, 当首次调用标准I/O函数时,系统会首先调用malloc,为流创造缓冲区, 2 fopen函数 #include<stdio.h> file * fopen(const char* pathname, const char * restrict name); 打开返回指针,出错返回NULL, type的取指有r(读),w(写),a(追加),r+/w+(读+写),a+(读+写+追加) int fclose(file* fp)

《UNIX环境高级编程》笔记——3.文件IO

一.引言 说明几个I/O函数:open.read.write.lseek和close,这些函数都是不带缓冲(不带缓冲,只调用内核的一个系统调用),这些函数不输入ISO C,是POSIX的一部分: 多进程共享资源(包括文件)时,会有很多额外的烦恼,需要对共享资源.原子操作等概念深入理解,需要理解涉及的内核有关数据结构,这些数据结构对理解文件.共享有重要作用: 最后介绍dup.fcntl.sync.fsync和ioctl函数. 二.文件描述符 open或creat文件时,内核--文件描述符fd-->

UNIX标准

背景 人们在UNIX编程环境和C 程序设计语言的标准化方面已经做了很多工作.虽然UNIX应用程序在不同的UNIX操作系统版本之间进行移植相当容易,但是2 0 世 纪 80年代UNIX版本种类 的剧增以及它们之间差别的扩大,导致很多大用户( 如美国政府)呼吁对其进行标准化. 对于我们程序员来说,了解基本的标准和背景是有必要,本文主要对ISO C    POSIX    Sigle UNIX Specification 3个标准进行说明 ISO C 1989年,c程序设计语言的ANSI的标准X3.1

unix高级编程中的一个头文件 apue.h 与一个差错文件error.c 的内容

在查看unix高级编程中的代码时,如果我们编写书中的代码,发现一般都会报错,这是因为作者在写这本书时,他自己编写了一个头文件,跟一个差错处理文件,出来处理他自己的代码错误信息: 下面我们来看下代码的内容: 我实现第一个代码,关于文件的打开,实现 ls 命令的代码: #include "apue.h"#include <stdio.h>#include <dirent.h> int main(int argc, char *argv[]){ DIR *dp; st

QT+ 使用标准对话框+关于对话框+问题对话框+文件对话框

#include "mainwindow.h" #include <QMenuBar> #include <QMenu> #include <QAction> #include <QDialog> #include<QDebug> #include <QMessageBox> #include <QFileDialog> MainWindow::MainWindow(QWidget *parent) :