标准IO(库函数)

一、标准io(库函数)

    

1、缓存:

        行缓存(line buffering)、全缓存(fully buffering)和无缓存(unbuffered)是文件IO中的三种不同的缓冲方式。

1. 行缓存(line buffering):行缓存是指在输入输出操作中,数据会被缓存在缓冲区中,直到缓冲区被填满或者遇到换行符 \n。当缓冲区被填满或者遇到换行符时,缓冲区的内容会被一次性地写入或读取。在行缓存模式下,输出函数如 printf 会将数据先写入缓冲区,直到遇到换行符或者缓冲区被填满,才会将缓冲区的内容一次性地写入文件。输入函数如 fgets 会将一行完整的数据读取到缓冲区中,直到遇到换行符或者缓冲区被填满,才会将缓冲区的内容一次性地返回。

2. 全缓存(fully buffering):全缓存是指在输入输出操作中,数据会被缓存在缓冲区中,直到缓冲区被填满。当缓冲区被填满时,缓冲区的内容会一次性地写入或读取。与行缓存不同的是,全缓存模式下不会考虑换行符,而是等待缓冲区被填满才进行IO操作。这种模式适用于大量数据的输入输出,可以提高IO的效率。

3. 无缓存(unbuffered):无缓存是指在输入输出操作中,数据不会被缓存在缓冲区中,而是直接进行IO操作。每次进行IO操作时,数据会立即写入或读取。无缓存模式下,每次IO操作都会导致系统调用,因此相对于缓存模式,无缓存模式的IO操作会更频繁,但是可以保证数据的实时性和准确性

  

1、基础知识:

        标准io通过c库来操作文件

        使用户程序具有可移植性(不同系统间)

        库函数为了实现某个功能而封装起来的API集合
        提供统一的编程接口, 更加便于应用程序的移植(不同系统之间的移植)
        是语言或者应用程序的一-部分
        流:表示源源不断,操作文件时字符源源不断的输入或输出,这种方式叫字节流,通过流来实现标准io

        FILE指针:即FILE *,FILE是系统定义好的一个结构体,用于保存文件的相关信息

        FILE结构体的定义可以在 <stdio.h> 头文件中找到,但具体的实现细节可能因编译器和操作系统而异。一般而言,FILE结构体包含了以下成员变量:
        - int _file: 文件描述符,用于标识文件在操作系统中的唯一标识符。
        - int _flag: 文件状态标志,用于表示文件的打开模式和状态信息。
        - int _charbuf: 用于缓冲输入和输出的字符。
        - int _bufsiz: 缓冲区的大小。
        - char *_base: 缓冲区的起始地址。
        - int _bufsiz: 缓冲区的大小。
        - int _cnt: 缓冲区中剩余的字符数。
        - char *_ptr: 指向缓冲区中当前字符的指针。
        - int _tmpfname: 临时文件名。

