你的代码是一个用于并行拷贝文件的C语言程序。它使用了多线程来实现文件拷贝的功能,将源文件分为两部分分别在两个线程中进行拷贝。以下是对这段代码的一些分析和可能需要注意的地方:
主要功能
- 获取源文件大小和创建目标文件:
get_srcfile_len_and_create_destfile
函数打开源文件并计算其长度,然后创建目标文件。 - 并行拷贝:
copy_file
函数在新线程中运行,用于从源文件读取数据并写入到目标文件。 - 多线程:主函数创建两个线程,每个线程负责拷贝一半的数据。
注意事项
错误处理:
ERR_LOG
宏未定义,建议添加相应的错误处理逻辑,比如打印错误信息或退出程序。- 检查所有系统调用(如
open
,lseek
,read
,write
, 和pthread_create
)返回值,并适当处理错误。
缓冲区大小:
- 在
copy_file
中使用的缓冲区大小为10字节,这在性能上可能不够理想,可以根据需求增大这个值(例如1024字节)。
- 在
偏移量问题:
- 确保你正确地管理每个线程中的偏移量,以及数据写入时是否出现越界。
关闭文件描述符:
- 确保在任何情况下都能关闭打开的文件描述符,包括发生错误时。
内存管理:
- 虽然这里没有动态分配内存,但若将来有涉及,请确保正确释放资源以避免内存泄漏。
线程安全性:
- 在本例中,每个线程操作不同的数据块,因此不会出现竞争条件,但如果你扩展此代码,要注意共享资源的访问同步问题。
命令行参数检查:
- 目前只检查了参数数量,建议添加更详细的参数验证,例如检查输入路径是否有效等。
下面是对以上一些改进点做出具体修改后的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#define ERR_LOG(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
typedef struct _Msg{
const char *src_file;
const char *dest_file;
int offset;
int cp_len;
}msg_t;
//获取源文件大小,创建目标文件
int get_srcfile_len_and_create_destfile(const char *src_file, const char *dest_file){
//获取源文件大小
int src_fd = open(src_file, O_RDONLY);
if(-1 == src_fd)
ERR_LOG("open error");
int length = lseek(src_fd, 0, SEEK_END);
close(src_fd);
//创建目标文件
int dest_fd = open(dest_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(-1 == dest_fd)
ERR_LOG("create destination file error");
close(dest_fd);
return length;
}
//拷贝文件
void *copy_file(void *arg){
msg_t *p = (msg_t *)arg;
// 打开源和目标文件
int src_fd = open(p->src_file, O_RDONLY);
if(-1 == src_fd)
ERR_LOG("open source file error");
int dest_fd = open(p->dest_file, O_WRONLY);
if(-1 == dest_fd)
ERR_LOG("open destination file error");
// 定位光标
lseek(src_fd, p->offset, SEEK_SET);
// 拷贝内容
char buff[1024]; // 增加缓冲区大小,提高性能
int total_copied = 0;
int nbytes;
while ((nbytes = read(src_fd, buff, sizeof(buff))) > 0) {
if (total_copied + nbytes > p->cp_len) {
nbytes = p->cp_len - total_copied; // 限制写入字节数
}
write(dest_fd, buff, nbytes);
total_copied += nbytes;
if (total_copied >= p->cp_len) {
break; // 达到复制要求,退出循环
}
}
close(src_fd);
close(dest_fd);
return NULL; // 返回NULL表示正常结束
}
int main(int argc, const char *argv[]) {
if(argc != 3){
printf("Usage : %s src_file dest_file\n", argv[0]);
exit(EXIT_FAILURE);
}
int length = get_srcfile_len_and_create_destfile(argv[1], argv[2]);
msg_t tasks[2] = {
{ .src_file = argv[1], .dest_file = argv[2], .offset = 0, .cp_len = length / 2 },
{ .src_file = argv[1], .dest_file = argv[2], .offset = length / 2, .cp_len = length - (length / 2) }
};
pthread_t tid[2];
for(int i=0; i<2; i++) {
if(pthread_create(&tid[i], NULL, copy_file, &tasks[i]) != 0) {
printf("pthread_create error: [%s]\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
for(int i=0; i<2; i++) {
pthread_join(tid[i], NULL); // 等待每个线程结束
}
return EXIT_SUCCESS;
}
改动总结:
- 增加了缓冲区大小,提高性能。
- 错误处理进行了简化和统一。
- 调整了一些细节以提高代码健壮性和可读性。
内容由零声教学AI助手提供,问题来源于学员提问