2013-08-14 2 views
4

Цитируется MSDN entry for TransmitFile:Как передать файлы размером более 2,147,483,646 байт (~ 2 гигабайт) с помощью Win32 TransmitFile()?

Максимальное число байтов, которые могут быть переданы с использованием одного вызова к функции TransmitFile является 2147483646, максимальное значение для 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 GiB) с TransmitFile затем должна быть разделена на две части минимум (например, 2 GiB + 2 GiB в двух вызовах TransmitFile). Но как точно хотел бы сделать это, в то время как предпочтительно также поддерживать базовое TCP-соединение живым между ними?

Когда файл действительно < = 2147483646 байт, один мог бы просто написать:

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, все вещи более низкого уровня (кэширование, отрывы данных на часть для эффективной передачи и т. д. Однако, в отличие от сопоставимого сценария Linux sendfile(), в вызове нет очевидного аргумента смещения (хотя пятый аргумент LPOVERLAPPED lpOverlapped, вероятно, именно то, что я ищу). Я полагаю, я мог бы что-то взломать, m также ищет изящное, эффективное решение Win32 от тех, кто действительно знает об этом.

Вы можете использовать параметр lpOverlapped, чтобы указать 64-битное смещение в файле, с которого можно начать передачу данных файла, установив член Offset и OffsetHigh структуры OVERLAPPED. Если lpOverlapped является указателем NULL, передача данных всегда начинается с текущего смещения байта в файле.

Таким образом, из-за отсутствия минимального примера, легко доступного в сети, какие вызовы необходимы для выполнения такой задачи?

+1

Если вы не передадите флаг 'TF_DISCONNECT', предположительно, вы можете сделать другой вызов' TransmitFile() 'для отправки следующих 2GB и т. Д. Параметр 'lpOverlapped' - это действительно то, как вы предоставляете смещение файла. –

+0

Он просто читает файл в своем текущем положении. –

+2

Вы пробовали 'Socket.SendFile()'?MSDN ничего не говорит о размере файла, поэтому я предполагаю (хотя и никогда не пытаюсь) он справится с этим обстоятельством. 'socket.sendFile' использует функцию TransmitFile для выполнения задания. Также взгляните на 'SetFilePointerEx', чтобы расположить файл перед каждым вызовом на' TransmitFile'. –

ответ

2

Удалось выяснить, основываясь на комментариях.

Итак, если 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); 

для выполнения этой задачи. Не очень элегантный imo, но он работает.

+0

Вы должны принять свой собственный ответ, чтобы вопрос не отображался в неотвеченном списке. –