Как передать файлы размером более 2 147 483 646 байт (~2 ГиБ) с помощью Win32 TransmitFile()?
Цитируется из записи MSDN для TransmitFile:
Максимальное количество байтов, которое может быть передано с помощью одного вызова функции TransmitFile, составляет 2 147 483 646, максимальное значение для 32-разрядного целого числа минус 1. Максимальное количество байтов, отправляемых за один вызов, включает любые данные, отправленные до или после данные файла, на которые указывает параметр lpTransmitBuffers, плюс значение, указанное в параметре nNumberOfBytesToWrite для длины данных файла для отправки. Если приложению необходимо передать файл, размер которого превышает 2 147 483 646 байт, то можно использовать несколько вызовов функции TransmitFile, при этом каждый вызов передает не более 2 147 483 646 байт. Установка параметра nNumberOfBytesToWrite в ноль для файла размером более 2 147 483 646 байт также завершится ошибкой, поскольку в этом случае функция TransmitFile будет использовать размер файла в качестве значения для количества байтов для передачи.
Хорошо. Отправка файла размером 2*2,147,483,646 bytes
(~ 4 ГиБ) с TransmitFile затем должен быть разделен как минимум на две части (например, 2 ГиБ + 2 ГиБ при двух вызовах TransmitFile). Но как именно это можно сделать, предпочтительно также поддерживая основное TCP-соединение между ними?
Когда размер файла действительно <=2 147 483 646 байт, можно просто написать:
HANDLE fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
TransmitFile(SOCK_STREAM_socket, fh, 0, 0, NULL, NULL, TF_DISCONNECT);
позволить Windows обрабатывать все вещи более низкого уровня (кэширование, разбиение данных на части для эффективной передачи и т. д. Однако, в отличие от сопоставимого системного вызова sendfile() в Linux, в вызове нет очевидного аргумента смещения (хотя пятый аргумент), LPOVERLAPPED lpOverlapped
наверное это именно то, что я ищу). Я полагаю, что я мог бы взломать что-то вместе, но я также ищу изящное, хорошее решение Win32 от кого-то, кто действительно знает об этом.
Вы можете использовать параметр lpOverlapped, чтобы указать 64-битное смещение в файле, с которого начинается передача данных файла, установив элемент Offset и OffsetHigh структуры OVERLAPPED. Если lpOverlapped является указателем NULL, передача данных всегда начинается с текущего байтового смещения в файле.
Итак, из-за отсутствия минимального примера, легко доступного в сети, какие вызовы необходимы для выполнения такой задачи?
1 ответ
Удалось выяснить это по комментариям.
Так что если LPOVERLAPPED lpOverlapped
нулевой указатель, вызов начинает передачу с текущего смещения файла (очень похоже на Linux sendfile()
системный вызов и его off_t *offset
параметр). Этим смещением (указателем) можно манипулировать с помощью SetFilePointerEx
так можно написать:
#define TRANSMITFILE_MAX ((2<<30) - 1)
LARGE_INTEGER total_bytes;
memset(&total_bytes, 0, sizeof(total_bytes));
while (total_bytes < filesize) {
DWORD bytes = MIN(filesize-total_bytes, TRANSMITFILE_MAX);
if (!TransmitFile(SOCK_STREAM_socket, fh, bytes, 0, NULL, NULL, 0))
{ /* error handling */ }
total_bytes.HighPart += bytes;
SetFilePointerEx(fh, total_bytes, NULL, FILE_BEGIN);
}
closesocket(SOCK_STREAM_socket);
выполнить задачу. Не очень элегантно, но это работает.