FILE结构体的指针类型 FILE* 在文件操作中的意义是用于引用和操作文件。通过使用 FILE* 类型的指针,我们可以打开文件、读取文件内容、写入文件内容以及关闭文件等操作。

        由shell默认打开了三个流, 标准输入(stdin)标准输出(stdout)标准错误(stderr,无缓存流

2、标准io中的缓存:(其实系统调用就像是一个杯子,这个杯子会当任务装满(刷新)杯子(缓存区)之后再执行)

        缓存区大小(1024)、缓存区也相当于一个队列、刷新缓存区,执行缓存区内的任务

                1、全缓存

                        当缓存区满后,缓存区刷新一次

                        fopen打开的默认全缓存

                2、行缓存

                        当遇到换行,缓存区刷新一次

                        stdout默认是行缓存

                3、无缓存

                        没有缓存

3、标准io的相关函数

       1、fflush

        作用:强制刷新缓存区

        头文件<stdio.h>

        函数原型:

                int fflush(FILE *stream)

        参数:

                stream:传入想要操作的流

        返回值:

                成功返回0

 2、fprintf

        作用:

                向指定流中输出内容

        头文件:

                #includ<stdio.h>

        函数原型:

  补充:sprintf函数:

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

        sprintf函数是C语言中的一个标准库函数,用于将格式化的数据写入字符串中。它的作用是将格式化的数据按照指定的格式写入到一个字符串中,而不是输出到屏幕上,它可以格式化数据,也可以组合两个字符串。

其中,str是一个指向字符数组的指针,用于存储格式化后的字符串;format是一个格式控制字符串,用于指定输出的格式;...表示可变参数,用于提供要格式化的数据。

sprintf函数将格式化后的字符串写入到str指向的字符数组中,并返回写入的字符数(不包括终止符\0)。这个函数可以用于将数据格式化为字符串,然后进一步处理或存储。

例如,下面的代码将一个整数和一个浮点数格式化为字符串,并存储到buffer数组中:

char buffer[100];
int num = 10;
float f = 3.14;
sprintf(buffer, "Number: %d, Float: %.2f", num, f);

3、fopen:

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

      其中,filename是一个字符串,表示要打开的文件的路径和名称;mode也是一个字符串,表示打开文件的模式。

mode参数可以是以下几种模式之一:
- "r":以只读方式打开文件(返回的文件流指针只读)。文件必须存在,否则打开失败。
- "w":以写入方式打开文件(返回的文件流指针只写)。如果文件不存在,则创建一个新文件;如果文件已存在,则清空文件内容。(无论有无文件都创建新文件)
- "a":以追加方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则在文件末尾追加内容。只写
- "r+":以读写方式打开文件。文件必须存在,否则打开失败。
- "w+":以读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则清空文件内容。
- "a+":以读写方式打开文件。如果文件不存在,则创建一个新文件;如果文件已存在,则在文件末尾追加内容。

 fopen函数返回一个指向FILE结构的指针,该结构包含有关打开文件的信息。如果打开文件失败,则返回NULL,可以通过全局变量errno来获取错误码。errno是一个整数类型的变量,它在 <errno.h> 头文件中定义。要获取errno的值,可以在fopen函数调用后立即使用errno变量。例如,可以使用perror函数来输出错误信息,它会根据errno的值输出对应的错误信息。

此时可以通过perror函数来打印错误信息。

在上面的例子中,我们尝试以只读方式打开一个不存在的文件"test.txt"。由于文件不存在,fopen函数将返回NULL,然后我们使用perror函数输出错误信息。输出的错误信息将包含前缀字符串"Failed to open file"和具体的错误描述,例如"No such file or directory"。

 4、fputc/fgetc

        1、fputc

int fputc(int c, FILE *stream);

                作用:向指定流中输出单个字符,其中,c是要写入文件的字符的ASCII码值,stream是一个指向已打开文件的指针。fputc函数将指定的字符写入到指定的文件中,并返回写入的字符。如果发生错误,fputc函数将返回EOF(-1)。

          2、fgetc

int fgetc(FILE *stream);

        
5、fputs/fgets

        fgets(获取流中的数据到str内,其实gets也是获取输入流中的数据到括号内的参数内,gets不安全的原因是若缓冲区的数据大于参数最大容量的大小会导致越界。)

        

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


- str是一个指向字符数组的指针,用于存储读取的字符串。
- n是要读取的最大字符数(包括空字符)。
- stream是要读取的输入流,通常是stdin(标准输入)或文件指针。

fgets函数会从输入流中读取字符,直到达到以下条件之一:
- 读取了n-1个字符。
- 读取到换行符(\n)。
- 到达文件末尾。

6、fwrite/fread
- fwrite函数用于将数据块从内存写入到文件中。
- 函数原型:size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream)
- ptr是指向要写入的数据块的指针。
- size是每个数据项的大小(以字节为单位)。
- count是要写入的数据项的数量。
- stream是要写入的文件指针。
- 函数返回值是成功写入的数据项数量。

- fread函数用于从文件中读取数据块到内存中。
- 函数原型:size_t fread(void *ptr, size_t size, size_t count, FILE *stream)
- ptr是指向要存储读取数据的内存块的指针。
- size是每个数据项的大小(以字节为单位)。
- count是要读取的数据项的数量。
- stream是要读取的文件指针。
- 函数返回值是成功读取的数据项数量。
读取的字符会存储在str指向的字符数组中,直到达到上述条件为止。如果成功读取到字符串,则会在字符串的末尾添加一个空字符(\0)作为字符串的结束符。

