C语言 文件操作

时间:2024-03-06 14:51:58

C语言 文件操作

文件概述

一、磁盘文件和设备文件

1、磁盘文件

指一组相关数据的有序集合,通常存储在外部介质(如磁盘)上,使用时才调入内存。

2、设备文件

在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文件的读和写。

二、磁盘文件的分类

计算机的存储在物理上是二进制的,所以物理上所有的磁盘文件本质上都是一样的:以字节为单位进行顺序存储。

 从用户或者操作系统使用的角度(逻辑上)把文件分为:

  • 文本文件:基于字符编码的文件
  • 二进制文件:基于值编码的文件

三、文本文件和二进制文件

1、文本文件

  • 基于字符编码,常见编码有ASCII、UNICODE等
  • 一般可以使用文本编辑器直接打开

数5678的以ASCII存储形式(ASCII码)为:

00110101 00110110 00110111 00111000

2、二进制文件

  • 基于值编码,自己根据具体应用,指定某个值是什么意思
  • 把内存中的数据按其在内存中的存储形式原样输出到磁盘上

 数5678的存储形式(二进制码)为:

00010110 00101110

文件打开和关闭

一、文件指针

在C语言中用一个指针变量指向一个文件,这个指针称为文件指针

typedef struct
{
       short           level;       //缓冲区"满"或者"空"的程度
       unsigned        flags;       //文件状态标志
       char            fd;          //文件描述符
       unsigned char   hold;        //如无缓冲区不读取字符
       short           bsize;       //缓冲区的大小
       unsigned char   *buffer;     //数据缓冲区的位置
       unsigned        ar;          //指针,当前的指向
       unsigned        istemp;      //临时文件,指示器
       short           token;       //用于有效性的检查
}FILE;

  FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型,结构中含有文件名、文件状态和文件当前位置等信息。

  声明FILE结构体类型的信息包含在头文件“stdio.h”中,一般设置一个指向FILE类型变量的指针变量,然后通过它来引用这些FILE类型变量。通过文件指针就可对它所指的文件进行各种操作。

C语言中有三个特殊的文件指针由系统默认打开,用户无需定义即可直接使用:

  • stdin: 标准输入,默认为当前终端(键盘),我们使用的scanf、getchar函数默认从此终端获得数据。
  • stdout:标准输出,默认为当前终端(屏幕),我们使用的printf、puts函数默认输出信息到此终端。
  • stderr:标准出错,默认为当前终端(屏幕),我们使用的perror函数默认输出信息到此终端。

二、文件打开

1、说明

任何文件使用之前必须打开:

#include <stdio.h>
FILE * fopen(const char * filename, const char * mode);

功能:打开文件
参数:

  • filename:需要打开的文件名,根据需要加上路径
  • mode:打开文件的模式设置

返回值:

  • 成功:文件指针
  • 失败:NULL

2、第一个参数的几种形式

FILE *fp_passwd = NULL;
 
//相对路径:
//打开当前目录passdw文件:源文件(源程序)所在目录
FILE *fp_passwd = fopen("passwd.txt", "r");
      
//打开当前目录(test)下passwd.txt文件
fp_passwd = fopen(". / test / passwd.txt", "r");
      
//打开当前目录上一级目录(相对当前目录)passwd.txt文件
fp_passwd = fopen(".. / passwd.txt", "r");
             
//绝对路径:
//打开C盘test目录下一个叫passwd.txt文件
fp_passwd = fopen("c://test//passwd.txt","r");

3、第二个参数的几种形式(打开文件的方式)

注意事项:

  • b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的
  • Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾
  • 在Windows平台下,以“文本”方式打开文件,不加b:
  • 当读取文件的时候,系统会将所有的 "\r\n" 转换成 "\n"
  • 当写入文件的时候,系统会将 "\n" 转换成 "\r\n" 写入
  • 以"二进制"方式打开文件,则读\写都不会进行这样的转换
  • 在Unix/Linux平台下,“文本”与“二进制”模式没有区别,"\r\n" 作为两个字符原样输入输出

