Skip to content

文件输入/输出

约 1522 个字 93 行代码 预计阅读时间 6 分钟

文本模式和二进制模式

文本模式中,可以访问文件的每一个字节,并且把它解释为字符

二进制模式中,可以访问文件的每一个字节,但不解释它

I/O的级别

I/O的级别有两种:

  1. 低级I/O: 直接访问文件系统,不经过缓冲区,速度快,但不安全
  2. 高级I/O: 经过缓冲区,速度慢,但安全

标准文件

C程序会自动打开三个文件

  1. stdin: 标准输入,默认从键盘输入
  2. stdout: 标准输出,默认输出到屏幕
  3. stderr: 标准错误输出,默认输出到屏幕

一个例子

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char *argv[] )
// 程序入口,argc为命令行参数个数,argv为参数数组
// 其中argv[0]是程序名,argv[1]是输入文件名,argv[2]是输出文件名(但此程序没有使用输出文件)
 {
  int ch;
  File *fp;
  unsigned long count = 0;
  if (argc!= 2) {
    printf("Usage: %s input_file output_file\n", argv[0]);// 判断命令行参数的个数是否为2(包括程序名,输入文件名
    return 1;
  }
  if ((fp = fopen(argv[1], "rb")) == NULL) {// 尝试以二进制只读模式打开输入文件(argv[1]为输入文件名)
    printf("Can't open input file %s\n", argv[1]);
    return 1;
  }
  while ((ch = fgetc(fp)) != EOF) {//上面已经打开了文件,这里直接使用fp指针来读取文件内容
    // 处理文件内容
    if (ch == 'a') {
      count++;
    }
  }
  fclose(fp);
  // 关闭文件,输出结果
  printf("There were %lu 'a's in the file.\n", count)

  return 0;
}

标准I/O

标准I/O包对于专门函数简化了处理不同io的问题,并且输入和输出都是缓冲的,给了人们一种自己逐字符访问的错觉,

文件指针

FILE *fp;, 指向一个FILE结构体,用来保存文件相关信息

File是一个结构体,包含了文件指针,文件位置,缓冲区,文件状态等信息


打开文件

C
#include <stdio.h>

int main() {
    FILE *fp;
    fp = fopen("test.txt", "r"); // 打开文件test.txt,以读模式打开
    if (fp == NULL) {
        printf("打开文件失败\n");
        return -1;
    }
    // 读文件内容
    char c;
    while ((c = fgetc(fp))!= EOF) {
        printf("%c", c);
    }
    fclose(fp); // 关闭文件
    return 0;
}

fopen()函数打开文件,第一个参数是文件名,第二个参数是打开模式,有"r"、"w"、"a"、"r+"、"w+"、"a+"等

成功打开文件之后,返回一个指向FILE结构体的指针,失败返回NULL

其中r表示读取,w表示写入,a表示追加,r+表示读写,w+表示读写,如果文件依据存在则会被截断成0长度,不存在就创建新的

a+表示读写,不存在创建新的,存在的话就读取可以从开头开始读,但是写入只能是追加模式写入

getc()putc()

getc()函数从文件中读取一个字符,返回EOF表示文件结束

putc()函数向文件中写入一个字符,这两个和getchar()和putchar()类似

注意

不同之处在于,要告诉fget()putc()函数使用哪一个文件,例如getc(fp)putc(ch,fp)

putc()函数第二个参数是文件指针,第一个参数是要写入的字符

getc()函数是从fp制定的文件中获取一个字符


文件结尾

当读到文件结尾时,getc()函数返回EOF,fgetc()函数返回EOF

为了避免读到空文件,应该在入口条件循环,在进入循环体中先尝试读取,如果返回EOF,则表示文件结尾,可以退出循环

C
1
2
3
while ((c = fgetc(fp))!= EOF) {
    // 处理文件内容
}

关闭文件

fclose()函数关闭文件,释放资源

C
fclose(fp);

还应该检查是否成功关闭文件,如果失败,应该打印出错误信息

C
1
2
3
if (fclose(fp)!= 0) {
    printf("关闭文件失败\n");
}

指向标准文件的指针