fgets函数返回一个指向str的指针,如果成功读取到字符串,则返回str的值;如果读取失败或到达文件末尾,则返回NULL。

fgets函数相对于其他输入函数(如gets)更安全,因为它可以指定要读取的最大字符数,避免了缓冲区溢出的风险

fputs

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

fputs函数接受两个参数:

1. str:要写入文件的字符串。它是一个指向字符数组的指针,通常使用字符串常量或字符数组作为参数。
2. stream:文件指针,指定要写入的文件。

fputs函数的返回值是一个非负整数,表示成功写入的字符数。如果发生错误,返回值为EOF。

使用fputs函数时,它会将字符串写入到指定的文件中。写入的过程是将字符串中的字符逐个写入文件,直到遇到字符串的结束符\0。

 

7、fseek

fseek函数用于在文件中移动文件指针的位置。它的原型如下:

fputs(char *str, k);

其中,str是一个字符数组,存储了字符串。k是一个文件指针,指向要写入的文件。

通过调用fputs函数,时间字符串将被写入到文件中。注意,fputs函数只写入字符串本身,不会自动添加换行符或其他字符。如果需要换行,需要在字符串中显式地添加换行符。

在写入完成后,可以通过调用fflush函数手动刷新缓冲区,确保数据被写入到文件中。


stream是文件指针,offset是偏移量,whence是起始位置。

offset表示要移动的字节数,可以是正数、负数或零。正数表示向文件末尾方向移动,负数表示向文件开头方向移动,零表示不移动。

whence参数用于指定起始位置,有以下三个常量可选:
- SEEK_SET:从文件开头开始计算偏移量。
- SEEK_CUR:从当前位置开始计算偏移量。
- SEEK_END:从文件末尾开始计算偏移量。

具体解释如下:
- 当whence为SEEK_SET时,offset表示从文件开头开始的偏移量。
- 当whence为SEEK_CUR时,offset表示从当前位置开始的偏移量。
- 当whence为SEEK_END时,offset表示从文件末尾开始的偏移量。

fseek函数的返回值为0表示成功,非零值表示失败。

例如,要将文件指针移动到文件开头,可以使用以下代码:

fseek(stream, 0, SEEK_SET);

这将把文件指针的位置设置为文件的开头。

要将文件指针移动到文件末尾,可以使用以下代码

fseek(stream, 0, SEEK_END);

代码示例:获取时间戳写入time.conf文件

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
int main()
{
    time_t currentTime;
    struct tm *localTime;
    char arr[100];

    FILE *m = fopen("time.conf", "a+");
    if (NULL == m)
    {
        perror("fopen:");
        return -1;
    }
    int i = 0;
    fseek(m, 0, SEEK_SET);
    while (NULL != fgets(arr, 50, m))
    {
        i++;
    }

    FILE *k = fopen("time.conf", "w+");
    if (NULL == k)
    {
        perror("fopen:");
        return -1;
    }

    while (1)
    {
        // 获取当前系统时间
        currentTime = time(NULL);

        // 将时间转换为本地时间
        localTime = localtime(&currentTime);
        // 定义一个时间字符数组用于存储时间。
        char time[50];

        printf("current time:%d:%02d:%02d:%02d:%02d:%02d\n", localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday, localTime->tm_hour, localTime->tm_min, localTime->tm_sec);
        // 此处的换行符不会导致缓存区刷新,因为fopen打开的缓存方式默认为全缓存模式,需要手动刷新缓存区
        // 此处的刷新方式有三种
        // 1. 当缓冲区满时,会自动刷新。
        // 2. 当文件被关闭时,会自动刷新。
        // 3. 当程序正常结束时,所有打开的文件都会被关闭,因此也会刷新缓冲区。
        // 4. 可以通过调用fflush函数手动刷新。
        sprintf(time, "%d.%d-%02d-%02d %02d:%02d:%02d%c", i, localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday, localTime->tm_hour, localTime->tm_min, localTime->tm_sec, '\n');
        fputs(time, k);
        fflush(k);
        sleep(1);
        i++;
        memset(time, 0, sizeof(time));
    }

    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值