打开模式

含义

r或rb

以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)

w或wb

以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a或ab

以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件

r+或rb+

以可读、可写的方式打开文件(不创建新文件)

r+或rb+

以可读、可写的方式打开文件(不创建新文件)

w+或wb+

以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a+或ab+

以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件

4、案例

#include <stdio.h>

int main(void)
{
       FILE *fp = NULL;
 
       // "\\"这样的路径形式,只能在windows使用
       // "/"这样的路径形式,windows和linux平台下都可用,建议使用这种
       // 路径可以是相对路径,也可是绝对路径
       fp = fopen("../test", "w");
       //fp = fopen("..\\test", "w");
 
       if (fp == NULL) //返回空,说明打开失败
       {
              //perror()是标准出错打印函数,能打印调用库函数出错原因
              perror("open");
              return -1;
       }
 
       return 0;
}
文件打开 使用案例

三、文件关闭

1、说明

任何文件在使用后应该关闭:

  • 打开的文件会占用内存资源,如果总是打开不关闭,会消耗很多内存
  • 一个进程同时打开的文件数是有限制的,超过最大同时打开文件数,再次调用fopen打开文件会失败
  • 如果没有明确的调用fclose关闭打开的文件,那么程序在退出的时候,操作系统会统一关闭。
#include <stdio.h>
int fclose(FILE * stream);

功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:

  • stream:文件指针

返回值:

  • 成功:0
  • 失败:-1

2、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 定义文件指针
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");
    
    // 判断文件是否打开成功
    // 1、找不到文件
    // 2、文件权限(读、写、执行)
    // 3、程序打开文件超出上限 65535
    if (fp == NULL)
    {
        printf("打开文件失败\n");
        return -1;
    }
    
    printf("文件打开成功:%p\n",fp);
    
    // 关闭文件指针
    fclose(fp);

    return 0;
}
文件关闭 使用案例

文件字符读写

一、写文件

1、说明

#include <stdio.h>
int fputc(int ch, FILE * stream);

功能:将ch转换为unsigned char后写入stream指定的文件中
参数:

  • ch:需要写入文件的字符
  • stream:文件指针

返回值:

  • 成功:成功写入文件的字符
  • 失败:返回-1

2、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 以写的方式打开文件、如果文件不存在则创建一个新文件、如果文件存在则清空内容
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "w");
    
    if (!fp)
    {
        printf("打开文件失败\n");
        return -1;
    }
    
    // 创建字符
    // char ch = \'a\';

    // 字符写入
    // 约束:if(value==-1)
    // fputc(ch, fp);
    
    // 通过键盘输入方式存字符
    char ch;
    while (1)
    {
        scanf("%c", &ch);
        // 输入@关闭文件
        if (ch == \'@\')
        {
            break;
        }
        fputc(ch, fp);
    }


    // 关闭文件
    fclose(fp);

    return 0;
}
fputc 使用案例

二、文件结尾

1、概述

  在C语言中,EOF表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~127,不可能出现-1,因此可以用EOF作为文件结束标志。

#define EOF     (-1)

  当把数据以二进制形式存放到文件中时,就会有-1值的出现,因此不能采用EOF作为二进制文件的结束标志。为解决这一个问题,ANSI C提供一个feof函数,用来判断文件是否结束。feof函数既可用以判断二进制文件又可用以判断文本文件。

2、说明

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

功能:检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。
参数:

  • stream:文件指针

返回值:

  • 非0值:已经到文件结尾
  • 0:没有到文件结尾

3、案例

三、读文件

1、说明

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

功能:从stream指定的文件中读取一个字符
参数:

  • stream:文件指针

返回值:

  • 成功:返回读取到的字符
  • 失败:-1

