[python] 거대한 텍스트 파일에서 특정 줄로 이동하는 방법은 무엇입니까?

아래 코드에 대한 대안이 있습니까?

startFromLine = 141978 # or whatever line I need to jump to

urlsfile = open(filename, "rb", 0)

linesCounter = 1

for line in urlsfile:
    if linesCounter > startFromLine:
        DoSomethingWithThisLine(line)

    linesCounter += 1

(~15MB)알 수 없지만 길이가 다른 줄이 있는 대용량 텍스트 파일 을 처리하고 있고 미리 알고있는 특정 줄로 이동해야하는 경우? 적어도 파일의 전반부를 무시할 수 있다는 것을 알았을 때 하나씩 처리함으로써 기분이 좋지 않습니다. 더 우아한 솔루션을 찾고 있다면.



답변

라인 캐시 :

linecache모듈은 하나의 파일에서 여러 줄을 읽는 일반적인 경우 인 캐시를 사용하여 내부적으로 최적화를 시도하면서 Python 소스 파일에서 모든 줄을 가져올 수 있습니다. 이는 traceback모듈이 형식화 된 트레이스 백에 포함 할 소스 행을 검색 하는 데 사용됩니다 .


답변

줄 바꿈이 어디에 있는지 모르기 때문에 적어도 한 번 파일을 읽지 않고는 앞으로 이동할 수 없습니다. 다음과 같이 할 수 있습니다.

# Read in the file once and build a list of line offsets
line_offset = []
offset = 0
for line in file:
    line_offset.append(offset)
    offset += len(line)
file.seek(0)

# Now, to skip to line n (with the first line being line 0), just do
file.seek(line_offset[n])


답변

줄의 길이가 다른 경우에는 옵션이 그렇게 많지 않습니다. 슬프게도 다음 줄로 진행할 때를 알기 위해 줄 끝 문자를 처리해야합니다.

그러나 마지막 매개 변수를 “open”으로 변경하여 0이 아닌 것으로 변경함으로써 속도를 크게 높이고 메모리 사용량을 줄일 수 있습니다.

0은 파일 읽기 작업이 버퍼링되지 않음을 의미하며 이는 매우 느리고 디스크 집약적입니다. 1은 파일이 라인 버퍼링되어 개선되었음을 의미합니다. 1 이상 (예 : 8k .. 즉 : 8096 이상)은 파일 청크를 메모리로 읽습니다. 여전히를 통해 액세스 for line in open(etc):하지만 파이썬은 한 번에 조금만 이동하여 처리 된 각 버퍼링 된 청크를 버립니다.


답변

나는 아마도 풍부한 램에 의해 망쳐 졌을 것입니다. 그러나 15M은 크지 않습니다. 로 메모리로 읽는 readlines() 것은 일반적으로이 크기의 파일로 수행하는 작업입니다. 그 후 라인에 액세스하는 것은 사소합니다.


답변

아무도 islice를 언급하지 않았다는 것이 놀랍습니다.

line = next(itertools.islice(Fhandle,index_of_interest,index_of_interest+1),None) # just the one line

또는 나머지 파일 전체를 원하는 경우

rest_of_file = itertools.islice(Fhandle,index_of_interest)
for line in rest_of_file:
    print line

또는 파일에서 다른 모든 줄을 원할 경우

rest_of_file = itertools.islice(Fhandle,index_of_interest,None,2)
for odd_line in rest_of_file:
    print odd_line


답변

모든 줄을 읽지 않고 길이를 결정할 수있는 방법이 없기 때문에 출발 선 앞에서 모든 줄을 반복 할 수밖에 없습니다. 당신이 할 수있는 일은 멋지게 보이게하는 것입니다. 파일이 정말 큰 경우 생성기 기반 접근 방식을 사용할 수 있습니다.

from itertools import dropwhile

def iterate_from_line(f, start_from_line):
    return (l for i, l in dropwhile(lambda x: x[0] < start_from_line, enumerate(f)))

for line in iterate_from_line(open(filename, "r", 0), 141978):
    DoSomethingWithThisLine(line)

참고 :이 접근 방식에서는 인덱스가 0입니다.


답변

메모리에있는 전체 파일을 읽지 않으려면 .. 일반 텍스트 이외의 다른 형식이 필요할 수 있습니다.

물론 그것은 당신이 무엇을하려고하는지, 얼마나 자주 파일을 건너 뛸 것인지에 달려 있습니다.

예를 들어 같은 파일에서 여러 줄로 건너 뛰고 작업하는 동안 파일이 변경되지 않는다는 것을 알고 있다면 다음과 같이 할 수 있습니다.
먼저 전체 파일을 통과하고 ” 몇 개의 키-라인 번호 (예 : 1000 줄)의 탐색 위치 “를 입력 한
다음 12005 줄을 원할 경우 12000 (기록한) 위치로 이동 한 다음 5 줄을 읽으면 알 수 있습니다. 12005 줄에 있습니다.