PHP: чтение удаленного файла с использованием fread, размер чанка постоянно меняется

Я использую следующую функцию для чтения удаленных файлов

define('BUFSIZ', 4095);
$url = "file url";
$rfile = fopen($url, 'r');
$lfile = fopen(basename($url), 'w');
while(!feof($rfile))
fwrite($lfile, fread($rfile, BUFSIZ), BUFSIZ);
fclose($rfile);
fclose($lfile);

но fread читает файл с размерами фрагментов, такими как 2kb, 3kb, 7kb и т. д., а не с указанным размером фрагмента

Я искал несколько часов, но не смог выяснить проблему.

Я на самом деле пытаюсь загрузить удаленный файл и загрузить его, файлы большие, что создает проблемы с памятью на сервере, поэтому я не могу использовать file_get_contents.

Изменение размера фрагмента портит загрузку, так как размер фрагмента должен быть предварительно определен до начала загрузки.

—-Редактировать—-

если поток читается как буферизованный и не представляет простой файл,
не более одного чтения до количества байтов, равного размеру куска
(обычно 8192) сделано; в зависимости от ранее буферизованных данных,
Размер возвращаемых данных может быть больше, чем размер чанка.

в любом случае, чтобы обойти это?

Или же Как я могу прочитать данные из удаленных файлов в чанках, кроме использования FOPEN и Fread?

1

Решение

Я обнаружил, что PHP Engine по умолчанию имеет размер чанка 8 КБ.
http://php.net/manual/en/function.fread.php

если поток читается как буферизованный и не представляет простой файл,
не более одного чтения до количества байтов, равного размеру куска
(обычно 8192) сделано; в зависимости от ранее буферизованных данных,
Размер возвращаемых данных может быть больше, чем размер чанка.

в примере кода BUFSIZ может быть меньше, чем внутренний размер чанка по умолчанию.

fread($rfile, BUFSIZ);

Но все же фактический объем прочитанных данных зависит от пропускной способности сети, если вы читаете из удаленного источника.

Вы можете увидеть это, когда вы контролируете свой скрипт с strace в Linux:

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("<remote.ip>")}, 16) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLOUT}])
getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
fcntl(3, F_SETFL, O_RDWR)               = 0
sendto(3, "GET /remote_file.txt HTTP"..., 181, MSG_DONTWAIT, NULL, 0) = 181
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "HTTP/1.1 200 OK\r\nDate: Mon, 15 M"..., 8192, MSG_DONTWAIT, NULL, NULL) = 4320
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "\362F\334\350h\t\350 \211R\200\272\312}\320Ftn~\240\350\32k\177\265\333\\\257\222\345?\203"..., 8192, MSG_DONTWAIT, NULL, NULL) = 8192
poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "\350", 1, MSG_PEEK, NULL, NULL) = 1
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "\350\260r\205D\5\343\377\323\357\306B6\335|\213OM\205\237i\236\306\356(\304-\214F\305=>"..., 8192, MSG_DONTWAIT, NULL, NULL) = 1834
poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "/\26\v\f\250!(\2\22\342\250\235i\fKQe\2058\322\275\315:\270f\266\24R\326bn\371"..., 8192, MSG_DONTWAIT, NULL, NULL) = 1440
poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)

Мы видим, что первый загруженный блок имеет только 4 КБ, и только второй действительно заполнен 8 КБ, но последующие блоки только заполнены менее чем 2 КБ.

Пропускная способность ограничивает загрузку в этом случае.
То же самое произойдет с загрузкой.

Вы можете изменить размер чанка соединения с помощью функции PHP stream_set_chunk_size()
http://php.net/manual/en/function.stream-set-chunk-size.php

$rfile = fopen($url, 'r');
$lfile = fopen(basename($url), 'w');
stream_set_chunk_size($rfile, BUFSIZ);
stream_set_chunk_size($lfile, BUFSIZ);
0

Другие решения

http://php.net/manual/en/function.fread.php говорится, что

if the stream is read buffered and it does not represent a plain file,
at most one read of up to a number of bytes equal to the chunk size
(usually 8192) is made; depending on the previously buffered data, the
size of the returned data may be larger than the chunk size.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

я искал часами

… во всех неправильных местах кажется

РЕДАКТИРОВАТЬ: в качестве дополнительного примечания — где вопрос?

-1

По вопросам рекламы [email protected]