当前位置: 首页 > news >正文

文件IO之标准IO

标准IO

我们是知道系统IO是挺好用。但是在不同操作系统下面,对文件一些管理和API接口都是不一样的。同一 个文件,在不同的操作系统下面, 操作文件的代码其实不一样的。C/C++几乎支持所有的操作系统、使 用C/C++操作文件(系统IO)可移植性非常差。于是C/C++语言标准委员会指定/统一文件操作的接口: 标准IO

标准IO是ANSI C建立的一个标准I/O模型,不依赖系统内核,因此具有良好的移植性。它提供了一系列用 于文件输入输出的函数。

标准IO是建立在系统调用IO之上的高级抽象。标准IO通过封装系统调用IO的底层细节,提供了一套更为 简便和易用的接口,这些函数在内部通过缓冲机制来优化性能,并减少直接对系统调用的次数。

标准IO通过缓冲机制来提高I/O操作的效率。**缓冲是一种技术,**它通过在内存中开辟一块区域(称为缓冲 区)来暂时存放输入或输出的数据,以减少对底层设备(如硬盘、终端等)的直接访问次数,从而提高 I/O操作的效率

缓冲的优点

  • 提高性能

    • 缓冲可以减少系统调用的次数。每次系统调用都会带来一定的开销。通过缓冲,可以将多个小

      的I/O请求合并成较大的请求,从而减少系统调用的次数,提高性能。

    • 缓冲还可以减少磁盘I/O的次数。磁盘I/O操作比内存操作慢得多,通过缓冲可以将多个写操作

      合并到一次磁盘I/O中,从而减少磁盘I/O的次数,提高数据写入的速度。

  • 平滑I/O需求峰值

    • 缓冲可以用来平滑I/O需求峰值。当I/O设备(如打印机、磁盘等)的负载较高时,通过缓冲可

      以暂时存储待处理的数据,等待设备负载降低后再进行处理,从而避免数据丢失或处理延迟。

  • 提高数据一致性

    • 在某些情况下,如数据库操作中,缓冲可以用来确保数据的一致性。通过先将数据写入缓冲

      区,再统一刷新到磁盘上,可以避免因系统崩溃等原因导致的数据不一致问题。

  • 简化编程

    • 标准IO库提供了丰富的缓冲机制,使得程序员在进行I/O操作时无需关心底层的缓冲细节,从 而简化了编程工作。

缓冲分为三种类型:全缓冲、行缓冲和无缓冲。用户可以通过setbuf 、 setvbuf 或 setbuffer 来设置文件流的缓冲类型。

全缓冲:当缓冲区满时,或者当调用fflush 函数、文件被关闭、或程序正常结束时,缓冲区的内容会被全部写入到文件中。

