Не обновляйте синхронно ваш пользовательский интерфейс с прогрессом копирования, это значительно замедлит процесс. Вам следует запускать копию файла в отдельном потоке от основного потока пользовательского интерфейса, чтобы копирование файла могло выполняться максимально быстро, не мешая отзывчивости вашего приложения. Затем пользовательский интерфейс может обновляться с естественной частотой (например, с частотой обновления вашего монитора).
Вы также должны использовать больший размер буфера, чем 8 КБ. Поэкспериментируйте, но я думаю, вы получите более быстрые результаты с большими размерами буфера (например, в диапазоне 64-128 КБ).
Итак, это может выглядеть примерно так:
#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
Обратите внимание, что если вы отправляете файл в сокет вместо другого файла, вам следует вместо этого использовать системный вызов sendfile(2)
, который копирует файл непосредственно в пространство ядра без кругового отключения в пользовательское пространство. Конечно, если вы это сделаете, вы не сможете получить какую-либо информацию о прогрессе, поэтому она не всегда может быть идеальной.
Для систем Windows вы должны использовать CopyFileEx
, который одновременно эффективен и обеспечивает выполнение процедуры обратного вызова.