PHP:使用fread读取远程文件,块大小不断变化


PHP: Reading remote file using fread, chunk size keeps varying

我正在使用以下类型的函数来读取远程文件

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。

由于在开始上传之前需要预先定义chunksize,因此改变chunksize会使上传变得混乱。

----编辑----

如果流是读缓冲的并且它不表示普通文件,最多一次读取最多等于块大小的字节数(通常为8192);根据先前缓冲的数据返回的数据的大小可以大于块大小。

有办法绕过这个吗?

或者除了使用fopen和fread之外,我如何从远程文件中读取数据块

我发现PHP引擎的Chunk大小默认为8kB
http://php.net/manual/en/function.fread.php

如果流是读缓冲的并且它不表示普通文件,最多一次读取最多等于块大小的字节数(通常为8192);根据先前缓冲的数据返回的数据的大小可以大于块大小。

在示例代码中CCD_ 1只能小于内部默认块大小。

fread($rfile, BUFSIZ);

但是,如果从远程源读取,实际读取的数据量仍然取决于网络带宽。

当您在Linux上使用strace监控脚本时,您可以看到这一点:

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)

我们看到,第一个下载的Chunk只有4kB,只有第二个真正装满了8kB,但随后的Chunk只装满了小于2kb的

在这种情况下,带宽确实限制了下载
上传也会发生同样的情况

您可以使用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);

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.
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我搜索了几个小时

在所有错误的地方,似乎

编者按:顺便提一下,问题在哪里?