2013-06-14 4 views
5

매우 큰 파일 (약 20GB)을 가지고 있는데 어떻게 fseek()를 사용하여 건너 뛰고 그 내용을 읽을 수 있습니까?PHP : fseek() 대용량 파일 (> 2GB)

코드는 다음과 같습니다 : $가 < 2147483647

업데이트 오프셋 (offset)를 가지는 경우에

function read_bytes($f, $offset, $length) { 
    fseek($f, $offset); 
    return fread($f, $length); 
} 

결과는 올바른 : 나는 창 (64), 은 phpinfo에서 실행 오전 - 건축 : 64를, PHP_INT_MAX : 2147483647

+0

파일을 어떻게여시겠습니까? –

+0

$ f = fopen ('data.log', 'r'); – anvoz

+1

32 비트 또는 64 비트를 사용하고 있습니까? – Baba

답변

3

는, 나는 큰 파일 (> 3기가바이트)에 오프셋 BIG에서 10킬로바이트의 블록을 읽는 데 필요한. 쓰기는 항상 추가되었으므로 오프셋이 필요하지 않습니다.

사용중인 PHP 버전 및 OS에 관계없이이 방법으로 작동합니다.

사전 필수 = 서버가 범위 검색 쿼리를 지원해야합니다. 아파치 & IIS는 이미이 지원하는 다른 웹 서버 (공유 호스팅 또는 기타)

// offset, 3GB+ 
$start=floatval(3355902253); 

// bytes to read, 100 KB 
$len=floatval(100*1024); 

// set up the http byte range headers 
$opts = array('http'=>array('method'=>'GET','header'=>"Range: bytes=$start-".($start+$len-1))); 
$context = stream_context_create($opts); 
// bytes ranges header 
print_r($opts); 

// change the URL below to the URL of your file. DO NOT change it to a file path. 
// you MUST use a http:// URL for your file for a http request to work 
// this will output the results 
echo $result = file_get_contents('http://127.0.0.1/dir/mydbfile.dat', false, $context); 

// status of your request 
// if this is empty, means http request didnt fire. 
print_r($http_response_header); 

// Check your file URL and verify by going directly to your file URL from a web 
// browser. If http response shows errors i.e. code > 400 check you are sending the 
// correct Range headers bytes. For eg - if you give a start Range which exceeds the 
// current file size, it will give 406. 

// NOTE - The current file size is also returned back in the http response header 
// Content-Range: bytes 355902253-355903252/355904253, the last number is the file size 

... 

의 99 % ...

...

보안처럼 - 당신은 htaccess로를 추가해야합니다 규칙은 로컬 IP 127.0.0.1에서 오는 것을 제외하고이 데이터베이스 파일에 대한 모든 요청을 거부합니다.

+0

이 솔루션을 시도했지만 메모리가 고갈되었습니다. 'offset/maxlen parameters' 또는'Range header'를 사용하면'file_get_contents'가 전체 파일을 메모리로 읽어들이는 것을 막을 수 있습니까? – anvoz

+0

http 범위 헤더는 사용자가 요청한 양 (이 경우 100KB) 만 검색하므로 거기에 메모리 문제가 없습니다. 그래서 문제는 PHP 스크립트입니다. 10MB를 읽는다면 PHP 메모리 제한을 두 배로 설정하십시오. ini_set ('memory_limit', '20M'); –

+0

20GB 파일 중 단지 200 바이트 ('$ len = floatval (200);') 만 읽었습니다. 내'memory_limit'는 1024M입니다. (테스트를 위해 더 큰 값을 시도했습니다.) 파일을 메모리에로드하는 데 몇 분이 걸리는 요청은 소모 된 메모리 오류로 중단됩니다. – anvoz

5

경고 : 주석에서 언급했듯이 fseek은 INT를 내부적으로 사용하며 단순히 32 비트 PHP 컴파일로 큰 파일을 가지고 작업을 수행 할 수 없습니다. 해결책을 따르십시오 실 거예요. 여기서는 참조 용으로 남겨 두었습니다.

검색의 조금 fseek과에 대한 PHP 매뉴얼 페이지에 대한 의견를 알려준 :

http://php.net/manual/en/function.fseek.php

문제가 오프셋 매개 변수에 대한 최대 INT 크기이지만 여러 작업을 수행하여이를 해결할 수 있습니다 보인다 fseek는 SEEK_CUR 옵션을 사용하여 호출하고 큰 숫자 처리 라이브러리 중 하나와 섞습니다.

예 : 내 프로젝트에 대한

function fseek64(&$fh, $offset) 
{ 
    fseek($fh, 0, SEEK_SET); 
    $t_offset = '' . PHP_INT_MAX; 
    while (gmp_cmp($offset, $t_offset) == 1) 
    { 
     $offset  = gmp_sub($offset, $t_offset); 
     fseek($fh, gmp_intval($t_offset), SEEK_CUR); 
    } 
    return fseek($fh, gmp_intval($offset), SEEK_CUR); 
} 

fseek64($f, '23456781232'); 
+0

흠.하지만 64 비트 시스템에서 64 비트 시스템으로 작업하고 있다면 문제가 다른 곳에서 발생합니다. – fsw

+1

이것은 또한 php에 대한 코멘트에서 downvoted입니다. 나는'$ offset = $ offset - $ t_offset;이 줄 때문에이 줄 수 있다고 생각합니다. '$ 오프셋은 할당의 오른쪽을 해결하기 위해 int로 캐스팅되어야합니다 어떤 PHP_INT_MAX 이상 수 없습니다 – Orangepill

+0

나는 20GB 파일에 시도 : 'fseek64 ($ f, 2200000000); //220,000,000' 'echo fread ($ f, 100);' 그 다음 파일의 작은 부분 인 2bil 바이트를 두 번째 부분에 시도했습니다 : 'fseek ($ f, 200000000); // 200,000,000' 'echo fread ($ f, 100); ' 두 가지 결과가 다릅니다. – anvoz