行缓冲:遇到换行符(\n)时,或者当缓冲区满时,或者当调用 fflush 函数、文件被关闭、或程序 正常结束时,缓冲区的内容会被写入到文件中。( printf :行缓冲

无缓冲:每次读写操作都直接对文件进行,不使用缓冲区。

编译器怎么区分标准IO应该调用Linux的系统还是还是Window的系统IO呢?

每个操作系统定义一个宏,在使用条件编译(#ifdef #endif,不同的操纵系统执行不同的宏

例如:

  • Windows:通常会定义 _WIN32_WIN64 宏。
  • Linux:通常会定义 __linux__ 宏。
  • macOS:通常会定义 __APPLE____MACH__

1 标准IO流

在Linux中,IO流(Input/Output Stream)指的是一种用于数据输入和输出的机制。这里的“流”可以理
解为一种连续的数据序列,可以是字节流或字符流,用于在程序的不同部分之间、程序与外设(如磁
盘、网络等)之间传输数据。
Linux中的IO操作主要涉及对文件的读写操作,而文件在Linux中被视为一种特殊的资源,可以是磁盘上
的普通文件、目录、字符设备(如终端)、块设备(如硬盘)等。因此,IO流在Linux中主要指的是对
这些文件资源的读写操作流

Linux中的IO流可以分为以下几种类型:

  • 标准IO流:

    在标准IO库下面,系统会为程序自动打开三个标准IO流,它们分别是:

    • 标准输入流FILE *stdin):

      • 定义在<stdio.h> 头文件中,通常指向**标准输入设备(**如键盘)。
      • 用于从标准输入设备读取数据。
      • 在UNIX和类UNIX系统中,其文件描述符为STDIN_FILENO(通常为0)(例如scanf函数)
    • *标准输出流( FILE stdout)

      • 同样定义在<stdio.h> 头文件中,通常指向标准输出设备(如显示器或终端)。
      • 用于向标准输出设备输出(写入)数据。
      • UNIX和类UNIX系统中,其文件描述符为STDOUT_FILENO(通常为1)。( 例如printf 函数)
    • *标准错误输出流( FILE stderr):

      • 也定义在<stdio.h> 头文件中,用于向标准错误输出设备输出数据(通常也是显示器或终端,但可以与 标准输出分开显示,以便于区分错误信息)。
      • 在UNIX和类UNIX系统中,其文件描述符为STDERR_FILENO通常为2)。(例如perror 函数 )
  • 网络IO流

    • 网络IO流是指在网络通信过程中,数据在客户端和服务器之间传输的流。在Linux中,网络IO流通常是
      通过套接字(Socket)编程接口来实现的。
      网络IO流涉及到数据的发送和接收操作,这些操作可以通过系统调用(如
      sendrecv等或更高级的网络编程库(如libevent、libev等)来完成。
  • 其他类型的IO流:
    除了其他三种常见的IO流之外,Linux还支持其他类型的IO流,如管道(Pipe)、命名管道(Named
    Pipe)、消息队列(Message Queue)等。这些IO流提供了不同的数据传输方式和同步机制,以满足不
    同场景下的需求。

  • 文件IO流:

文件IO流是通过Linux系统调用(如 open 、 read 、 write 、 close 等)直接对文件进行操作的一种机 制。与标准IO流不同,文件IO流不经过C语言标准库的缓冲机制,因此每次调用系统调用都会直接操作 底层设备(比较慢)。

文件IO流提供了更底层的控制能力**,允许程序员直接管理缓冲区的大小、位置等参数**,从而实现更高效 的IO操作。 在Linux中,文件类型主要可以分为两大类,即普通(文本)文件和二进制文件(在此分类中,我们排除 设备文件等特殊类型)。

  • 文本文件:无组织、无格式的文件、以字符的ASCII来解析文件。

    • 例如.cpp、.c、.txt、.cs、.html、.java、.py...文件
  • **二进制文件:**有特定格式的文件

    • 需要按照特定的文件格式解析
    • 某一些字节可能代表特殊含义
    • 例如.exe、.out、.apk、.jpg、.mp4、.doc、.xls...文件

1.1 打开文件流

fopen 函数是C语言标准库(stdio.h提供的一个用于打开文件的函数。这个函数通过指定文件名和模 式(如只读、只写、读写等),来打开文件,并返回一个指向 FILE 文件操作,如读写文件

fopen 函数的原型如下:

#include <stdio.h>  
FILE *fopen(const char *path, const char *mode);
  • 参数

path 参数指定了要打开文件的路径和名称。
mode 参数指定了文件的打开模式
"r" 表示只读打开,
"w" 表示只写打开(如果文件已存在则覆盖),
"a" 表示追加写入(文件不存在则创建)
"r+" 读写模式。文件必须存在。文件指针将放在文件的开头。允许读取和写入操作。
"w+" 读写模式。如果文件存在,其长度将被截断为零(即文件内容会丢失)。如果文件不存在,则创
建新文件。文件指针将放在文件的开头。允许读取和写入操作。
"a+" 读写模式。如果文件存在,写入的数据将被追加到文件末尾。如果文件不存在,则创建新文件以
写入数据

如果是二进制文件还可以在上述模式前添加字符 “b”,如"rb" , "r+b"

  • 返回值
    • 如果文件成功打开,fopen函数将返回一个指向 FLLE结构体的指针。
    • 如果文件打开失败(例如,由于权限问题或路径不存在),则返回NULL;
    • FILE 结构体是C标准I/O库中定义的一个结构体类型,用于表示一个流(stream)。通过这个指针,程 序可以访问和操作打开的文件。

1.2 关闭文件流

fclose 函数是 C 语言标准输入输出库(stdio.h)中的一个函数,用于关闭一个打开的文件。当文件不
再需要被访问时,应该使用fclose函数来关闭它。关闭文件是一个好习惯,因为它可以释放文件相关
的资源,并确保所有缓冲的输出都被正确地写入文件中。

函数原型如下:

int fclose(FILE *stream);

参数

FILE *stream 是指向 FILE 对象的指针,该对象标识了要关闭的文件。这个指针是之前通过调用如 freopen 或 fdopen 等函数打开文件时返回的。

返回值:

如果成功关闭文件,fclose函数返回 0。如果发生错误,则返回 EOF(通常定义为 -1,但这是一个 宏,在不同的环境中可能有所不同)。然而,请注意,尽管 fclose 在关闭文件时可能会遇到错误(如 写错误),但它在大多数情况下都能成功关闭文件,即使返回了EOF

示例

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fd = fopen("text.txt", "a+");// 失败if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");// 关闭文件fclose(fd);return 0;
}

fclose在文件关闭的时候,会同步缓冲区的内容到硬件中

1.3 文件流读取

  • fgets函数

fgets 函数是 C 语言标准输入输出库(stdio.h)中的一个函数,用于从指定的文件流(或标准输入, 即键盘输入)中读取一行文本。这个函数会读取直到遇到**换行符( '\n' )、文件结束符(EOF)或已读 取了指定数量的字符(**不包括最后的空字符 '\0' ,该函数会自动在字符串末尾添加这个空字符作为字 符串的结束标志)为止的文本。

函数原型如下:

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

    • str 是一个指向字符数组的指针,该数组将存储从文件中读取的字符串。

    • n 是要读取的最大字符数(包括最后的空字符 stream 是一个指向 '\0' )。因此,如果希望字符串包含最多n-1个字符, 应该将这个值作为n的参数。

    • FILE 对象的指针,该对象指定了要从中读取数据的文件流。如果 stream 是 stdin ,则函数将从标准输入读取数据。

  • 返回值

    • 如果成功,fgets会返回指向 str 的指针。

    • 如果到达文件末尾或发生错误,则返回 NULL 。

    • 需要注意的是,即使成功读取了换行符,它也会被存储在字符串中,并且会在换行符之后添加一个空字 符'\0'来结束字符串。

示例

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fd = fopen("text.txt", "a+");// 失败if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");// /为存储缓冲区,用于临时存储读取的文件内容。char buffer[256] = {0};// 从文件读取fgets(buffer, sizeof(buffer) - 1, fd);printf("%s", buffer);// 从标准输入读取fgets(buffer, sizeof(buffer) - 1, stdin);printf("%s", buffer);// 关闭文件fclose(fd);return 0;
}只读取一行文本
  • fread函数

