书写逻辑
请写下你的逻辑,与参考逻辑对比,如有缺失,可细看本文
一、终端操作流程
# 创建项目目录
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() 自动继承 |
扩展应用场景
- 断点续传功能实现
- 文件加密传输模块
- 网络文件传输协议基础
- 增量同步算法开发基础
参考逻辑
- 创建源文件a
- 读取形参个数
- 打开文件a
- 异常处理
- 打开文件b
- 异常处理-关闭a
- 分配缓冲区
- 异常处理-关闭a\b
- 读取a,写入b
- 读取数据检测
- 释放c,关闭文件a\b