2、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");
    
    if (!fp)
    {
        printf("打开文件失败\n");
        return -1;
    }
    
    // 定义字符
    char ch;

    // 文件字符读取
    // 文件默认结尾为 -1
    // ch = fgetc(fp);

    // 不能修改文件指针
    // 文件在读取时光标流会自动向下移动
    // fp++;

    // 循环打印
    while ((ch = fgetc(fp)) != EOF)
    {
        printf("%c", ch);
    }

    // 关闭文件
    fclose(fp);

    return 0;
}
fgetc 使用案例

四、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    FILE* fp1 = fopen("C:/Users/Administrator/Desktop/解密.txt", "r");
    FILE* fp2 = fopen("C:/Users/Administrator/Desktop/加密.txt", "w");
 if (!fp1 || !fp2)return -1;
    char ch;
    while ((ch = fgetc(fp1)) != EOF)
    {
        // 加密
        ch++;
        fputc(ch, fp2);
    }

    fclose(fp1);
    fclose(fp2);

    return 0;
}
字符读写 使用案例:加密
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    FILE* fp1 = fopen("C:/Users/Administrator/Desktop/加密.txt", "r");
    FILE* fp2 = fopen("C:/Users/Administrator/Desktop/解密文件.txt", "w");
    if (!fp1 || !fp2)return -1;
    char ch;
    while ((ch = fgetc(fp1)) != EOF)
    {
        // 解密
        ch--;
        fputc(ch, fp2);
    }

    fclose(fp1);
    fclose(fp2);

    return 0;
}
字符读写 使用案例:解密

文件行读写

一、写文件

1、说明

#include <stdio.h>
int fputs(const char * str, FILE * stream);

功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 \'\0\' 不写入文件。
参数:

  • str:字符串
  • stream:文件指针

返回值:

  • 成功:0
  • 失败:-1

2、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 打开文件
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "w");
    // 判断
    if (!fp)return -1;

    // 创建字符串
    // "你想怎\0么滴吧" 遇到\0则停止
    // char ch[] = "你想怎么滴吧";
    //fputs(ch, fp);

    // 通过键盘输入获取字符串
    char* p = (char*)malloc(sizeof(char) * 1024);
    while (1)
    {
        memset(p, 0, 1024);
        
        // 问题:scanf("%s", p);无法接收回车空格
        // 方式一、fgets() 可接收空格
        // 方式二、scanf("%[^\n]", p); 避免吞噬空格回车
        scanf("%[^\n]", p);
        // 吞噬回车\n
        getchar();

        // 停止输入命令:comm=exit
        if (!strcmp(p, "comm=exit",9))break;

        // 追加换行符
        strcat(p, "\n");

        // 写入字符串
        fputs(p, fp);
    }

    free(p);
    fclose(fp);

    return 0;
}
fputs 使用案例

二、读文件

1、说明

#include <stdio.h>
char * fgets(char * str, int size, FILE * stream);

功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 \'\0\' 作为字符串结束。
参数:

  • str:字符串
  • size:指定最大读取字符串的长度(size - 1)
  • stream:文件指针

返回值:

  • 成功:成功读取的字符串
  • 读到文件尾或出错: NULL

2、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 打开文件
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");
    // 判断
    if (!fp)return -1;

    // 开辟堆空间
    char* p = (char*)malloc(sizeof(char) * 1024);
    
    // 初始化内存空间 
    // memset(p, 0, 5);
    // 通过堆开放内存,打印文件中100个字节
    // 根据光标位置继续向下读取字符串
    // fgets(p, 5, fp);
    // printf("%s", p);
    
    // 打印
    // feof(文件指针):判断文件是否到结尾 可以判断文本文件也可以判断二进制文件
    // 如果到文件结尾返回值为 非0的值
    // 如果没到文件结尾返回值为 0的值
    while (!feof(fp))
    {
        memset(p, 0, 100);
        fgets(p, 100, fp);
        printf("%s", p);
    }

    free(p);
    fclose(fp);

    return 0;
}
fgets 使用案例

三、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