fread 函数是 C 语言标准输入输出库(stdio.h)中用于从文件流(或其他输入流)中读取数据块的函 数。与 fgets不同,fread 不会解析数据,而是按照指定的字节数直接从流中读取数据到内存缓冲区 中。这使得 fread 非常适合于读取二进制文件或需要精确控制读取数据大小的情况。

函数原型如下:

 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    • 参数
      • ptr 是指向内存缓冲区的指针,该缓冲区用于存储从文件流中读取的数据。
      • size 是每个数据项的大小(以字节为单位)。
      • nmemb 是要读取的数据项的数量。
      • stream 是指向 FILE 对象的指针,该对象指定了要从中读取数据的文件流。
    • 返回值
      • fread 函数返回成功读取的数据项的数量。如果遇到文件末尾或发生错误,则可能返回小于nmemb
        值。在成功读取的情况下,返回的值乘以 size 等于实际读取的字节数。

例子

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fd = fopen("text.txt", "a+");// 失败if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");// /为存储缓冲区,用于临时存储读取的文件内容。char buffer[256] = {0};// 从文件读取fread(buffer,1 ,100, fd);printf("%s", buffer);// 关闭文件fclose(fd);return 0;
}
读取文件全部内容
  • fcanf函数

    fscanf 函数是C语言标准输入输出库(stdio.h)中的一个重要函数,用于从文件流中读取格式化的输 入数据。fscanf函数根据指定的格式字符串从文件流中读取数据并将读取到的数据存储到提供的变量中。它会在遇到空格、制表符或换行符时停止读取当前字段。

    函数原型如下:

     int fscanf(FILE *stream, const char *format, [argument...]);
    
    • 参数(和scanf函数参数一样)

      • stream:指向FILE对象的指针,该FILE对象标识了要从中读取数据的文件流。

      • format:一个字符串,定义了要读取的数据的类型和格式。它包含格式说明符、空格字符、非空字符等,用于指定如何解析输入流中的数据

      • [argument...]:可变参数列表,用于存储从文件中读取的数据。这些参数的类型和数量应该与format字符串中指定的格式说明符相匹配(要是地址)。

    • 返回值

      • fscanf函数返回成功匹配并赋值的数据项数。如果到达文件末尾或发生读取错误,则返回EOF(通常 是-1)。因此,可以通过检查返回值来判断是否成功读取了预期数量的数据项