指针 指向 设备
stdin 标准输入 键盘
stdout 标准输出 屏幕
stderr 标准错误输出 屏幕

这些都是指向FILE的指针,所以可以用作创建标准I/O函数的参数,例如fclose(fp)中的fp


文件IO函数

fprintf()fscanf()函数

fprintf()函数用来向文件输出格式化字符串,fscanf()函数用来从文件读取格式化字符串

C
#include <stdio.h>

int main() {
    FILE *fp;
    fp = fopen("test.txt", "w"); // 打开文件test.txt,以写模式打开
    if (fp == NULL) {
        printf("打开文件失败\n");
        return -1;
    }
    int age = 25;
    char name[] = "Alice";
    fprintf(fp, "My name is %s, and I am %d years old.\n", name, age); // 输出格式化字符串
    fclose(fp); // 关闭文件
    return 0;
}
  1. fprintf()函数的第一个参数是文件指针,第二个参数是格式化字符串,后面的参数是要输出的变量或值
  2. fscanf()函数的第一个参数是文件指针,第二个参数是格式化字符串,后面的参数是要读取的变量的地址
C
#include <stdio.h>

int main() {
    FILE *fp;
    fp = fopen("test.txt", "r"); // 打开文件test.txt,以读模式打开
    if (fp == NULL) {
        printf("打开文件失败\n");
        return -1;
    }
    char name[10];
    int age;
    fscanf(fp, "My name is %s, and I am %d years old.\n", &name, &age); // 读取格式化字符串
    printf("My name is %s, and I am %d years old.\n", name, age); // 输出读取结果
    fclose(fp); // 关闭文件
    return 0;
}

rewind()函数

rewind()函数用来将文件指针指向文件开头

C
rewind(fp);

可以在fscanf()函数结束之后,使用rewind()函数将文件指针指向文件开头,再次读取文件内容

fgets()fputs()函数

fgets()函数用来从文件中读取一行字符串,并存入缓冲区,fputs()函数用来向文件写入一行字符串

fgets()函数的第一个参数是存储字符串的地址,第二个的取出字符串的最大长度(包括结尾加的'\0'),第三个是文件指针,从键盘输入就是stdin

fputs()只有两个int参数,第一个是要写入的字符串地址,第二个是文件指针,向屏幕输出就是stdout,可以自定义自定目标文件


写入文件:

int fputc(int c, FILE *fp);是把字符写入到流中最简单的函数,函数fputc()把参数c的字符串写入到fp所指向的输出流中,如果写入成功就会返回写入的字符,发生错误就会返回EOF

文件中发生错误都会返回EOF

可以使用下面的函数来吧一个以null结尾的字符串写入到流中

int fputs(const char *s, FILE *fp);

fputs()第一个参数可以是字符串的首地址,也可以是一个字符

我们也可使用fprintf(FILE *fp,const char *format,...)函数来吧该字符串写入到文件上

例如

C
fputs(S, fp);

等价于

C
fprintf(fp, "%s", S);

写入成功返回一个非负值,写入失败就返回一个EOF


读取文件

从文件中读取单个字符最简单的方式就是

int fgetc(FILE *fp);

表示的是fgets()函数从fp所指向的输入文件中读取一个字符,返回值是读取的字符,如果发生错误就返回EOF

下面的函数可以让我们读取一个字符串

char *fgets(char *s, int n, FILE *fp);

fgets()函数从fp所指向的输入流中读取n-1个字符,把读取的字符复制啊到缓冲区buff,并且在最后追加一个null字符来终止字符串

如果这个字符读取最后一个字符之前就遇到了一个换行符或者文件的末尾EOF,则只会返回读取到的字符,报考换行符

也可以用

int fscanf(FILE *fp, const char *format,...);

来读取字符串,当遇到第一个空格和换行符的时候会停止读取

fgets可以逐行读取直到读到末尾的EOF,fscanf可以读取到空格和换行符之间的字符,一般拿来逐个单词读取

C
char str[100];
fgets(str, 100, fp);

等价于

C
1
2
3
char str[100];
fgets(str, 100, fp);
str[strcspn(str, "\n")] = '\0';