enum opt
{
    add,sub,mlt,dive
};

int main(void)
{
    
    srand((size_t)time(NULL));
    
    // 打开文件
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "w");
    // 判断
    if (!fp)return -1;

    int a, b;
    char c; // + - * /
    char * p = (char*)malloc(sizeof(char) * 20);

    for (int i = 0; i < 100; i++)
    {
        a = rand() % 10 + 1;
        b = rand() % 10 + 1;

        switch (rand() % 4)
        {
        case add:c = \'+\';break;
        case sub:c = \'-\';break;
        case mlt:c = \'*\';break;
        case dive:c = \'/\';break;
        }

        memset(p, 0,20);
        sprintf(p, "%d%c%d=\n", a, c, b);
        fputs(p, fp);//fgets(p,size,fp)

    }

    free(p);
    fclose(fp);
    p = NULL;
    fp = NULL;

    return 0;
}
文件行读写 使用案例:四则运算(打印运算表达式)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    
    srand((size_t)time(NULL));
    
    // 打开文件
    FILE* fp1 = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");
    FILE* fp2 = fopen("C:/Users/Administrator/Desktop/xsk2.txt", "w");
    // 判断
    if (!fp1 || !fp2)return -1;

    // 判断文件结尾
    // !feof(fp);
    // EOF -1

    int a, b, sum;
    char c;
    char * p = (char*)malloc(sizeof(char) * 20);

    for (int i = 0; i < 100; i++)
    {
        memset(p, 0, 20);
        // 打印1行内容
        fgets(p, 20, fp1);

        sscanf(p, "%d%c%d=\n", &a, &c, &b);

        switch (c)
        {
        case \'+\':sum = a + b; break;
        case \'-\':sum = a - b; break;
        case \'*\':sum = a * b; break;
        case \'/\':sum = a / b; break;
        }

        memset(p, 0, 20);
        sprintf(p, "%d%c%d=%d\n", a, c, b, sum);
        fputs(p, fp2);
    }

    free(p);
    fclose(fp1);
    fclose(fp2);

    return 0;
}
文件行读写 使用案例:四则运算(打印运算表达式结果)

文件格式化

一、写文件

1、说明

#include <stdio.h>
int fprintf(FILE * stream, const char * format, ...);

功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 \'\0\' 为止。
参数:

  • stream:已经打开的文件
  • format:字符串格式,用法和printf()一样

返回值:

  • 成功:实际写入文件的字符个数
  • 失败:-1

2、案例

二、读文件

1、说明

#include <stdio.h>
int fscanf(FILE * stream, const char * format, ...);

功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:

  • stream:已经打开的文件
  • format:字符串格式,用法和scanf()一样

返回值:

  • 成功:参数数目,成功转换的值的个数
  • 失败: - 1

2、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    
    // 打开文件
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");
    // 判断
    if (!fp)return -1;

    char * p = (char*)malloc(sizeof(char) * 100);
    
    // 直接格式化取出字符串
    // 遇到空格与回车就结束
    // fscanf(fp, "%s", p);
    // printf("%s", p);


    int a, b, c;

    // 1+2=3
    // 处理表达式
    fscanf(fp, "%d+%d=%d", &a,&b,&c);

    printf("%d\n", a);
    printf("%d\n", b);
    printf("%d\n", c);

    free(p);
    fclose(fp);

    return 0;
}
fscanf 使用案例