例子

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fd = fopen("text.txt", "a+");// 失败if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");// // 定义存储日期的变量int year;int month;int day;// 循环从文件中读取日期数据while (fscanf(fd, "%d:%d:%d", &year, &month, &day) == 3){// 格式化输出读取的日期printf("读取的数据是:%04d:%02d:%02d\n", year, month, day);}// 关闭文件fclose(fd);return 0;
}
//根据指定的格式字符串从文件流中读取数据

结果是

打开成功
读取的数据是:2025:05:06
读取的数据是:2025:05:07
读取的数据是:2025:05:08
读取的数据是:2025:05:09
读取的数据是:2025:11:12

1.4 文件流写入

  • fputs函数

    函数原型如下:

     int fputs(const char *s, FILE *stream)
    
    • 参数:
      • s:指向要写入文件的字符串的指针。
      • stream:指向 FILE 对象的指针,该对象标识了要写入的文件流。
    • 返回值
      • 如果成功,fputs 返回非负值。
      • 如果发生错误,则返回 EOF
      • 但是,请注意,在大多数情况下,fputs 不会在遇到错误时立即返回 EOF,除非底层 I/O 操作失败 (例如,磁盘空间不足)。

示例

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fd = fopen("text.txt", "w+");// 失败if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");if(fputs("hello world!\n", fd) == EOF){perror("fputs");}printf("%s\n",  "写入成功" );// 关闭文件fclose(fd);return 0;
}

EOF是什么类型?

EOF 是一个宏,它在 C 语言中定义在 <stdio.h> 头文件中。EOF 代表**“End Of File”(文件结束**),它是一个整型值(int),通常被定义为 -1。

  • fwrite函数

fwrite 函数是 C 语言标准输入输出库(stdio.h)中的一个函数,用于向文件写入数据块(数组中的元 素)。与 fputs 不同,,fwrite 不关心数据的具体内容(如字符串或格式化文本),而是将内存中的一 块连续区域(通常是数组)直接写入到文件中。这使得rwrite 特别适合于二进制文件的写入 ,但也可以用于文本文件的写入。

使用fwrite 时,你需要指定每个数据项的大小( size )和要写入的数据项数(nmemb )( 才能函数正确地计算要写入的总字节数。

函数原型如下:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 参数

    • ptr:指向要写入的数据块的指针。

    • size :每个数据项的大小,以字节为单位。

    • nmemb :数据项的个数。

    • stream :指向 FILE 对象的指针,该对象标识了要写入的数据的目标文件流。

  • 返回值

    • 成功时,返回写入的完整项数(即 nmemb 的值,如果所有项都被成功写入)。

    • 如果发生错误或到达文件末尾之前写入的项数少于 nmemb,则可能返回一个小于

    • 如果 size 或 nmemb 为 0,则函数不执行任何操作,并返回 0。

示例

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fd = fopen("text.txt", "a+");// 失败if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");int number[5] = {1, 2, 3, 4, 5};// size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);fwrite(number, sizeof(int), sizeof(number)/sizeof(int), fd);// 关闭文件fclose(fd);fd = fopen("text.txt", "r+");if(fd == nullptr){perror("fopen");return -1;}printf("%s\n", "第二次打开成功");fread(number, sizeof(int), sizeof(number)/sizeof(int), fd);for(int i = 0; i < 5; i++){printf("%d ",number[i]);}printf("\n");// 关闭文件fclose(fd);return 0;
}
  • 为什么fwrite写入的内容系统使用二进制保存了

    • write 写入的内容本身是原始的字节序列。系统不会自动在文件末尾添加一个 EOF(文件结束符)作为结尾。实际上,EOF 并不是一个实际存储在文件中的特殊字符,而是在文件读取操作中,由程序或标准库函数生成的一个信号,用于指示文件的结束。
    • 由于 fwrite 不会对写入的数据进行文本模式的解析和处理(如换行符转换等),因此写入的内容会被系统以二进制形式保存。当文件被读取时,系统会根据读取方式(如文本模式或二进制模式)来解析这些原始字节序列
  • fprintf 函数

fprintf 函数是 C 语言标准输入输出库(stdio.h)中的一个函数,用于向文件流写入格式化的数据。

函数原型如下:

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

stream :指向 FILE 对象的指针,该对象标识了要写入的文件流。

format :一个格式字符串,指定了后续参数如何被格式化和插入到输出流中。这个字符串可以包含普 通字符(这些字符会被直接复制到输出流中),以及格式说明符(这些说明符被后续参数的值替换)。

... :表示可变数量的额外参数,这些参数将根据 format字符串中的格式说明符进行格式化,并插入到输出流中。

  • 返回值

成功时,format字符串中的格式说明符进行格式化(不包括末尾的空字符 ‘\0’)。

如果发生错误,则返回负值。

例子

#include <stdio.h>int main()
{// FILE类型的指针接受fopen的返回植FILE *fp = fopen("text.txt", "a+");// 失败if(fp == nullptr){perror("fopen");return -1;}printf("%s\n", "打开成功");int number = 123;float pi = 3.1415926;const char *text = "sdkklsfs";// 向文件写入格式化数据fprintf(fp,"%d\n", number);fprintf(fp,"%f\n", pi);fprintf(fp,"%s\n", text);fclose(fp);return 0;
}

2.缓冲区操作

2.1 冲洗一个文件流

冲洗流: fflush 主要作用就是同步文件。(把缓冲区中的内容同步中硬件中)

标准IO带缓冲的IO,读写时候针对与缓冲区,并不是每次都是操作硬件

有的时候多线程编程的时候会影响到程序结果。

函数原型

 #include <stdio.h>
int fflush(FILE *stream);

描述:

强制给所在的输出流或是更新流(stream)上,写入在用户空间缓冲的所有数据,使用底层写 流的打开状态是不受影响的。 如果stream是NULL,fflush刷新所有打开的流。

  • 参数
    • @stream 需要刷新的文件流指针
  • 返回值
    • 成功返回0
    • 失败返回EOF,同时errno被设置

示例

