2009-08-19 1 views
2

이진 비교자를 만들기 위해 CreateFileW 함수를 사용하여 두 파일의 이진 내용을 읽으려고합니다. 그러나 이로 인해 전체 파일이 메모리로 버퍼링되어 큰 파일 (500MB)의 경우 문제가됩니다.C++에서 전체 파일을 메모리에 버퍼링하지 않고 이진 파일 읽기

필자는 대신 파일의 일부만 버퍼링 할 수있는 다른 기능을 살펴 보았지만 버퍼가 이러한 기능을 수행하는 방법을 구체적으로 설명하는 문서를 찾지 못했습니다. 이것은 어쩌면 나는 명백한 것을 놓치고있다).

지금까지 가장 잘 나온 부분은 ReadFile입니다. 버퍼를 정의 할 수있는 것처럼 보이지만 CreateFileW가있는 것처럼 배후에 다른 버퍼가 구현되지 않을지는 확실하지 않습니다.

여러분이 사용하기에 좋은 기능이 무엇인지에 대한 의견이 있으십니까?

+3

왜'CreateFile'가 전체 파일을 메모리에 저장한다고 생각합니까? –

+1

@pavel 좋은 점 CreateFileW는 전체 파일을 메모리에 버퍼링하지 않습니다. 꽤 많은 파일을 처리합니다. 이 핸들을 사용하여 전체 파일 또는 파일의 일부 (선택한 부분)를 읽을 수 있습니다. – leeeroy

+0

맞아요, 방금 내가 수동으로보고 있던 코드가 모든 것을 메모리에 저장 했으므로, 거대한 발자국임을 깨달았습니다. 그래서 이것은 레거시 코드, grr을 다루는 것 같은 느낌입니다 ... –

답변

7

메모리 매핑 된 파일을 사용하여이 작업을 수행 할 수 있습니다. createFile으로 열려면 createFileMapping을 사용하고 MapViewOfFile을 사용하여 데이터에 대한 포인터를 가져옵니다.

+0

이것은 정확히 내가 필요로했던 것입니다, 감사합니다! –

5

CreateFile 버퍼링의 의미를 잘 모름 - CreateFile은 파일의 전체 내용을 읽지 않으며 ReadFile을 호출하기 전에 CreateFile을 호출해야합니다.

ReadFile을 당신이 원하는 것을 할 것입니다 - OS가 일부 캐시 데이터를 opportunisticly 앞서 데이터의 읽기 할 수 있지만,이 글은 파일의 전체 500MB의 읽지 않습니다

을 정말 버퍼링이없는 것으로합니다. FILE_FLAG_NO_BUFFERING을 CreateFile로 전달하고 파일 액세스가 볼륨 섹터 크기의 배수인지 확인하십시오. 필자는 그렇게하지 말 것을 강력하게 제안합니다. 이유는 시스템 파일 캐시가 존재하고 성능에 도움이됩니다. 메모리에있는 파일을 캐싱하면 시스템 파일 캐시가 줄어들어 메모리 사용량에 영향을 미치지 않습니다.

다른 언급했듯이 메모리 매핑 된 파일도 사용할 수 있습니다. 메모리 매핑 파일과 ReadFile의 차이점은 주로 인터페이스뿐입니다. 궁극적으로 파일 관리자는 일부 버퍼링을 포함하여 유사한 방식으로 요청을 처리합니다. 인터페이스는 좀 더 직관적 인 것처럼 보입니다. 그러나 발생하는 모든 오류는 예외가 발생하여 프로그램을 중단시킬 수 있습니다.

+0

그는 가상 메모리에 대해 걱정할 수도 있습니다. 32 비트 주소 공간에서는 500MB 파일을 저장할 충분한 공간이 없을 수 있습니다. RAM에 실제로 복사되는지 여부는 문제가되지 않습니다. –

+0

그래도 한 번에 500MB를 읽을 필요는 없습니다. – Michael

5

CreateFile()을 호출해도 대상 파일의 내용을 버퍼링하거나 읽지 않습니다. 또한

DWORD cbRead; 
BYTE buffer[1024]; 
HANDLE hFile = ::CreateFile(filename, 
          GENERIC_READ, 
          FILE_SHARE_READ, 
          NULL, 
          OPEN_EXISTING, 
          FILE_ATTRIBUTE_NORMAL, 
          NULL); 
::ReadFile(hFile, sizeof(buffer), &cbRead, NULL); 
::CloseHandle(hFile); 

당신의 임의의 부분을 읽으려면 : CreateFile이()를 호출 한 후에 예제는 파일의 첫 번째 킬로바이트를 읽을 원하는 파일의 어떤 부분을 얻기 위해 ReadFile()를 호출해야합니다

DWORD cbRead; 
BYTE buffer[1024]; 
HANDLE hFile = ::CreateFile(filename, 
          GENERIC_READ, 
          FILE_SHARE_READ, 
          NULL, 
          OPEN_EXISTING, 
          FILE_ATTRIBUTE_NORMAL, 
          NULL); 
::SetFilePointer(hFile, 1024 * 1024, NULL, FILE_BEGIN); 
::ReadFile(hFile, sizeof(buffer), &cbRead, NULL); 
::CloseHandle(hFile); 

당신은 물론, SetFilePointer를() 및 ReadFile을을 (호출 할 수 있습니다) 여러 번 : 파일, 당신은 일킬로바이트 파일에 일메가바이트를 시작 읽을 예를 들어, ReadFile을()를 호출하기 전에 SetFilePointer()을 사용할 수 있습니다 파일이 열려있는 동안 원하는대로 ReadFile() 호출은 파일 포인터를 ReadFile()이 읽은 마지막 바이트 바로 다음의 바이트로 암시 적으로 설정합니다.

또한 사용하는 File Management Functions에 대한 설명서를 읽고 반환 값을 적절하게 검사하여 발생할 수있는 오류를 잡아 두어야합니다.

Windows는 자유 재량에 따라 열려있는 파일의 내용을 캐시하기 위해 사용 가능한 시스템 메모리를 사용할 수 있지만 실행중인 프로그램에서 메모리가 필요한 경우이 프로세스로 캐시 된 데이터는 삭제됩니다 (결국 캐시 된 데이터는 필요한 경우 디스크에서 다시 읽음).