繁体   English   中英

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。

变化的块大小会干扰上传,因为在开始上载之前需要预先定义块大小。

- - 编辑 - -

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

反正绕过这个?

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

我发现默认情况下,PHP引擎的块大小为8kB。
http://php.net/manual/zh/function.fread.php

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

示例代码中的BUFSIZ只能小于内部默认的“块大小”。

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却只有不到2 kb

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

您可以使用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.
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我搜索了几个小时

...似乎在所有错误的地方

编辑:作为旁注-问题在哪里?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM