002库函数IO基础二

fopen补充

image-20260114114241855

其中还有二进制模式的

在原有mode字符串后加b,例如:

  • "rb"二进制只读(文件必须存在)
  • "rb+"二进制读写(文件必须存在)
  • "wb"二进制只写(文件不存在则创建,存在则清空)
  • "wb+"二进制读写(文件不存在则创建,存在则清空)
  • "ab"二进制追加只写(文件不存在则创建,写数据到末尾)
  • "ab+"二进制追加读写(文件不存在则创建,写数据到末尾)

文本和二进制的区别

  • 文本模式下,写入和读取的数据可能与实际存储的数据不同。

    Windows 下文本模式会转换换行符(\n\r\n),二进制模式不转换

  • 二进制模式下,写入和读取的数据与实际存储的数据一致,适用于处理图片、音频等二进制文件

    所有字符(包括特殊字符)都会被当作普通字节直接读写,保持原始存储形式。

一、文件写入方式

标准 IO 提供三种核心文件写入方式:

  1. 字符写入:按单个字符维度写入文件;

    imgimg

    过程:输出--->写缓冲区--->内核写缓冲区--->文件内

  2. 按行写入:按整行维度写入文件;img

    img
    \0为终止符,遇到\0立即停止写入,且不写入\0本身

  3. 按块写入:按指定大小的块维度写入文件。 img

    img

写出错时,文件光标位置结果值不确定

二、文件位置

每个被打开文件的结构体中都有一个位置指示器(简单理解:位置指示器是文件光标)

注意:被打开的文件的光标默认是在文件开头的。

  1. 设置位移

img

img

  1. 获取位移

img

img

可以用来求文件的数据大小

确保文件的光标在末尾

​ 调用fseek设置SEEK_END 用追加的方式也是在末尾

​ 使用ftell计算光标的偏移量

得到文本数据大小

练习:要求利用标准IO函数接口实现计算一个本地磁盘某个文件的大小,要求文件名称通过命令行进行传递,并进行验证是否正确( ls -l)。

#include <stdio.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
    //1、要求计算大小的
    // 文件的路径需要通过命令行参数传递进来
    if(2 != argc){
        printf("Usage:%s filepath\n",argv[0]);
        exit(1);
    }
    //2、打开文件
    FILE *fp = fopen(argv[1],"rb");
    if(fp == NULL){
        perror("fopen");
         exit(1);
    }
    //3、循环读取文件内容
    int i = 0;
    while(fgetc(fp) != EOF){
        i++;
    }
    printf("文件共有 %d 个字符\n",i);
    //4、关闭文件
    fclose(fp);
    return 0;
}

#include <stdio.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
    //1、要求计算大小的
    // 文件的路径需要通过命令行参数传递进来
    if(2 != argc){
        printf("Usage:%s filepath\n",argv[0]);
        exit(1);
    }
    //2、打开文件
    FILE *fp = fopen(argv[1],"ab");	//a追加模式,光标会在文本末尾
    if(fp == NULL){
        perror("fopen");
         exit(1);
    }
    // //3、循环读取文件内容
    // int i = 0;
    // while(fgetc(fp) != EOF){
    //     i++;
    // }
    printf("文件共有 %d 个字符\n",ftell(fp));
    //4、关闭文件
    fclose(fp);
    return 0;
}

练习:利用标准IO函数接口实现文件拷贝,把本地磁盘的文件A中的数据完整的拷贝到另一个文本B中,如果文本B不存在则创建,要求文本A的名称和文本B的名称通过命令行传递,并进行验证是否正确。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERSIZE 512

int main(int argc,const char *argv[])
{   
    int sizeA=0;        //文件A的大小
    int loop_cnt=0;    //循环次数
    int remainder = 0; //余数
    //1、文件的路径需要通过命令行参数传递进来
    if(3!=argc){
        printf("Usage:%s filepath\n",argv[0]);
        exit(1);    
    }
    //2、打开文件A、B
    FILE *A = fopen(argv[1],"rb");
    if(NULL == A){
    perror("fopen:A");
    exit(1);
    }
    FILE *B = fopen(argv[2],"wb");
    if(NULL == B){
    perror("fopen:B");
    exit(1);
    }
    //3、读取A中的内容
    //为了提高程序运行效率,采用空间换时间,定义数据缓冲区来存储
    char data_buffer[BUFFERSIZE] ={0};
    
    fseek(A,0,SEEK_END);    //将光标偏移到文件末尾
    sizeA = ftell(A);
    fseek(A, 0, SEEK_SET);  //将光标偏移到文件开头

    //计算读取数据块的次数,循环写入
    loop_cnt= sizeA / BUFFERSIZE;
    remainder = sizeA % BUFFERSIZE;

    while (loop_cnt--) {
        //读取数据到缓冲区
        fread(data_buffer, BUFFERSIZE,1, A);
        //将缓冲区数据写入文件B
        fwrite(data_buffer, BUFFERSIZE,1, B);
    }

    //处理剩余数据
    if (remainder > 0) {
        //清空缓冲区
        memset(data_buffer, 0, BUFFERSIZE);

        //读取剩余数据到缓冲区
        fread(data_buffer, remainder, 1, A);
        //将缓冲区数据写入文件B
        fwrite(data_buffer, remainder, 1, B);
    }
    //验证文件B的大小是否和文件A一致
    int sizeB = ftell(B);   
    printf("文件A的大小为:%ld 字节\n", sizeA);
    printf("文件B的大小为:%ld 字节\n", sizeB);
    if(sizeA == sizeB){
        printf("文件复制成功!\n");
    }else{
        printf("文件复制失败!\n");
    }
    //4、关闭文件
    fclose(A);
    fclose(B);

    return 0;
}

三、 格式访问

标准库中除了以上关于文件读写的函数之外,还提供了一些可以对文件进行格式化读写的函数接口,在C99标准中有关于这些函数的描述,如下:

img

注意:一般常用的关于文件IO的格式化函数有printf、fprintf、scanf、fscanf、sprintf、snprintf。

img

img

作业:设计程序,获取当前系统时间,把时间转换为特定格式”yy年mm月dd日 星期x tt:mm:ss”,并每隔1s写入到本地磁盘中一个叫做log.txt的文本中,如果文本不存在则创建。

获取时间的函数

img

img

/*

 * © 2026 guokun. All rights reserved.

*   email:guokun603@gmail.com

*   获取当前系统时间
 */

#include <stdio.h>
#include <time.h>
// 星期转换数组
const char* week_day[] = {"日", "一", "二", "三", "四", "五", "六"};
int main (int argc , const char * argv[])
{
     time_t now;
    while (1)
    {
    //1、获取当前系统时间
    time(&now);
    if (-1 == now) {
        perror("time");
        return -1;
    }
    //2、转换为本地时间
    struct tm *local = localtime(&now);
    if (NULL == local) {
        perror("localtime");
        return -1;
    }
    //打开文件
    FILE *fp = fopen("log.txt","ab");
    if(NULL == fp){
        perror("fopen");
        return -1;
    }
    //将时间写入文件
    fprintf(fp,"当前系统时间为:""%04d年%02d月%02d日 星期%s %02d:%02d:%02d\n",
           local->tm_year + 1900,
           local->tm_mon + 1,
           local->tm_mday,
           week_day[local->tm_wday],
           local->tm_hour,
           local->tm_min,
           local->tm_sec);
    //关闭文件
    fclose(fp);
    sleep(1);
    }
    
    return 0;
}
posted @ 2026-01-14 12:14  郭小胖  阅读(0)  评论(0)    收藏  举报