文件拷贝练习-c

书写逻辑

请写下你的逻辑,与参考逻辑对比,如有缺失,可细看本文

一、终端操作流程

# 创建项目目录
mkdir file-copy && cd file-copy

# 创建C源码文件
touch file_copy.c

# 创建测试文件
echo "Hello World" > source.txt

二、C语言实现代码

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

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    // 参数校验
    if (argc != 3) {
        fprintf(stderr, "用法: %s <源文件> <目标文件>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *src = fopen(argv[1], "rb");
    if (!src) {
        perror("打开源文件失败");
        exit(EXIT_FAILURE);
    }

    FILE *dst = fopen(argv[2], "wb");
    if (!dst) {
        perror("创建目标文件失败");
        fclose(src);
        exit(EXIT_FAILURE);
    }

    // 缓冲区动态分配
    char *buffer = malloc(BUFFER_SIZE);
    if (!buffer) {
        perror("内存分配失败");
        fclose(src);
        fclose(dst);
        exit(EXIT_FAILURE);
    }

    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, src)) > 0) {
    	printf("一次性读取数据大小:%d\n",bytes_read);
        size_t bytes_written = fwrite(buffer, 1, bytes_read, dst);
        if (bytes_written != bytes_read) {
            perror("写入数据不完整");
            break;
        }
    }

    // 资源释放
    free(buffer);
    fclose(src);
    fclose(dst);
    
    printf("文件拷贝完成\n");
    return EXIT_SUCCESS;
}

stderr 是一个指向标准错误输出流的指针,通常用于打印错误信息或警告信息。与之相对的是stdout(标准输出流,用于正常的输出信息)和stdin(标准输入流,用于读取输入)。

rb这是 fopen 函数的第二个参数,指定了文件的打开模式。“r” 表示以只读模式打开文件,“b” 表示以二进制模式打开文件。在Unix-like系统上,“b” 标志通常可以忽略,因为在这些系统上,文本模式和二进制模式没有区别。但在Windows上,使用 “b” 标志可以避免在读取或写入文件时对数据进行不必要的转换(如将换行符 \n 转换为 \r\n 或反之)。
fopen 函数以只读模式(如 “r” 或 “rb”)打开文件,fopen 将不会创建该文件。如果你以写入模式(如 “w”、“w+”、“a”、“a+”)或更新模式(如 “w+”、“a+”)打开文件,并且文件不存在,fopen 将会创建该文件。

fread尝试从文件流src中读取BUFFER_SIZE个字节的数据到缓冲区buff中。
1类型:size_t。这是每个数据项的大小(以字节为单位)。在这个例子中,1 表示每个数据项的大小是 1 字节。这意味着 fread 将从文件流中按字节读取数据到 buff 中。如果你想要读取更大的数据单元(比如整数、浮点数或结构体),你需要将这个参数设置为相应类型的大小(例如,sizeof(int)、sizeof(float) 或 sizeof(struct MyStruct))。
BUFFER_SIZE,类型:size_t。解释:这是要读取的数据项的数量。在这个例子中,BUFFER_SIZE 是一个宏定义或常量,表示你想要从文件流中读取的字节总数。由于第二个参数是 1,这意味着 fread 将尝试读取BUFFER_SIZE 个字节到 buff 中。

while循环处理1.内存限制,有些数据很长,一次性可能读不到指定的大小; 2.文件大小未知;3.错误处理。
size_t 是一个无符号整数类型。

三、关键函数解析

文件操作生命周期模型: 文件操作生命周期模型: 文件操作生命周期模型:
{ 打开阶段 f _ o p e n ( ) 传输阶段 { f _ r e a d ( ) f _ w r i t e ( ) 关闭阶段 f _ c l o s e ( ) \begin{cases} \text{打开阶段} & f\_open() \\ \text{传输阶段} & \begin{cases} f\_read() \\ f\_write() \end{cases} \\ \text{关闭阶段} & f\_close() \end{cases} 打开阶段传输阶段关闭阶段f_open(){f_read()f_write()f_close()


四、编译与运行

# 编译程序(GCC)
gcc -o fcopy file_copy.c -Wall -Wextra

# 执行拷贝操作
./fcopy source.txt destination.txt

# 验证结果
diff source.txt destination.txt && echo "文件一致"

-Wall:这个选项启用了 GCC 的所有基本警告。它有助于在编译过程中发现潜在的编程错误或不良编程实践。-Wall 是 “Warning All” 的缩写,但实际上它并不会启用所有可能的警告,而只是一组常见的、有用的警告。
-Wextra:这个选项启用了除了 -Wall 之外的额外警告。这些警告通常针对一些不那么常见但仍然值得注意的问题。结合使用 -Wall 和 -Wextra 可以帮助开发者在编译阶段捕获更多的潜在问题。

五、性能优化技巧

// 调整缓冲区大小(根据系统页大小优化)
#define BUFFER_SIZE (4 * 1024) // 4KB缓冲区

// 使用内存映射文件(Linux系统)
#include <sys/mman.h>
void* map = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, src_fd, 0);
msync(map, file_size, MS_SYNC);
munmap(map, file_size);

六、错误处理增强

// 添加错误代码详细输出
if (ferror(src)) {
    fprintf(stderr, "[错误码 0x%X] 读取源文件时发生I/O错误\n", ferror(src));
    clearerr(src);
}

// 支持大文件(32位系统需要)
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>

七、运行示例验证

# 创建大文件测试(Linux/Mac)
dd if=/dev/urandom of=1GB.bin bs=1M count=1024

# 执行拷贝
time ./fcopy 1GB.bin 1GB-copy.bin

# 输出示例:
# 文件拷贝完成
# real    0m2.147s
# user    0m0.432s
# sys     0m1.689s

八、跨平台注意事项

系统特性Windows方案Linux/Mac方案
路径分隔符\\//
二进制模式必须指定"rb"/"wb"推荐显式指定
文件锁定_locking()flock()
权限保留需额外调用chmod()fchmod()自动继承

扩展应用场景

  1. 断点续传功能实现
  2. 文件加密传输模块
  3. 网络文件传输协议基础
  4. 增量同步算法开发基础

参考逻辑

  1. 创建源文件a
  2. 读取形参个数
  3. 打开文件a
  4. 异常处理
  5. 打开文件b
  6. 异常处理-关闭a
  7. 分配缓冲区
  8. 异常处理-关闭a\b
  9. 读取a,写入b
  10. 读取数据检测
  11. 释放c,关闭文件a\b
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值