0

尝试通过在 c 中一次复制 n 个字节来将文件的内容复制到另一个文件。我相信下面的代码可以一次复制一个字节,但我不确定如何使它适用于 n 个字节,尝试制作一个大小为 n 的字符数组并将读/写函数更改为read(sourceFile , &c, n)and write(destFile , &c, n),但是缓冲区似乎不是那样工作的。

#include <fcntl.h>    
#include <unistd.h> 
#include <stdint.h>
#include <time.h>

void File_Copy(int sourceFile, int destFile, int n){
    char c;

    while(read(sourceFile , &c, 1) != 0){
        write(destFile , &c, 1);
    }


}

int main(){
    int fd, fd_destination;      
    fd = open("source_file.txt", O_RDONLY); //opening files to be read/created and written to
    fd_destination = open("destination_file.txt", O_RDWR | O_CREAT); 

    clock_t begin = clock(); //starting clock to time the copying function

    File_Copy(fd, fd_destination, 100); //copy function

    clock_t end = clock();
    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; //timing display

return 0;
}
4

3 回答 3

1

如何使它适用于 n 个字节

只需读取 N 个字节并复制您成功读取的那么多字节。

#define N  4096 
void File_Copy(int sourceFile, int destFile, int n){
    char c[N];
    const size_t csize = sizeof(c)/sizeof(*c);
    while (1) {
        const ssize_t readed = read(sourceFile, c, csize);
        if (readed <= 0) {
            // nothing more to read
            break;
        }
        // copy to destination that many bytes we read
        const ssize_t written = write(destFile, c, readed);
        if (written != readed) {
            // we didn't transfer everything and destFile should be blocking
            // handle error
            abort();
        }
    }
}
于 2020-02-26T11:49:38.823 回答
0

这是我使用lseek的版本(不需要循环):它依赖于读取和写入,始终处理完整的缓冲区,而不是其中的一部分(我不知道这是否得到保证)。

void File_Copy(int sourceFile, int destFile)
{
    off_t s = lseek(sourceFile, 0, SEEK_END);
    lseek(sourceFile, 0, SEEK_SET);

    char* c = malloc(s);

    if (read(sourceFile, c, s) == s)
        write(destFile, c, s);

    free(c);
}

以下代码不依赖此假设,也可用于不支持lseek的文件描述符。

void File_Copy(int sourceFile, int destFile, int n)
{
    char* c = malloc(n);
    while (1)
    {
        ssize_t readStatus = read(sourceFile, c, n);
        if (readStatus == -1)
        {
            printf("error, read returned -1, errno: %d\n", errno);
            return;
        }
        if (readStatus == 0)
            break; // EOF

        ssize_t bytesWritten = 0;
        while (bytesWritten != readStatus)
        {
            ssize_t writeStatus = write(destFile, c + bytesWritten, readStatus - bytesWritten);
            if (writeStatus == -1)
            {
                printf("error, write returned -1, errno is %d\n", errno);
                return;
            }
            bytesWritten += writeStatus;
            if (bytesWritten > readStatus) // should not be possible
            {
                printf("how did 'bytesWritten > readStatus' happen?");
                return;
            }
        }
    }
    free(c);
}

在我的系统(PCIe SSD)上,我使用 1MB 到 4MB 之间的缓冲区获得最佳性能(您也可以使用 dd 来查找此大小)。更大的缓冲区没有意义。而且您需要大文件(尝试 50GB)才能看到效果。

于 2020-02-26T13:21:40.650 回答
0

您想n一次复制一个大小的缓冲区:

void File_Copy(int sourceFile, int destFile, int n){
    char c[n];

    ssize_t st;
    while((st = read(sourceFile , c, n)) > 0){
        write(destFile , c, st);
    }
}

请注意,不一定n总是一次复制字节,它可能会更少。当写入的字节数减少时,您还必须检查返回值write()并处理这种情况,因为它符合您的需要。

一个例子是循环:

while (st > 0) {
    int w = write(destFile, c, st);
    if (w < 0) {
        perror("write");
        return;
    }
    st -= w;
}

另一个问题:当您在此处创建目标文件时

fd_destination = open("destination_file.txt", O_RDWR | O_CREAT);

您没有指定第三个模式参数。这会导致随机模式,这可能会导致open()下一次失败。所以最好添加一个有效模式,例如这样:

fd_destination = open("destination_file.txt", O_RDWR | O_CREAT, 0644);

这可能会扭曲您的测试结果。

于 2020-02-26T11:49:05.840 回答