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

时间:2014-10-24 17:51:26

标签: 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使用chkksizes读取文件,如2kb,3kb,7kb等,而不是指定的chunksize

我搜索了几个小时但却无法找出问题。

我实际上是在尝试下载远程文件并上传它,文件很大,这会在服务器上造成内存问题,因此我无法使用file_get_contents。

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

---- ----编辑

  

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

无论如何要绕过这个?

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

2 个答案:

答案 0 :(得分:0)

我发现默认情况下PHP引擎的块大小为8kB http://php.net/manual/en/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但后续的Chunks只填充了不到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);

答案 1 :(得分:-1)

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

我搜索了几个小时

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

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