这看起来像一个简单的问题,但我没有发现任何类似的东西.
由于C中没有文件复制功能,我们必须自己实现文件复制,但是我不喜欢重新发明轮子,即使是这样的微不足道的东西,所以我想问云:
>使用fopen()/ fread()/ fwrite()),您建议使用什么代码进行文件复制?
>使用open()/ read()/ write(),您建议使用什么代码进行文件复制?
这个代码应该是可移植的(windows / mac / linux / bsd / qnx / younameit),稳定的,时间测试的,快速的,内存高效的等等.进入特定系统的内部来挤压一些更多的性能是受欢迎的(如获取文件系统集群大小) .
解决方法
就实际的I / O而言,我将数据从一个流复制到另一个流程的代码写在百万次以上,就像这样.在成功时返回0,或者在错误时设置了errno(在这种情况下可能会复制任何数量的字节).
请注意,对于复制常规文件,您可以跳过EAGAIN的东西,因为常规文件总是阻止I / O.但是不可避免地,如果你写这个代码,有人会使用它在其他类型的文件描述符,所以认为它是一个免费的.
有一个文件特定的GNU cp优化,我没有在这里烦恼,对于0个字节的长块而不是写你只是通过寻求结束扩展输出文件.
void block(int fd,int event) { pollfd topoll; topoll.fd = fd; topoll.events = event; poll(&topoll,1,-1); // no need to check errors - if the stream is bust then the // next read/write will tell us } int copy_data_buffer(int fdin,int fdout,void *buf,size_t bufsize) { for(;;) { void *pos; // read data to buffer ssize_t bytestowrite = read(fdin,buf,bufsize); if (bytestowrite == 0) break; // end of input if (bytestowrite == -1) { if (errno == EINTR) continue; // signal handled if (errno == EAGAIN) { block(fdin,POLLIN); continue; } return -1; // error } // write data from buffer pos = buf; while (bytestowrite > 0) { ssize_t bytes_written = write(fdout,pos,bytestowrite); if (bytes_written == -1) { if (errno == EINTR) continue; // signal handled if (errno == EAGAIN) { block(fdout,POLLOUT); continue; } return -1; // error } bytestowrite -= bytes_written; pos += bytes_written; } } return 0; // success } // Default value. I think it will get close to maximum speed on most // systems,short of using mmap etc. But porters / integrators // might want to set it smaller,if the system is very memory // constrained and they don't want this routine to starve // concurrent ops of memory. And they might want to set it larger // if I'm completely wrong and larger buffers improve performance. // It's worth trying several MB at least once,although with huge // allocations you have to watch for the linux // "crash on access instead of returning 0" behavIoUr for Failed malloc. #ifndef FILECOPY_BUFFER_SIZE #define FILECOPY_BUFFER_SIZE (64*1024) #endif int copy_data(int fdin,int fdout) { // optional exercise for reader: take the file size as a parameter,// and don't use a buffer any bigger than that. This prevents // memory-hogging if FILECOPY_BUFFER_SIZE is very large and the file // is small. for (size_t bufsize = FILECOPY_BUFFER_SIZE; bufsize >= 256; bufsize /= 2) { void *buffer = malloc(bufsize); if (buffer != NULL) { int result = copy_data_buffer(fdin,fdout,buffer,bufsize); free(buffer); return result; } } // could use a stack buffer here instead of failing,if desired. // 128 bytes ought to fit on any stack worth having,but again // this could be made configurable. return -1; // errno is ENOMEM }
打开输入文件:
int fdin = open(infile,O_RDONLY|O_BINARY,0); if (fdin == -1) return -1;
int fdout = open(outfile,O_WRONLY|O_BINARY|O_CREAT|O_TRUNC,0x1ff); if (fdout == -1) { close(fdin); return -1; }
但有混淆因素:
>你需要特殊情况下文件是一样的,我不记得如何做可移植的.
>如果输出文件名是目录,则可能需要将文件复制到目录中.
>如果输出文件已经存在(使用O_EXCL打开以确定此错误并检查EEXIST是否有错误),则可能需要执行与cp -i不同的操作.
>您可能希望输出文件的权限反映输入文件的权限.
>您可能需要复制其他平台特定的元数据.
>您可能希望或可能不希望取消输出文件的错误.
显然,所有这些问题的答案可能是“做同样的cp”.在这种情况下,原始问题的答案是“忽略我或任何其他人所说的一切,并使用cp的来源”.