三、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    srand((size_t)time(NULL));
    // 打开文件
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk1.txt", "w");
    // 判断
    if (!fp)return -1;

    int a, b;
    char c;

    for (int i = 0; i < 100; i++)
    {
        a = rand() % 10 + 1;
        b = rand() % 10 + 1;

        switch (rand() % 4)
        {
        case 0:c = \'+\'; break;
        case 1:c = \'-\'; break;
        case 2:c = \'*\'; break;
        case 3:c = \'/\'; break;
        }
        fprintf(fp, "%d%c%d=\n", a, c, b);
    }

    fclose(fp);

    return 0;
}
文件格式化 使用案例:四则运算案例(打印运算表达式)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    srand((size_t)time(NULL));
    // 打开文件
    FILE* fp1 = fopen("C:/Users/Administrator/Desktop/xsk1.txt", "r");
    FILE* fp2 = fopen("C:/Users/Administrator/Desktop/xsk2.txt", "w");
    // 判断
    if (!fp1||!fp2)return -1;

    int a, b, sum;
    char c;

    for (int i = 0; i < 100; i++)
    {
        fscanf(fp1, "%d%c%d\n", &a, &c, &b);

        switch (c)
        {
        case \'+\':sum = a + b; break;
        case \'-\':sum = a - b; break;
        case \'*\':sum = a * b; break;
        case \'/\':sum = a / b; break;
        }
        fprintf(fp2, "%d%c%d=%d\n", a, c, b,sum);
    }

    fclose(fp1);
    fclose(fp2);
    return 0;
}
文件格式化 使用案例:四则运算案例(打印运算表达式结果)
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 大文件排序 打印1000数字
    srand((size_t)time(NULL));
    // 打开文件
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "w");
    // 判断
    if (!fp)return -1;


    for (int i = 0; i < 1000; i++)
    {
        fprintf(fp, "%d\n", rand() % 256);
    }
    fclose(fp);
    return 0;
}
文件格式化 使用案例:大文件排序(打印1000行数字)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 打开文件
    FILE* fp1 = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");
    FILE* fp2 = fopen("C:/Users/Administrator/Desktop/xsk2.txt", "w");
    // 判断
    if (!fp1||!fp2)return -1;

    int* arr = (int*)malloc(sizeof(int) * 256);

    memset(arr, 0, sizeof(int) * 256);

    // 直接插入
    // 数据一定要在一个范围内
    for (int i = 0; i < 1000; i++)
    {
        int value;
        fscanf(fp1, "%d\n", &value);
        // 数据的个数放在对应的下标
        arr[value]++;
    }

    for (int i = 0; i < 256; i++)
    {
        for (int j = 0; j < arr[i]; j++)
        {
            fprintf(fp2, "%d\n", i);
        }
    }

    free(arr);
    fclose(fp1);
    fclose(fp2);

    return 0;
}
文件格式化 使用案例:大文件排序(直接插入排序)

文件块读写

一、写文件

1、说明

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以数据块的方式给文件写入内容
参数:

  • ptr:准备写入文件数据的地址
  • size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
  • nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb
  • stream:已经打开的文件指针

返回值:

  • 成功:实际成功写入文件数据的块数目,此值和nmemb相等
  • 失败:0

2、案例

typedef struct Stu
{
       char name[50];
       int id;
}Stu;
 
Stu s[3];
int i = 0;
for (i = 0; i < 3; i++)
{
       sprintf(s[i].name, "stu%d%d%d", i, i, i);
       s[i].id = i + 1;
}
 
int ret = fwrite(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);
fwrite 使用案例

二、读文件

1、说明

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以数据块的方式从文件中读取内容
参数:

  • ptr:存放读取出来数据的内存空间
  • size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
  • nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
  • stream:已经打开的文件指针

返回值:

  • 成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
  • 失败:0

2、案例

typedef struct Stu
{
       char name[50];
       int id;
}Stu;
 
Stu s[3];
int ret = fread(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);
 
int i = 0;
for (i = 0; i < 3; i++)
{
       printf("s = %s, %d\n", s[i].name, s[i].id);
}
fread 使用案例

