文件IO (持续更新)

文件IO

1、 fopen     ->   文件打开

FILE *fopen(const char *pathname, const char *mode);
  • 参数

    • pathname:文件路径

    • mode:打开模式(见下表)

  • 模式说明

    模式 描述 文件存在 文件不存在
    "r" 只读(文本文件) 打开 失败
    "w" 只写(清空文件) 清空 创建
    "a" 追加写入(文本文件) 追加 创建
    "r+" 读写(文本文件) 打开 失败
    "w+" 读写(清空文件) 清空 创建
    "a+" 读写(追加模式) 追加 创建
    "b" 二进制模式(如 "rb+")    
  • 示例

     
    FILE *fp = fopen("data.txt", "r");
    if (fp == NULL) {
        perror("文件打开失败");
        exit(EXIT_FAILURE);
    }
  • 注意

    • 始终检查返回值是否为 NULL

    • 跨平台时建议使用二进制模式(如 Windows 的换行符问题)

2、 fclose ->文件关闭

int fclose(FILE *stream);
  • 参数stream - 要关闭的文件指针

  • 返回值:成功返回 0,失败返回 EOF

  • 示例

     
    if (fclose(fp) != 0) {
        perror("关闭文件失败");
    }
  • 注意

    • 关闭后文件指针不再可用

    • 未关闭文件可能导致数据丢失或资源泄漏

3、 fgetc   ->   字符读

int fgetc(FILE *stream);
  • 参数stream - 文件指针

  • 返回值

    • 成功返回读取的字符(转为 unsigned char 再转 int

    • 失败或 EOF 返回 EOF

  • 示例

     
    int c;
    while ((c = fgetc(fp)) != EOF) {
        putchar(c);
    }
  • 注意

    • 必须用 int 接收返回值,char 类型无法区分 EOF 和 0xFF

4、 fgets   ->   字符串读

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

    • str:存储读取数据的缓冲区

    • size:缓冲区大小(包含结尾的 \0

    • stream:文件指针

  • 返回值

    • 成功返回 str

    • 失败或 EOF 返回 NULL

  • 示例

     
    char buffer[256];
    if (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("读取内容: %s", buffer);
    }
  • 注意

    • 读取到 \n 或缓冲区满时停止

    • 保留换行符并在末尾添加 \0

5、 fread   ->   读文件

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

    • ptr:数据存储缓冲区

    • size:每个数据项的字节数

    • nmemb:要读取的数据项数量

    • stream:文件指针

  • 返回值:实际读取的数据项数量(可能小于 nmemb

  • 示例

     
    int data[10];
    size_t read_count = fread(data, sizeof(int), 10, fp);
  • 注意

    • 推荐用 sizeof 计算 size  (思考一下sizeof会把字符串中'\0'计算在内吗?)

    • 需检查返回值是否等于预期数量

6、 fputc   ->   字符写

int fputc(int c, FILE *stream);
  • 参数

    • c:要写入的字符(转为 unsigned char

    • stream:文件指针

  • 返回值:成功返回写入的字符,失败返回 EOF

  • 示例

     
    fputc('A', fp); // 写入字符'A'

7、 fputs   ->   字符串写

int fputs(const char *s, FILE *stream);
  • 参数

    • s:要写入的字符串(需包含换行符)

    • stream:文件指针

  • 返回值:成功返回非负数,失败返回 EOF

  • 示例

     
    fputs("Hello World\n", fp);
  • 注意

    • 不会自动添加换行符

    • 字符串需以 \0 结尾

8、 fwrite   ->   写文件

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

    • ptr:数据存储缓冲区

    • size:每个数据项的字节数

    • nmemb:要读取的数据项数量

    • stream:文件指针

  • 返回值:实际写入的数据项数量

  • 示例

     
    int data[] = {1, 2, 3};
    fwrite(data, sizeof(int), 3, fp);
  • 注意

    • 数据写入可能因磁盘满等原因部分成功

    • 二进制文件需用相同模式读写(如结构体序列化)

9、 fflush   ->   刷新缓冲区

int fflush(FILE *stream);
  • 功能:强制将缓冲区数据写入文件

  • 注意

    • 对输入流使用行为未定义

    • 频繁调用可能影响性能

10、 fseek/ftell   ->   fseek移动光标/ftell计算当前光标距离文件开头的距离

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
  • whence 参数

    • SEEK_SET:文件开头

    • SEEK_CUR:当前位置

    •    SEEK_END:文件末尾
  • 示例
 

 

fseek(fp, 0, SEEK_END); // 定位到文件末尾
long size = ftell(fp);  // 获取文件大小

11、 feof   ->   检测文件结束标志

int feof(FILE *stream);
  • 功能:检测文件流的 文件结束标志(end-of-file indicator) 是否被置位。

  • 参数stream - 文件指针(指向已打开的文件流)。

  • 返回值

    • 如果文件结束标志被置位(即尝试读取时已到达文件末尾),返回 非零值

    • 否则返回 0

12、 ferror   ->   检测文件错误标志

int ferror(FILE *stream);
  • 功能:检测文件流的 错误标志(error indicator) 是否被置位。

  • 参数stream - 文件指针。

  • 返回值

    • 如果错误标志被置位(如磁盘I/O错误、非法操作),返回 非零值

    • 否则返回 0

  • 通常与 feof 结合使用,区分“正常结束”和“异常终止”。

 

 

 

例1:向log文件写入当前的时间 👇代码

这个感觉有点意思的

 #include<stdio.h>
#include<time.h>
#include<unistd.h>
#include<stdlib.h>


int main(int argc,char const * argv[]){
    // if(2 != argc){
    //     printf("argument is invalid\n");
    // }

    FILE * log = fopen("log.txt","wd");
        if (!log) {
        perror("无法打开日志文件");
        exit(-1);
    }


    

    while(1){

        //获取时间
        time_t now;

        time(&now);

        struct tm *tm_info = localtime(&now);

        //把当前时间按照 --yy年mm月dd日--来输入到log.txt文件
        fprintf(log,"%d年%d月%d日%d时%d分%d秒\n",(tm_info->tm_year+1900),tm_info->tm_mon,tm_info->tm_mday,tm_info->tm_hour,tm_info->tm_min,tm_info->tm_sec);
        
        fflush(log);  // 立即刷新缓冲区确保数据写入
        
        sleep(1);//休眠1秒
        
        printf("*******正在写入*******\n");
    }
    fclose(log);
    return 1;

}

例2:计算文件的大小 👇代码

 /*************************************************************************
*   file name:CalculateFileSize
*   function:  计算文件的大小
*   date: 2025.5.21
*   note:需要在执行文件时 写入所计算文件的名字 
*            例:
*                   ./main a.txt
*    Copyright (c) 2024-2025 l550036303@163.com All right reserved
**************************************************************************/

#include<stdio.h>
#include<stdlib.h>


void main(int argc,char const * argv[]){

/************************************第一种方法计算******************************************/
#if 0

    
    long int number=0;

    if( 2 !=argc ){
        perror("argument is invail");
        exit(-1);
    }

    FILE * p = fopen(argv[1],"rb");
    if( NULL == p ){
        perror("无法打开文件");
        exit(-1);
    }

    while((fgetc(p)) != EOF ){
        number++;
    }
    // printf("\tfilename: %s\tsize:%d\n",argv[1],number);

    if(ferror(p) != 0){
        perror("读取文件时发生错误");
        fclose(p);
        exit(-1);
    }

    if(feof(p) != 0){
        printf("\tfilename: %s\tsize:%ld\n",argv[1],number);
    }
#endif
/************************************第二种方法计算******************************************/
#if 0
    long int number=0;

    if( 2 !=argc ){
        perror("argument is invail");
        exit(-1);
    }

    FILE * p = fopen(argv[1],"ab");

    if( NULL == p ){
        perror("无法打开文件");
        exit(-1);
    }
    number = ftell(p);  

    if(ferror(p) != 0){    //ferror 为0时就是无异常
        perror("读取文件时发生错误");
        fclose(p);
        exit(-1);
    }
        printf("\tfilename: %s\tsize:%ld\n",argv[1],number);
#endif
/************************************第三种方法计算******************************************/
#if 1
    long int number=0;

    if( 2 !=argc ){
        perror("argument is invail");
        exit(-1);
    }

    FILE * p = fopen(argv[1],"rb");

    if( NULL == p ){
        perror("无法打开文件");
        exit(-1);
    }

    fseek(p,0,SEEK_END); //移动光标到末尾  CUR当前  SET开头
    number = ftell(p);  

    if(ferror(p) != 0){    //ferror 为0时就是无异常
        perror("读取文件时发生错误");
        fclose(p);
        exit(-1);
    }
        printf("\tfilename: %s\tsize:%ld\n",argv[1],number);
#endif
/******************************************************************************/

    //关闭
    fclose(p);

    return;
}

例3:复制文件 👇代码

/*************************************************************************
*   file name:creatlog
*   function:  source文件的内容复制到 target文件
*   date: 2025.5.22
*   note: 要输入两个文件名 第一个是source名 第二个是target文件名  ./creatlog io.c copytest.c
*    Copyright (c) 2024-2025 l550036303@163.com All right reserved
**************************************************************************/

#include<stdio.h>
#include<stdlib.h>

void main(int argc,char const *argv[]){

    if(3 != argc){
        perror("argument is invail\n");
        exit(-1);
    }

    FILE* src = fopen(argv[1],"rb");

    FILE* tar = fopen(argv[2],"wb");

    if( src == NULL ){
        printf("%s open fail\n",argv[1]);
        exit(-1);
    }
    if( tar == NULL){
        printf("%s open fail\n",argv[2]);
        exit(-1);
    }
    char temp[5];
    int n = 0;

    while((n=fread(temp,1,sizeof(temp),src) ) > 0){        
        fwrite(temp,1,n,tar);
            if (ferror(tar)) {
            perror("写入目标文件失败");
            fclose(src);
            fclose(tar);
            exit(-1);
        }
    
    }
       if (ferror(src)) {
        perror("读取源文件失败");
        fclose(src);
        fclose(tar);
        exit(-1);
    }
    fclose(src);
    fclose(tar);
    return;
}

 

posted @ 2025-05-21 21:42  记得要好好吃饭  阅读(35)  评论(0)    收藏  举报