标准IO

一、关于标准IO缓冲区

标准IO提供缓冲的目的是尽可能减少使用read和write调用的此数,他对每个IO流自动地进行缓冲管理。标准IO提供三种类型的缓冲:
1、全缓冲:这种情况下,当标准IO缓冲区填满后才进行实际IO操作。在一个流上执行第一次IO时,相关标准IO函数通常调用malloc获得所需的缓冲区。全缓冲的缓冲区大小一般为8192(具体要看设置)
2、行缓冲:当输入和输出中遇到换行符‘\n’时,才会执行实际IO操作。当涉及一个终端时(例如标准输入和标准出错),通常使用行缓冲。
因为标准IO库用来收集每一行的缓冲区的长度是固定的,所以只要行缓冲区满了,即使还没有写一个换行符,也会进行IO操作
3、不带缓冲:标准IO库不对字符进行缓冲存储,只要执行了输入和输出操作,便会立即实行IO操作。标准出错stderr通常是不带缓冲的。

对于进程预定义了三个流,并且这三个流可以自动地被进程使用:
标准输入:stdin
标准输出:stdout
标准出错:stderr

ISO  C要求下列缓冲特征:
当且仅当标准输入和标准输出并不涉及交互式设备时,它们才是全缓冲。否则一般为行缓冲。
人机交互要求不可全缓冲。
标准出错绝不会是全缓冲的
涉及终端设备的其他流,一般为行缓冲的,否则是全缓冲。
普通文件一般为全缓冲


可以使用下面两个函数更改缓冲类型:

void setbuf(FILE *stream, char *buf);
功能:更改流的缓冲类型
参数:
          stream:要更改缓冲类型的流指针
          buf:缓冲区的长度,通常指定为BUFSIZ,通常在此之后流就是全缓冲的。如果为NULL,则关闭缓冲。
返回值:成功返回0,错误返回非0值

int setvbuf(FILE *stream, char *buf, int mode, size_t size);
功能:更改流的缓冲类型
参数:
            stream:要更改缓冲类型的流指针
             buf:如果被设置为不带缓冲的流,则忽略buf和size,如果指定了全缓冲或行缓冲,buf指定了缓冲区的地址,size指定了缓冲区的长度。如果buf为NULL,系统自动分配全缓冲区或行缓冲区合适的长度。
             mode:
                           指定所需的缓冲类型    
                            _IOFBF         全缓冲
                            _IOLBF          行缓冲
                            _IONBU        不带缓冲
             size:缓冲区大小
返回值: 成功返回0,错误返回非0值

int fflush(FILE *stream);
功能:冲洗一个流,此函数使该流所有未写的数据都被传送至内核
参数:
        stream:要冲洗的流,如果为NULL,则冲洗所有输出流
返回值:成功返回0,失败返回EOF

冲洗说明标准IO缓冲区的写操作,flush有两种意思,在标准IO库方面,flush意味着将缓冲区的内容写到磁盘上。在终端驱动程序方面,flush表示丢弃已存储在缓冲区的数据


二、流的定向
对于ASCII字符集,一个字符用一个字节表示,对于国际字符集,一个字符可用多个字节表示。标准IO文件流可用于单字节或多字节(宽)字符集。流的定向决定了所读写的字符是单字节还是多字节。当一个流最初被创建时,它并没有定向。如若在未定向的流上使用一个多字节IO函数,则将该流的定向设置为宽定向。如若在未定向的流上使用一个单字节IO函数,则将该流的定向设置为字节定向。
可用以下函数设置流的定向:

int fwide(FILE *stream, int mode);
功能:设置一个未定向流的定向
参数:
                    stream:要改变定向的流
mode:
为负值时,试图将指定的流设置为字节定向
为正值时,试图将指定的流设置为宽定向
为0时,不设置流的定向,但返回标示该流定向的值
返回值:若流是宽定向的则返回正值,若流是字节定向的则返回负值,若流是未定向的,则返回0。无出错返回
注:fwaid只能改变未定向的流。并不改变已定向的流


三、标准IO的一些函数
FILE *fopen(const char *path, const char *mode);
功能:打开一个指定文件,返回一个标准IO流
参数:
        path:文件所在路径
        mode:打开方式
                    r:只读方式打开,打开后从文件头开始读
                    r+:读写方式打开,打开后从文件头开始读写
                    w:只写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空
                    w+:读写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空
                    a:只写打开,文件不存在则创建,存在以只写方式追加,即从文件尾部开始写
                    a+:读写方式打开,文件不存在则创建,存在则读文件时从文件头开始,写文件时从文件尾开始
当指定参数b时,表示以二进制方式打开,不过因为UNIX不对文本文件和二进制文件进行区分,所以在UNIX环境下指定b实际上并无作用
返回值:成功返回流指针,失败返回NULL

FILE *freopen(const char *path, const char *mode, FILE *stream);
功能:在一个指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流。若该流已经定向,则freopen清除该定向。此函数一般用于将一个指定的文件打开为一个预订义的流:标准输入,标准输出或标准出错。
参数:
                 path:文件所在路径
                 mode:  
                    r:只读方式打开,打开后从文件头开始读
                    r+:读写方式打开,打开后从文件头开始读写
                    w:只写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空
                    w+:读写方式打开,文件不存在则创建,存在则把文件截短至0,即将文件清空
                    a:只写打开,文件不存在则创建,存在以只写方式追加,即从文件尾部开始写
                    a+:读写方式打开,文件不存在则创建,存在则读文件时从文件头开始,写文件时从文件尾开始
当指定参数b时,表示以二进制方式打开,不过因为UNIX不对文本文件和二进制文件进行区分,所以在UNIX环境下指定b实际上并无作用

                  stream:要在此流上打开文件
返回值:成功返回流指针,失败返回NULL

FILE *fdopen(int fd, const char *mode);
功能:将一个现有的文件描述符和一个标准IO流相结合
参数:
         fd:一个已经打开的文件描述符
         mode:
                    和fopen一样,不过此函数为写打开时,并不将文件清空。另外追加方式也不能创建该文件(因为文件已经存在)
        
返回值:成功返回生成的流指针,失败返回NULL
注:此文件描述符必须是一个已经打开的文件描述符


四、标准IO读写

int fgetc(FILE *stream);
功能:从指定的流中丢读取字符
参数:stream:要读取的流
返回值:成功返回字符,失败或读到文件尾部返回EOF(-1)


int fputc(int c, FILE *stream);
功能:向指定的流中写一个字符
参数:
c:要写入的字符
stream:要写入的流
返回值:成功返回写的字符,错误返回EOF


char *fgets(char *s, int size, FILE *stream);
功能:从指定的流读取多个字符存放在s指向的地址,每次读一行,以一个换行符终止
参数:
            s:将读取到的数据存放到s中
            size:缓冲区长度
            stream:要读取的文件流
返回值:成功返回s,失败或读到结尾返回NULL
注:
  • 每次fgets最多只能读取size-1个字符,因为每次读取结束时都会自动加‘\0’
  • 如果读取过程中遇到‘\n’,则读取结束,'\n'会被读走


int fputs(const char *s, FILE *stream);
功能:将字符串写到指定的流
参数:
          s:s中存放将要写入的数据
          stream:要写的文件流
返回值:成功返回写入的字符个数,失败返回EOF
注:如果遇到‘\n’则结束写


size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从指定的流读取多数据存放在ptr指向的地址
参数:
          ptr:将已读取的数据存放到ptr中
          size:要读取对象的大小
          nmemb:要求读取对象的个数
          stream:要读取的流
返回值:返回实际读取的对象的个数


size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:将数据写向指定的流
参数:
          ptr:存放要写入的数据存放在ptr中
          size:要写入数据的对象的大小
          nmemb:要求写入数据的对象的个数
          stream:要写入的流
返回值:返回实际写入的对象的个数,如果返回值小于所要求的nmemb,则出错

注:

1、在上面的三个读操作中,不区分出错和到达文件尾,为了区分这两种情况,需调用以下两个函数
int feof(FILE *stream);
int ferror(FILE *stream);
两个函数的返回值:若条件为真则返回非0值。否则返回0

2、在大多数实现中,为每个流在FILE对象中维持了两个标志:
  • 出错标志
  • 文件结束标志 
     调用clearerr清除这两个标志 
    void clearerr(FILE *stream);

3、从流中读取数据以后可以调用ungetc将字符再压送回流中
        int ungetc(int c, FILE *stream);
         参数:c:要回送的字符
                    stream:要回送的流
         返回值:成功返回c,出错返回eof
        
        压送回流中的字符以后又可从流中读出。ISO C允许实现支持任何次数的回送,但是它要求时限提供一次只送回一个字符,我们不能期望一次能送回多个字符
        回送的字符不必一定是上一次读到的字符,参数c既可以是上次读出的字符,也可以是任意别的字符,但不能回送EOF。但是当已经到达文件尾端时,仍可以回送一个字符,下次读将返回该字符,再次读则返回EOF。之所以能这样做的原因是一次成功的ungetc调用会清除该流的文件结束标志。



五、文件定位