三、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 写入数据
    // FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "wb");
    // 判断
    // if (!fp)return -1;
    // int a = 5678;
    // 以二级制格式写入
    // fwrite(&a, sizeof(int), 1, fp);
    // fclose(fp);
    
    // 数组写入
    // FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "wb");
    // 判断
    // if (!fp)return -1;
    // int arr[] = { 1,2,3,4,5,6,7,8,10 };
    // fwrite(arr, sizeof(int), 10, fp);
    // fclose(fp);

    // 读取数据
    // FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "rb");
    // 判断
    // if (!fp)return -1;
    // int value;
    // fread(&value, sizeof(int), 1, fp);
    // printf("%d\n", value);
    // fclose(fp);

    // 数组读取
    // FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "rb");
    // 判断
    // if (!fp)return -1;
    // int arr[10] = { 0 };
    // fread(arr, sizeof(int), 10, fp);
    // for (int i = 0; i < 10; i++)
    // {
    //     printf("%d\n", arr[i]);
    // }

    return 0;
}
文件块读写 使用案例

文件随机读写

一、说明

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

功能:移动文件流(文件光标)的读写位置。
参数:

  • stream:已经打开的文件指针
  • offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
  • whence:其取值如下:
  • SEEK_SET:从文件开头移动offset个字节
  • SEEK_CUR:从当前位置移动offset个字节
  • SEEK_END:从文件末尾移动offset个字节

返回值:

  • 成功:0
  • 失败:-1

二、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r");

    if (!fp)
    {
        return -1;
    }

    char arr[100];

    // 输出第一行
    memset(arr, 0, 100);
    fgets(arr, 100, fp);
    printf("%s", arr);

    // 输出第二行
    memset(arr, 0, 100);
    fgets(arr, 100, fp);
    printf("%s", arr);

    // 光标偏移
    // 文件随机读写
    // 从当前位置偏移,往回偏移8个
    fseek(fp, -8, SEEK_CUR);

    // 输出从光标位置输出
    memset(arr, 0, 100);
    fgets(arr, 100, fp);
    printf("%s", arr);

    fclose(fp);
    return 0;
}
文件随机读写 使用案例
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "r+");

    if (!fp)
    {
        return -1;
    }

    // 从文件末尾追加
    fseek(fp,-1, SEEK_END);

    fputs("aaaa",fp);

    fclose(fp);
    return 0;
}
文件随机读写 使用案例:2

文件流

一、文件流获取

1、说明

#include <stdio.h>
long ftell(FILE *stream);

功能:获取文件流(文件光标)的读写位置。
参数:

  • stream:已经打开的文件指针

返回值:

  • 成功:当前文件流(文件光标)的读写位置
  • 失败:-1

2、案例

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    FILE* fp = fopen("C:/Users/Administrator/Desktop/xsk.txt", "a");

    if (!fp)
    {
        return -1;
    }

    // 查看当前位置
    long pos = ftell(fp);

    printf("%ld\n", pos);

    fclose(fp);
    return 0;
} 
ftell 使用案例

二、文件流修改

1、说明

#include <stdio.h>
void rewind(FILE *stream);

功能:把文件流(文件光标)的读写位置移动到文件开头。
参数:

  • stream:已经打开的文件指针

返回值:
无返回值

2、案例

typedef struct Stu
{
       char name[50];
       int id;
}Stu;
 
//假如已经往文件写入3个结构体
//fwrite(s, sizeof(Stu), 3, fp);
 
Stu s[3];
Stu tmp;
int ret = 0;
 
//文件光标读写位置从开头往右移动2个结构体的位置
fseek(fp, 2 * sizeof(Stu), SEEK_SET);
 
//读第3个结构体
ret = fread(&tmp, sizeof(Stu), 1, fp);
if (ret == 1)
{
       printf("[tmp]%s, %d\n", tmp.name, tmp.id);
}
 
//把文件光标移动到文件开头
//fseek(fp, 0, SEEK_SET);
rewind(fp);
 
ret = fread(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);
 
int i = 0;
for (i = 0; i < 3; i++)
{
       printf("s === %s, %d\n", s[i].name, s[i].id);
}
rewind 使用案例

文件状态

一、说明

#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);

功能:获取文件状态信息
参数:

  • path:文件名
  • buf:保存文件信息的结构体

