欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

C语言中的文本流模型与文件操作

最编程 2024-08-13 09:04:34
...

文本流的本质就是二进制数据流,其表现的形式,就是一维的字符数组。

在这里插入图片描述

文本流工作的流程如下:

  1. 设备将二进制数据送到缓冲区
  2. 文本流将二进制数据进行转化,主要为:
    按照 ‘\n’ 符号,将二进制流解析为一行行文本
  3. 最后输入\输出函数按照一行行文本进行读写

在这里插入图片描述

/*
    stream_first.c
    Use the stream to solve the problem
    BeginnerC
*/
#include <stdio.h>
int main()
{
    char c = 'c';
    char read_char = 'n';
    ungetc(read_char, stdin);
    c = getchar();
    putchar(c);
    return 0;
}

在这个案例中,我们展现了文本流模型的冰山一角,如您所见,getchar 函数直接返回了 ‘n’,而在这之前,我们使用了一个新函数 ungetc 将 ‘n’ 写入 stdin。

下面,我们叙述这一切的工作原理。

在 C语言 中,所有标准库函数的输入输出,都扎根于文本流模型,而 C语言 在运行的时候,默认也提供三个文本流供我们读写数据。

他们分别的 stdin, stdout, stderr,其中 前缀 std 代表 “标准",而in, out, err 代表输入、输出与错误。

他们的抽象就是字符数组,而在刚刚的工作流程之中:

  1. 一开始,标准输入输出流没有任何数据
  2. 使用 ungetc 以后,标准输入流里面拥有了字符 ‘n’
  3. 使用 getchar 函数以后,我们从标准输入流中读入了字符 ‘n’

值得一提的是,ungetc 的原理是对输入流缓冲区进行操作,而如果我们对输出流进行操作,其结果是未定义的。

在这里插入图片描述

/*
    stream_second.c
    Use the stream to solve the problem
    BeginnerC
*/
#include <stdio.h>
int main()
{
    char c = '\0';
    while (EOF != (c = getchar()))
        putchar(c);
    return 0;
}

在这个程序中,我们将输入流复制到输出流之中,我们可以发现:尽管 getchar 只读取一个字符,但是它真正工作起来是在我们换行之后。

这就体现出文本流模型按行读取的特点。

事实上,这个程序等价于

在这里插入图片描述

/*
    stream_third.c
    Use the stream to solve the problem
    BeginnerC
*/
#include <stdio.h>
int main()
{
    char c = '\0';
    while (EOF != (c = getc(stdin)))
        putc(c, stdout);
    return 0;
}

事实上,很多 C语言标准库函数 都是对输入输出流做了一层封装。

包括 printf, scanf 这些我们打过许多次交道的程序。

现在,我们发现程序中多出了一个叫做 EOF 的常量,它的含义就是“流结束"。,在 Fedora Linux 下面,CTRL+D可以让输入流结束。

而现在,我们希望以另一种角度看待文本流,那就是普通文件的角度。

Hello World
Here is BeginnerC

如你所见,我们准备一段文本,并将其写入一个文本文件,并进行如图所示的操作。
在这里插入图片描述

在这个案例之中,我们首次展现了文件与文本流的关系,这个 < 指令,被称为重定向,意义在于将输入的源头,从 shell 转移到 文件之中。

对于 C语言 而言,这仅仅意味着读写设备的转变,而不是输入输出流的改变,因此,一切照旧。

事实上,除了运用外部的手段以外,C语言自身也提供了许多与文件有关的函数,用于帮助我们将文本流与文件挂钩。

在这里插入图片描述

/*
    freopen.c
    Use the freopen function
    BeginnerC
*/
#include <stdio.h>
int main()
{
    char c = '\0';
    freopen("output.txt", "w", stdout);
    while (EOF != (c = getchar()))
        putchar(c);
    return 0;
}

在这个程序中,我们使用 freopen 函数对输入输出流进行重定向,将输出流 stdout 重定向到文本文件 output.txt 中。

值的注意的是,这里我们首次使用了 C语言 中的文件读写字符串,下面让我们来正式罗列他们。

标志 含义
w 写(如果原文件存在内容,则清空文件)
r 读文件(如果文件不存在,失败)
a 追加写模式(不存在则创建,存在则在文件末尾追加)
w+ 读写一体(如果原文件存在内容,则清空文件)
r+ 读写文件一体(如果文件不存在,失败)
a+ 追加读写模式(不存在则创建,存在则在文件末尾追加) 文本流模型与文件操作
b 采用二进制流模型而不是文本流(在 UNIX 下,二进制流与文本流是一体两面)

而在这个基础上,我们也引入除“重定向"以外的另一种使用文本流的方式。

在这里插入图片描述

/*
    fopen.c
    Use the fopen to open the file
    BeginnerC
*/
#include <stdio.h>
int main()
{
    FILE *fp = NULL;
    int number_1, number_2, number_result;
    fp = fopen("new.txt", "w+");
    if (NULL == fp)
    {
        return -1;
    }
    fprintf(fp, "%d + %d = %d\n", 1, 2, 1 + 2);
    fflush(fp);
    fseek(fp, SEEK_SET, 0);
    fscanf(fp, "%d + %d = %d", &number_1, &number_2, &number_result);
    printf("%d + %d = %d\n", number_1, number_2, number_result);
    fclose(fp);
    return 0;
}

在这个案例中,我们使用 fprintf 与 fscanf 等函数,对文本流进行读写,fopen 则让文本流与特定的文件挂钩。

可以注意到,实际上:

printf(argument_list)
scanf(argument_list)
// Euqal to
fprintf(stdout, arguemnt_list)
fscanf(stdin, argument_list)

而 fflush 函数,则是一个类似于“加速器"的函数,它会让输出流缓冲区的内容立刻写入对应的文件。

值得注意的是 fseek 函数,它的职责是定位,负责读写位置在文本流中的定位。

其中分为

标志 含义
SEEK_SET 文本流缓冲区起始
SEEK_CUR 文本流缓冲区当下位置
SEEK_END 文本流缓冲区末尾

推荐阅读