int fseeko(FILE *stream, off_t offset, int whence);
int fseek(FILE *stream, long offset, int whence);
功能:更改内核中offset的值
参数:
            stream:要更改的文件流
            offset:偏移值。offset>0,向后偏移,offset<0,向前偏移。
            whence:
                    SEEK_SET  从文件其实位置开始
                    SEEK_CUR 从文件当前位置开始
                    SEEK_END 从文件尾端开始
返回值:成功返回0,失败返回-1
注:上述两个函数的区别仅在于文件偏移量的类型不一样,一个时是long,一个是off_t


off_t ftello(FILE *stream);
long ftell(FILE *stream);
功能:获得内核中的文件偏移量
参数:stream:要获取偏移量的文件流
返回值:成功返回文件从头开始的偏移值,失败返回-1
注:上述两个函数的区别仅在于文件偏移量的类型不一样,一个时是long,一个是off_t

void rewind(FILE *stream);
功能:定位到文件起始位置
参数:stream:要定位的文件流

  
int fileno(FILE *stream);
功能:获得与流相关联的文件描述符
参数:stream:要获取描述符的流
返回值:返回与流相关联的文件描述符


六、临时文件

char *tmpnam(char *s);
功能:产生一个与现有文件名不同的一个有效路径名字符串
参数:s:如果为NULL,则将产生的路径名存放在一个静态区中。指向该静态区的指针作为函数值返回。下一次再调用该函数时,会重写该静态区。如果s不是NULL,则将产生的路径名存放在s指向的空间中,s作为函数返回值。
返回值:指向唯一路径名的指针

FILE *tmpfile(void);
功能:创建一个临时二进制文件(wb+),在关闭文件或进程结束时    将自动删除这种文件
返回值:成功返回文件流指针,出错返回NULL


























### 什么是标准IO? **标准IO(Standard I/O)** 是C语言标准库(`<stdio.h>`)提供的一组用于输入输出操作的**高级函数接口**。它对底层的系统调用(如 `read()` 和 `write()`)进行了封装,提供了**缓冲机制**,提高了IO效率,并增强了程序的**可移植性**。 --- ### 标准IO的特点 | 特点 | 描述 | |------|------| | **缓冲IO** | 标准IO自带缓冲区,减少系统调用次数,提高效率。 | | **面向流(FILE *)** | 所有操作都通过 `FILE *` 指针进行,屏蔽了底层细节。 | | **跨平台兼容性好** | 在不同操作系统(如Windows、Linux)上表现一致。 | | **使用方便** | 提供丰富的函数如 `fscanf()`、`fprintf()`、`fgets()`、`fread()` 等。 | --- ### 标准IO与系统调用IO的区别 | 对比项 | 标准IO | 系统调用IO | |--------|--------|-------------| | 缓冲机制 | 有缓冲 | 无缓冲(除非手动实现) | | 接口来源 | C标准库(`<stdio.h>`) | 操作系统API(如Linux的 `<unistd.h>`) | | 数据类型 | `FILE *` | 文件描述符 `int` | | 可移植性 | 高 | 低(依赖系统) | | 函数示例 | `fopen`, `fread`, `fwrite`, `fclose` | `open`, `read`, `write`, `close` | --- ### 标准IO的核心结构:`FILE *` - `FILE *` 是一个指向 `FILE` 结构体的指针,该结构体由C标准库定义,包含了文件状态、当前位置、缓冲区等信息。 - 示例: ```c FILE *fp = fopen("example.txt", "r"); if (fp == NULL) { perror("打开文件失败"); return 1; } ``` --- ### 常用标准IO函数 | 函数名 | 功能 | |--------|------| | `fopen()` | 打开文件 | | `fclose()` | 关闭文件 | | `fread()` | 从文件读取二进制数据 | | `fwrite()` | 向文件写入二进制数据 | | `fgets()` | 从文件标准输入读取一行字符串 | | `fputs()` | 向文件标准输出写入一行字符串 | | `fprintf()` | 格式化输出到文件标准输出 | | `fscanf()` | 格式化输入从文件标准输入 | --- ### 示例:使用标准IO读写文件 ```c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp = fopen("output.txt", "w"); if (!fp) { perror("无法打开文件"); return EXIT_FAILURE; } // 写入文本 fprintf(fp, "Hello, Standard IO!\n"); fclose(fp); // 读取文件 fp = fopen("output.txt", "r"); if (!fp) { perror("无法打开文件"); return EXIT_FAILURE; } char buffer[100]; if (fgets(buffer, sizeof(buffer), fp)) { printf("读取内容: %s", buffer); } fclose(fp); return 0; } ``` --- ### 总结 标准IO是C语言中最常用的IO操作方式,它基于系统调用IO进行了封装,提供了缓冲机制和统一的接口,使得程序开发更高效、更安全、更可移植。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值