Клиент или сервер должны читать данные порциями (я бы сделал кратные размеру страницы или что-то подобное) и записывать порции на диск. Нет необходимости иметь весь файл в оперативной памяти одновременно.
Что-то вроде этого псевдо-кода (проверка ошибок и аналогичные опущены) на принимающей стороне:
chunk = new byte[4096];
while(int size = recv(socket, chunk, 4096)) {
write(file, chunk, size);
}
Таким образом, приведенный выше пример для сервера, клиент будет делать то же самое.
chunk = new byte[4096];
while(int size = read(file, chunk, 4096)) {
send(sock, chunk, size);
}
EDIT:
Чтобы ответить на ваш комментарий. Следует иметь в виду, что смещение в файле не обязательно должно быть 32-разрядным в 32-разрядной системе, оно может быть 64-разрядным, поскольку на самом деле это не указатель, а просто смещение от начало файла. Если ОС поддерживает 64-битные смещения (и все современные windows / linux / osx поддерживают), вам не нужно об этом беспокоиться. Как уже отмечалось, файловая система, к которой пытается обратиться ОС, также является фактором, но я полагаю, что если у вас есть файл, размер которого превышает 4 ГБ, он явно находится в файловой системе, которая его поддерживает; -).