返回值:

  • 成功:0
  • 失败-1

二、使用

struct stat {
       dev_t         st_dev;          //文件的设备编号
       ino_t         st_ino;          //节点
       mode_t        st_mode;         //文件的类型和存取的权限
       nlink_t       st_nlink;        //连到该文件的硬连接数目,刚建立的文件值为1
       uid_t         st_uid;          //用户ID
       gid_t         st_gid;          //组ID
       dev_t         st_rdev;         //(设备类型)若此文件为设备文件,则为其设备编号
       off_t         st_size;         //文件字节数(文件大小)
       unsigned long st_blksize;      //块大小(文件系统的I/O 缓冲区大小)
       unsigned long st_blocks;       //块数
       time_t        st_atime;        //最后一次访问时间
       time_t        st_mtime;        //最后一次修改时间
       time_t        st_ctime;        //最后一次改变时间(指属性)
};

三、案例

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
 
int main(int argc, char **args)
{
       if (argc < 2)
              return 0;
     
// 文件状态结构体变量
       struct stat st = { 0 };
     
       stat(args[1], &st);
       int size = st.st_size;//得到结构体中的成员变量
       printf("%d\n", size);
       return 0;
}
stat 使用案例
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX (1024*1024*8)

// 拷贝大文件
int main(int argc,char* argv[])
{
    // 显示参数内容
    //for (int i = 0; i < argc; i++)
    //{
    //    printf("%s\n", argv[i]);
    //}

    // 用户输入参数缺少
    if (argc < 3)
    {
        printf("缺少参数\n");
        return -1;
    }

    // C:/copy.exe C:/xsk.txt C:/xsk/xsk.txt
    // argv[0] 程序名称、文件大小是50M
    FILE* fp1 = fopen(argv[1], "rb");
    FILE* fp2 = fopen(argv[2], "wb");

    if (!fp1 || !fp2)
    {
        printf("赋值文件出错\n");
        return -2;
    }

    char* temp = NULL;
    int size = 0;

    // 求文件大小
    struct stat st;
    stat(argv[1], &st);

    // 根据文件实际大小开辟空间
    if (st.st_size > MAX)
    {
        temp = (char*)malloc(sizeof(char) * MAX);
        size = MAX;
    }
    else
    {
        temp = (char*)malloc(sizeof(char) * st.st_size + 10);
        size = st.st_size + 10;
    }

    // 接收每次读取的字节数
    int count = 0;

    while (!feof(fp1))
    {
        memset(temp, 0, size);
        // count=读取实际字节数、读取内容
        count = fread(temp, sizeof(char), size,fp1);
        // 根据字节大小写入
        fwrite(temp, sizeof(char), count, fp2);
    }

    free(temp);
    fclose(fp1);
    fclose(fp2);
    return 0;
}
stat 使用案例:大文件拷贝操作

文件删除

一、说明

#include <stdio.h>
int remove(const char *pathname);

功能:删除文件
参数:

  • pathname:文件名

返回值:

  • 成功:0
  • 失败:-1

二、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 删除文件
    int value = remove("C:/Users/Administrator/Desktop/xsk.txt");
    if (value == 0)
    {
        printf("删除成功\n");
    }
    else
    {
        printf("删除失败\n");
    }

    return 0;
}
文件删除 使用案例

文件剪切重命名

一、说明

#include <stdio.h>
int rename(const char *oldpath, const char *newpath);

功能:把oldpath的文件名改为newpath
参数:

  • oldpath:旧文件名
  • newpath:新文件名

返回值:

  • 成功:0
  • 失败: - 1

二、案例

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int main(void)
{
    // 重命名、移动文件
    int value = rename("C:/Users/Administrator/Desktop/xsk.txt","C:/Users/Administrator/Desktop/xsk_new.txt");
    if (value == 0)
    {
        printf("改名成功\n");
    }
    else
    {
        printf("改名失败\n");
    }
    return 0;
}
文件剪切重命名 使用案例