C语言修改缓冲区大小拷贝文件的计时异常及代码优化咨询
你的文件拷贝计时异常与代码问题全解析
一、先解决你最困惑的三个初始问题
1. 为什么首次拷贝后耗时几乎为0?
这是文件指针位置和文件名拼写错误共同导致的:
- 你在循环外只打开了一次源文件
fichier1,第一次拷贝完成后,文件的读指针已经走到了末尾,后续调用read()直接返回0,拷贝循环根本没执行,自然耗时趋近于0。 - 代码里你创建的目标文件是
grosfichier_copy,但删除的是grosfichier_copie(拼写差了一个字母),导致后续循环里目标文件其实是已经写完的旧文件,进一步加剧了异常。
2. free的使用是否正确?
你的free操作是对的!循环里用realloc更新buffer后,temp_buffer和buffer指向同一块内存,所以最后只需要free(buffer)就足够了——你注释掉free(temp_buffer)是正确的,要是提前free反而会触发double free错误。
3. 缓冲区传递给copy函数的方式恰当吗?
完全不恰当,这里有两个致命错误:
// 你的初始copy函数代码 while ((t = read(in, &buffer, sizeof taille))> 0) write (out, &buffer, t);
&buffer传递的是缓冲区指针的地址,不是缓冲区本身的地址,read会把数据写到指针变量的内存里,而不是你malloc出来的缓冲区,这会直接导致内存错误!sizeof taille取的是taille变量本身的大小(比如long long类型是8字节),而不是你传入的缓冲区大小的值,等于你不管分配多大的缓冲区,每次最多只读8字节,完全浪费了缓冲区空间!
二、关于你的EDIT1:修正后计时合理的原因
你说修正后得到了符合预期的计时结果,推测你应该做了这几个关键修复:
- 把文件的
open和close移到了循环内部,每次拷贝前重新打开源文件(让读指针回到文件开头),并重新创建目标文件 - 修正了
copy函数里的缓冲区传递和读取大小问题:改成传递buffer而非&buffer,用taille的值作为read的第三个参数 - 统一了文件名的拼写(终于让删除的文件和创建的文件对应上了)
这些修改直接解决了计时异常的核心问题,现在的结果完全符合预期:缓冲区越大,拷贝耗时越低,直到达到系统IO的最优阈值(一般是4KB或8KB左右,之后耗时下降会明显变缓)。
三、针对你的EDIT2:新版copy函数是否可行?
这个版本比初始版本正确太多,但还有一个关键漏洞:write可能不会一次性写入所有数据。
根据POSIX标准,write()的返回值是实际写入的字节数,当内核缓冲区满的时候,它的返回值会小于你要求写入的t,如果不处理这种情况,会导致部分数据丢失。
所以需要给write加一个循环,确保所有数据都被写入:
void copy(int in, int out, char *buffer, size_t taille) { ssize_t t; while ((t = read(in, buffer, taille)) > 0) { char *ptr = buffer; ssize_t written; // 循环写入,直到所有t字节都被写完 while (t > 0) { written = write(out, ptr, t); if (written < 0) { perror("error writing"); return; // 也可以根据需求选择退出程序等错误处理方式 } t -= written; ptr += written; } } if (t < 0) { perror("read"); } }
最后再给你两个小建议:
- 打开目标文件时,建议加上权限参数和
O_TRUNC,比如open("grosfichier_copy", O_WRONLY|O_CREAT|O_TRUNC, 0644)——O_TRUNC确保每次打开时清空文件,避免旧内容残留,0644则明确设置文件权限,避免依赖系统默认的umask导致权限异常。 clock()测量的是CPU时间,如果你想得到更贴近实际感知的“真实耗时”(包括IO等待时间),可以用clock_gettime(CLOCK_MONOTONIC)或者gettimeofday(),结果会更准确。
内容的提问来源于stack exchange,提问作者Jonath P
相关产品推荐
相关产品推荐

