带进度的快速文件复制

mav*_*mav 2 c++ performance sdl copy file

我正在为 Linux 编写一个 SDL 应用程序,它可以从控制台(没有 X 服务器)运行。我的一个功能是文件复制机制,它将特定文件从 HDD 复制到 USB 闪存设备,并在 UI 中显示此复制的进度。为此,我使用简单的 while 循环并按 8kB 块复制文件以获取复制进度。问题是,它很慢。我在将近 10 分钟内复制了一个 100 MB 的文件,这是不可接受的。

如何实现更快的文件复制?我正在考虑一些异步 API,可以将文件从 HDD 读取到缓冲区并将数据存储到 USB 中的单独线程中,但我不知道是否应该自己实现这一点,因为它看起来不是一件容易的事。也许你知道一些 C++ API/库可以帮助我?或者也许其他一些更好的方法?

Ami*_*shk 5

让操作系统完成所有工作:

  1. 将文件映射到内存:mmap,将大大加快读取过程。
  2. 使用msync将其保存到文件中。


Ada*_*eld 5

不要用复制进度同步更新你的 UI,这会大大减慢速度。您应该在与主 UI 线程不同的线程上运行文件复制,以便文件复制可以尽快进行,而不会影响应用程序的响应能力。然后,UI 可以以自然速率(例如,以显示器的刷新率)更新自身。

您还应该使用大于 8 KB 的缓冲区大小。尝试一下,但我认为使用更大的缓冲区大小(例如在 64-128 KB 范围内)您会获得更快的结果。

所以,它可能看起来像这样:

#define BUFSIZE (64*1024)

volatile off_t progress, max_progress;

void *thread_proc(void *arg)
{
    // Error checking omitted for expository purposes
    char buffer[BUFSIZE];
    int in = open("source_file", O_RDONLY);
    int out = open("destination_file", O_WRONLY | O_CREAT | O_TRUNC);

    // Get the input file size
    struct stat st;
    fstat(in, &st);

    progress = 0;
    max_progress = st.st_size;

    ssize_t bytes_read;
    while((bytes_read = read(in, buffer, BUFSIZE)) > 0)
    {
        write(out, buffer, BUFSIZE);
        progress += bytes_read;
    }

    // copy is done, or an error occurred
    close(in);
    close(out);

    return 0;
}

void start_file_copy()
{
    pthread_t t;
    pthread_create(&t, NULL, &thread_proc, 0);
}

// In your UI thread's repaint handler, use the values of progress and
// max_progress
Run Code Online (Sandbox Code Playgroud)

请注意,如果您将文件发送到套接字而不是另一个文件,则应改为使用sendfile(2)系统调用,它直接将文件复制到内核空间中,而无需往返于用户空间。当然,如果这样做,您将无法获得任何进度信息,因此这可能并不总是理想的。

对于 Windows 系统,您应该使用CopyFileEx,它既高效又为您提供进度回调例程。