2009-10-02 2 views
5

500MB를 초과하는 대용량 로그 파일을 생성하는 응용 프로그램이 있습니다.파이썬에서 UTF-8로 인코딩 된 문서를 찾아보고 말할 수 있습니까?

필자는 파이썬에서 로그 파일을 빠르게 찾아보고 관심있는 데이터를 찾을 수있는 몇 가지 유틸리티를 작성했습니다. 그러나 이제는 파일이 너무 커서 전체를 메모리에로드 할 수없는 일부 데이터 세트를 얻습니다.

그래서 나는 문서를 한 번 스캔하고 색인을 작성한 다음 문서의 섹션을 한 번에보고 싶은 메모리에로드하려고합니다.

이 파일은 한 번에 한 줄씩 읽고 파일을 열 때 file.tell()에서 오프셋을 저장할 때 유용합니다. 그런 다음 나중에 file.seek (offset, 0)을 사용하여 파일의 해당 섹션으로 돌아갈 수 있습니다.

그러나 내 문제는 로그 파일에 UTF-8이있어 코덱 모듈 (codecs.open(<filename>, 'r', 'utf-8'))을 열어야한다는 것입니다. 결과 객체를 사용하여 찾기와 말하기를 호출 할 수 있지만 일치하지 않습니다.

나는 코덱이 약간의 버퍼링을 필요로한다고 가정하고 말하자면 바이트 수 대신 문자 수를 반환한다고 가정합니까?

이 방법이 있습니까?

답변

2

사실 인 경우, 이것은 혼동하는 바이트 및 문자 오프셋이므로 코덱 모듈의 버그 또는 제한 사항처럼 들립니다.

파일을 여는 데 일반 open() 함수를 사용하면 seek()/tell()은 항상 일관적인 바이트 오프셋을 제공합니다. 읽을 때마다 f.readline().decode('utf-8')을 사용하십시오.

그러나 f.read() 함수를 사용하면 멀티 바이트 문자의 중간에 착륙 할 수 있으므로 UTF-8 디코딩 오류가 발생합니다. readline()이 항상 작동합니다.

이것은 바이트 순서 표시를 투명하게 처리하지는 않지만 로그 파일에 BOM이 없을 가능성이 있습니다.

+0

엄밀히 말하면 UTF-8에는 가능한 한 바이트 순서 만 있으므로 바이트 순서 표시에는 사용되지 않으므로 UTF-8에 대해서는 바이트 순서 표시가 유효하지 않습니다. 그럼에도 불구하고 일부 UTF-8 인코더는 바이트 순서 표시를 잘못 앞에 붙이고 일부 UTF-8 디코더는 바이트 순서 표시로 인코딩 된 입력을 허용합니다. – yfeldblum

+2

UTF-8에 바이트 순서가 없다는 것은 사실입니다. 그러나 바이트 순서 표시는 파일이 UTF-8로 인코딩되었음을 나타 내기 위해 종종 사용됩니다. 나는이 사용법을 "부정확"이라고 부르지 않을 것이다. – intgr

1

UTF-8의 경우 실제로 codecs.open을 사용하여 파일을 열 필요가 없습니다. 대신 파일을 바이트 문자열로 먼저 읽은 다음 개별 섹션을 디코딩해야합니다 (문자열에서 .decode 메서드를 호출). 라인 경계에서 파일을 깨는 것은 안전합니다. 분할하는 유일한 안전하지 않은 방법은 멀티 바이트 문자의 중간에있을 것입니다 (바이트 값> 128에서 인식 할 수 있습니다).

0

업데이트 : codec.open()이 반환 한 객체에 대해 seek/tell을 수행 할 수 없습니다. 일반 파일을 사용하고 읽을 때 유니 코드로 문자열을 디코딩해야합니다.

왜 작동하지 않는지만 나는 그것을 작동하게 할 수 없는지 모르겠다. 예를 들어 한 번만 찾으면됩니다. 그런 다음 파일을 닫았다가 다시 열어야합니다. 물론 유용하지 않습니다.

tell은 문자 위치를 사용하지 않지만 스트림에서의 위치는 표시하지 않습니다 (그러나 기본 파일 객체가 디스크에서 읽는 중일 수 있습니다).

아마 기본 버퍼링 때문에 당신은 그것을 할 수 없습니다. 하지만 독서를 마친 후에는 문제가 없으므로 그 문제를 해결하십시오.

1

파이썬에서 UTF8을 사용하는 방법을 보면 파이썬에서 UTF8과 관련된 많은 부분이 의미가 있습니다.파이썬 3으로 다이빙에서 파일 장을 읽으면 귀하의 경우에는, 꽤 좀 더 의미가 있습니다 : http://diveintopython3.org/files.html

그것의 짧은,하지만입니다 유니 코드 문자 반면 바이트 위치와 file.seekfile.tell 일, 여러 바이트를 차지할 수 있습니다. 따라서, 당신이 할 경우 :

f.seek(10) 
f.read(1) 
f.tell() 

당신은 쉽게 당신이 읽은 하나 개의 문자가 무엇인지 길이에 따라, 17보다 다른 무언가를 얻을 수 있습니다.