#include <iostream>
using namespace std;
int main()
{FILE *fp =fopen("text.txt", "r+");if(fp == nullptr){perror("文件打开失败");return -1;}cout << "打开文件成功" << endl;// fputs("12345670123", fp);fwrite("2233", 1,10, fp);fflush(fp);//冲刷指定的文件流,会同步缓存区的内容到硬件getchar();fclose(fp);return 0;}
  • 为什么要定义变量或者动态内存分配要使用初始化

    • 当你定义变量或分配动态内存时,系统会分配一块内存空间给你。在这之前,这块内存可能存储着之前程序留下的旧数据(脏数据)。

    • 如果不初始化,变量或动态分配的内存可能包含未知的垃圾值。这些垃圾值是不可预测的,使用它们可能导致程序行为异常。

  • 缓冲区和文件同步后,缓冲区的内容通常不会被自动清空。这意味着如果你继续写入数据,新的数据会追加到缓冲区的末尾 ,只有关闭文件或者重新分配缓冲区缓冲区被覆盖或重置

2.2缓冲区策略

标准IO缓冲区有三种类型:

  • 行缓冲缓冲区数据只要达到一行了就会同步到外设(硬盘)上面。假设一行最多80字节,当一行

    满了80字节或者遇到\n的时候就会把缓冲区的数据同步到外设上。

    • printf :行缓冲

    • 当一行数据满了就同步。

    • 一行没满,但是遇到换行符也同步。

    • 当一行没满,也没有换行符,程序在正常退出的时候也会同步。

  • 全缓冲:只有当缓冲区的数据满了之后,才会同步到外设上面。

  • 无缓冲:只要缓冲区有一个字节,就会同步到外设上。

函数原型

 #include <stdio.h>void setbuf(FILE *stream, char *buf);void setbuffer(FILE *stream, char *buf, size_t size);void setlinebuf(FILE *stream);// 上面三个函数的功能它都有int setvbuf(FILE *stream, char *buf, int mode, size_t size);//用它就行

描述:

 设置缓冲策略的。        **有三种类型的缓冲策略,它们是无缓冲,块缓冲和行缓冲**。当输出流无缓冲时,信息在写 的同时出现于目标文件或终端上;当是块缓冲时,字符被暂存,然后一起写入;当是行缓 冲时,字符被暂存,直到要输出一个新行符,或者从任何与终端设备连接的流中 (典型的 是 `stdin`)  读取输入时才输出。

函数 fflush(3 可以用来强制提前输出。(参见 fclose(3)) 通常所有文件都是块缓冲的。当文件 I/O 操作在文件上发生时,将调用 malloc(3) ,获 得一个缓冲。 如果流指向一个终端 (通常 stdout 都是这样),那么它是行缓冲的。标准 错误流 stderr 默认总是无缓冲的。

  • 参数:

    • @stream 需要设置缓冲区策略的文件流指针

    • @buf 缓冲区指针,如果使用系统缓冲区,那么填null \

      注意!!!!!!!!!!!!!!!!!!!!!! buf必须要是在文件流关闭之前,以及程序结束之前它的空间都应该要有效(也就是从文 件流开始到程序结束该段空间都不能被释放)

    • @mode 缓冲策略 参数mode 必须是以下宏值

      • _IONBF 无缓冲

      • _IOLBF 行缓冲

      • _IOFBF 全缓冲

    • @size 缓冲区的大小,如果使用系统缓冲区,那么填0

  • 返回值:

    • ​ 成功返回0

    • ​ 失败可能返回任意值

例子

#include <iostream>
using namespace std;
int main()
{// setvbuf(stdout, buf, _IONBF, sizeof(buf) - 1);//无缓冲printf("sdad6f66sfssss");while(1);//卡住return 0;}
输出
sdad6f66sfssss有多少输出多少
#include <iostream>
using namespace std;
int main()
{char buf[1024] = {0};//设置缓冲区setvbuf(stdout, buf, _IOLBF, sizeof(buf) - 1);//行缓冲printf("sdad6f66sfssss");cout << endl << buf ;while(1);//卡住return 0;}
输出
sdad6f66sfssss
sdad6f66sfssss

3 定位文件流

3.1 设置光标位置

上面有提到fread和fwrite…只是说明要从哪个文件读写,读写多少个,并没有指明,从哪个位置开 始。标准IO会为每一个打开的文件流,保存一个“文件偏移量

一般来说,每次读写之前,先确定光标(定位流)。

fseek就是用来定位文件流的光标的。

  • 函数原型
 #include <stdio.h>int fseek(FILE *stream, long offset, int whence);
  • 作用:

    fseek就是用来定位文件流的光标的。

    • stream:

    • 需要进行定位流的,文件流指针

    • offset:

      偏移量,结合第三个参数。

      • 负:表示向前偏移

      • 正:表示向后偏移

    • whence:

      • SEEK_SET 基于文件开头定位 新光标的位置=文件开头+offset(>=0)

      • SEEK_CUR 基于当前位置定位 新光标的位置=当前位置+offset(可正可负)

      • SEEK_END 基于文件末尾定位 新光标的位置=文件末尾+offset(可正可负)

  • 返回值:

    • 成功返回实际偏移的数量,
    • 失败返回-1,同时errno被设置

示例

include <iostream>
using namespace std;
int main()
{FILE *ftpr = fopen("text.txt","r");if(ftpr == nullptr){perror("打开失败");}char buf[1024] = {0};// 光标偏移fseek(ftpr, 12, SEEK_SET);// 读取文件fread(buf, 1 , 100 ,ftpr);cout << "内容:" << endl << buf << endl;return 0;}

3.2 获取光标偏移量

获取此时光标的偏移量是多少(也可以理解为此时已经从文件头移动了多少个字节的数据)

  • 函数原型
#include <stdio.h>long ftell(FILE *stream);
  • 作用:

ftell是用来计算当前光标到文件头的距离(有多少个字节)

  • 参数

    • stream: 需要统计开头到当前位置的字节数的,文件流指针。
  • 返回值

    • 成功返回文件头到当前位置的字节数,
    • 失败返回-1,同时errno被设置
#include <iostream>
using namespace std;
int main()
{FILE *ftpr = fopen("text.txt","r");if(ftpr == nullptr){perror("打开失败");}char buf[1024] = {0};// 光标偏移fseek(ftpr, 16 , SEEK_SET);// 读取文件fread(buf, 1 , 100 ,ftpr);if(ftell(ftpr) == -1){perror;("ftell");return -1;}cout << "偏移" << ftell(ftpr) << endl;cout << "内容:" << endl << buf << endl;fclose(ftpr);return 0;}

3.3 重置光标位置

  • 函数原型
#include <stdio.h>void rewind(FILE *stream);
  • 作用:

将光标定位到文件头

stream: 需要将光标定位到文件头,文件流指针

使用该函数等价fseek(stream,0,SEEK_SET)一样

#include <iostream>
using namespace std;
int main()
{FILE *ftpr = fopen("text.txt","r");if(ftpr == nullptr){perror("打开失败");}char buf[1024] = {0};// 光标偏移fseek(ftpr, 16 , SEEK_SET);// 读取文件fread(buf, 1 , 100 ,ftpr);// 重置光标位置if(ftell(ftpr) == -1){perror;("ftell");return -1;}rewind(ftpr);cout << "偏移" << ftell(ftpr) << endl;cout << "内容:" << endl << buf << endl;fclose(ftpr);return 0;}

4 文件出错/文件结束标志

EOFEnd Of File 文件结束的标志

标准IO库中,在读文件内容时候,如果读取到了末尾,会往缓冲区填入一个EOF(二进制:1111)

  • 函数原型
  #include <stdio.h>void clearerr(FILE *stream);
  • 描述:

    • 清除stream指向的流中文件结束标志和出错标志的
  • 参数

    • stream: 需要清除文件结束标志和出错标志的stream流
  • 函数原型

  int feof(FILE *stream);
  • 描述:

    • 测试指向流中的文件结束标志,如果已设置就返回
    • 用于判断文件指针是否已经到达文件末尾(EOF)
  • 参数:stream

    • 需要测试文件结束标志的流
  • 返回值: return:

    • 如果已设置就返回非0
    • 否则,返回 0

函数原型

 int ferror(FILE *stream);int fileno(FILE *stream);

示例

#include <iostream>
using namespace std;
int main()
{char buf[1] = {0};FILE *ftpr = fopen("text.txt","r");if(ftpr == nullptr){perror("打开失败");}clearerr(ftpr);while(!feof(ftpr)){fread(buf,1 ,1 ,ftpr) ;cout << buf;}cout << endl;fclose(ftpr);return 0;}

5.格式化的输入输出

格式化:按照特定格式进行输入/输出
分为两类参数

  • 格式化字符串

    • 告知用户按照哪种格式进行输入/输出,怎么输入/输出。

    • 格式化字符串中字符分为三类:

      • 非转义字符/普通字符

        • A B C … 1 2 3… ! ? , … 必须要按格式化中的样子输入。精准输入
      • 格式化字符

        • %d %s %c %f %o … 占位符,表示接收一个指定类型的数据

          • %d :表示接收一个整型数据

          • %s :表示接收一个字符串数据

          • %c :表示接收一个字符数据

          • %f :表示接收一个浮点数

          • %o :表示接收一个整型并以八进制形式打印

      • 转义字符

        • \n \t \a \x89 \0777 … 通过反斜杠转义的不是原含义的字符

        • 空白字符:\n \t \a \r …

        • 非空白字符:\x89 \0777 …

  • 参数

    • 要与格式化字符串中占位字符的类型和数量要一致

注意:格式化字符串中的每一个格式化字符,就对应一个地址,所以在输入的时候,参数要与格式化字 符的类型和数量相匹配,然后需要提供地址。

5.1 格式化输入

scanf/sscanf/fscanf...
scanf 什么时候结束输入?

  • scanfstdin 的缓冲区中获取输入

    • 当该输入的都输入完了。

      • scanf("abcd%d %cbcd",&a,&c);

      • abcd123Abcd

    • 用户输入失败

      • scanf(abcd%d %cbcd",&a,&c);

      • ABCD // scanf就会停止匹配,结束

        scanf 返回成功匹配到的变量个数。

  • fscanf函数

  • 函数原型:

#include <stdio.h>int fscanf(FILE *stream, const char *format, ...);
  • 作用: 从指定的来源,接受输入数据
  • 参数
    • stream: 输入源,文件流指针
    • format: 格式化字符串
    • …: 可变参数
#include <stdio.h>int fscanf(FILE *stream, const char *format, ...);/*
作用:
从指定的来源,接受输入数据
stream:
输入源,文件流指针
format:
格式化字符串
...:
可变参数
*/eg:
FILE *fp = fopen("1.txt"."r");int r a;char c;fscanf(fp,"%d%d%c",&r,&a,&c);
#include <iostream>
using namespace std;
int main()
{FILE *ftpr = fopen("2.txt","r+");if(ftpr == nullptr){perror("打开失败");}char name[20] = {0}; // 声明一个字符数组来存储姓名int age = 0;char sex[10] = {0}; // 声明一个字符数组来存储性别fscanf(ftpr,"name:%s age:%d sex:%s",name, &age, sex);cout << "name:" << name <<"age:" << age << "sex:" << sex << endl;}eg:
FILE *fp = fopen("1.txt"."r");int r a;char c;fscanf(fp,"%d%d%c",&r,&a,&c);

fscanf 读取文件内容的时候是不会主动偏移光标的。

  • sscanf函数
#include <stdio.h>int sscanf(const char *str, const char *format, ...);
  • 作用:

    • 从指定的来源,接受输入数据
  • 参数

    • str:输入源
    • format:格式化字符串
    • …: 可变参数
 eg:eg:
const char *str = "123456asdsa4564asd";int r a;char c;sscanf(str,"%d%d%c",&r,&a,&c);

5.2 格式化输出

fprintf函数

#include <stdio.h>int fprintf(FILE *stream, const char *format, ...);
 eg:
FIEL *fp = open("1.txt","r+");int a = 1,char c = 'a';fprintf(fp,"abc%d123%c\n",a,c):
  • 参数
    • stream: 需要输出到的文件流指针
    • format: 输出格式字符串
    • …: 参数

sprintf函数

#include <stdio.h>int sprintf(char *str, const char *format, ...);
  • 函数原型

    • str:需要输出到的字符指针。

    • format:输出格式字符串

    • …: 可变 参数**

 char buf[256]={0};int a = 1;char c = 'a';sprintf(buf,"%d-----%c",a,c);

示例

#include <iostream>
using namespace std;
int main()
{FILE *ftpr = fopen("3.txt","a+");if(ftpr == nullptr){perror("打开失败");}const char *name1 = " lisi";int age1 = 20;const char *sex1 = "woman";fprintf(ftpr,"name:%s:\nage:%d :\nsex:%s:\n", name1, age1, sex1);fclose(ftpr);return 0;}

6.关于C++中的标准库的使用

#include <fstream>ofstream         
//文件写操作 内存写入存储设备 
ifstream         
fstream          
//文件读操作,存储设备读区到内存中
//读写操作,对打开的文件可进行读写操作

fs tream 类中,成员函数 open() 实现打开文件的操作,从而将数据流和文件进行关联,通过 ofstream,ifstream,fstream 对象进行对文件的读写操作

函数:open()public member functionvoid open (const char * filename,ios_base::openmode mode = ios_base::in | 
ios_base::out );void open(const wchar_t *_Filename,ios_base::openmode mode= ios_base::in | 
ios_base::out,int prot = ios_base::_Openprot);
参数: filename  操作文件名mode     打开文件的方式prot     打开文件的属性               //基本很少用到,在查看资料时,发现有两种方式
ios::in 为输入()而打开文件
ios::out 为输出()而打开文件
ios::ate 初始位置:文件尾
ios::app 所有输出附加在文件末尾
ios::trunc 如果文件已存在则先删除该文件
ios::binary 二进制方式作业:
**将标准IO文件操作封装成一个类。**

相关文章:

  • Binary Prediction with a Rainfall Dataset-(回归+特征工程+xgb)
  • 入门OpenTelemetry——应用自动埋点
  • ColorAid —— 一个面向设计师的色盲模拟工具开发记
  • 多模态大语言模型arxiv论文略读(八十)
  • Git多人协作
  • SOLID 面对象设计的五大基本原则
  • Denoising Score Matching with Langevin Dynamics
  • 2_Spring【IOC容器中获取组件Bean】
  • 中级统计师-统计学基础知识-第四章 假设检验
  • 企业内部风险管理:人性化与技术并重
  • 浅谈迷宫类问题中的BFS和DFS
  • ctf 基础
  • [ctfshow web入门] web119
  • 软件设计师CISC与RISC考点分析——求三连
  • 算法加训之最短路 上(dijkstra算法)
  • <前端小白> 前端网页知识点总结
  • 10.13 LangChain工具调用实战:@tool装饰器+小样本提示,日处理10w+调用秘籍
  • 3Dmax中用RayFire实现破碎动画效果
  • 机器学习(13)——LGBM(2)
  • 用Colab启动Streamlit应用
  • 倒计时1天:走进“中国荔乡”茂名,探寻农交文旅商融合发展新模式
  • 殷墟出土鸮尊时隔50年首次聚首,北京新展“看·见殷商”
  • 视频丨为救心梗同学缺席职教高考的小伙姜昭鹏完成补考
  • 纽约市长称墨海军帆船撞桥已致2人死亡,撞桥前船只疑似失去动力
  • AG600“鲲龙”批生产首架机完成生产试飞
  • 武康大楼再开发:一栋楼火还不够,要带火街区“朋友圈”