教材知识点总结

第九章 I/O库函数

I/O库函数与系统调用

  • 系统调用函数
    • open()
    • read()
    • write()
    • lseek()
    • close()
  • I/O库函数
    • fopen()
    • fread()
    • fwrite()
    • fseek()
    • fclose()

可见每个库函数的根都在对应系统调用函数中

I/O库函数的算法

  • fread算法
    • 第一次调用fread()时,FILE结构体的缓冲区是空的,fread()使用保存的文件描述符fd发出一个
      n=read(fd, fbuffer, BLKSIZE);
    • 在随后的每次fread()调用中,它都尝试满足来自FILE结构体内部缓冲区的调用。当缓冲区为空时,它就会发出read()系统调用来重新填充内部缓冲区。
  • fwrite()算法
    • fwrite()算法与fread()算法相似,只是数据传输方向不同。
    • 每次调用fwrite()时,它将数据写入内部缓冲区,并调整缓冲区的指针、计数器和状态变量。
    • 若缓冲区已满,则发出write()系统调用。
  • fclose()算法
    • 若文件以写的方式打开,fclose()会先关闭文件流的局部缓冲区。
    • 然后它会发出一个close(fd)系统调用来关闭FILE结构体中的文件描述符。
    • 最后它会释放FILE结构体,并将FILE指针重置为NULL。

I/O库模式

  • fopen()中的模式参数
    • r:读
    • w:写
    • a:追加
    • r+:读/写,不会截断文件
    • w+:读/写,会先截断文件;如果文件不存在,会创建文件。
    • a+:通过追加进行读/写;如果文件不存在,会创建文件。
  • 字符模式I/O
int fgetc(FILE *fp); // get a char from fp, cast to int.
int ungetc(int c, FILE *fp); // push a previously char got by fgetc() back to stream 
int fputc(int c, FILE *fp); // put a char to fp
编写一个c语言程序,将文本中的小写字母转换为大写字母
  • 原文本内容
  • c语言代码
#include <stdio.h>
int main() {
    FILE *file;
    char filename[] = "week2.txt";
    char ch;
    file = fopen(filename, "r+");
    if (file == NULL) {
        printf("无法打开文件。\n");
        return 1;
    }
    while ((ch = fgetc(file)) != EOF) {
        if (ch >= 'a' && ch <= 'z') {
            ch = ch - 32; 
            fseek(file, -1, SEEK_CUR);
            fputc(ch, file);
        } 
    }
    fclose(file);
    return 0;
}
  • 编译运行
  • 运行结果
  • 行模式I/O
    char *fgets(char *buf, int size,FILE *fp):从fp中读取最多为一行(以\n结尾)的字符。
    int fputs(char *buf,FILE *fp):将buf中的一行写入fp中。
  • 格式化I/O
    • 格式化输入:(FMT=格式字符串)
scanf(char *FMT, &items);  //from stdin
fscanf(fp, char *FMT, &items);  //from file stream
  • 格式化输出:
printf(char *FMT, items);  //to stdout
fprintf(fp, char *FMT, items);  //to file stream
  • 内存中的转换函数
scanff(buf, FMT, &items);  //input from buf[ ] in memory
sprintf(buf, FMT, items); //print to buf[ ] in memory
  • 其他I/O库函数
    • fseek()、ftell()、rewind(): 更改文件流中的读/写字节位置。
    • feof()、ferr()、fileno():测试文件流状态。
    • fdopen():用文件描述符打开文件流。
    • freopen():以新名称重新打开现有的流。
    • setbuf()、setvbuf():设置缓冲方案。
    • popen():创建管道,复刻子进程来调用sh。
  • 限制混合fread-fwrite
    • 当文件流同时用于读/写时,就会限制使用混合fread()和fwrite()调用。
    • 规范要求每对fread()和fwrite()之间至少有一个fseek()或ftell()。

文件流缓冲

  • 无缓冲:从非缓冲流中写入或读取的字符将尽快单独传输到文件或从文件中传输。
  • 行缓冲:遇到换行符时,写入行缓冲流的字符以块的形式传输。
  • 全缓冲:写入全缓冲流或从中读取的字符以块大小传输到文件或从文件传输。
  • 通过fopen()创建文件流之后在对其执行任何操作之前,用户均可发出一个
    setvbuf(FILE *stream, char *buf, int node, int size)

变参函数

  • 在I/O库函数中,printf()相当独特,因为多种不同类型的可变数量参数都可以调用它
  • C语言与C++仍然允许参数数量可变的函数。这些函数必须至少使用一个参数进行声明,后跟3个点。

苏格拉底测试

I/O库模式






文件流缓冲



问题与解决

内存中的转换函数是什么,有什么用,看完教材后不是很理解。

解答: