programing

대용량 텍스트 파일에서 특정 줄로 이동하는 방법은 무엇입니까?

elecom 2023. 8. 16. 21:57
반응형

대용량 텍스트 파일에서 특정 줄로 이동하는 방법은 무엇입니까?

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

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)알 수 없지만 길이가 다른 줄로 이동하고, 미리 알고 있는 특정 줄로 점프해야 합니까?파일의 전반부라도 무시할 수 있다는 것을 알고 하나씩 처리하면서 기분이 안 좋습니다.더 우아한 해결책을 찾고 있습니다.

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

# 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])

라인 캐시:

이 모듈을 사용하면 단일 파일에서 많은 줄을 읽는 일반적인 경우인 캐시를 사용하여 내부적으로 최적화를 시도하는 동안 파이썬 소스 파일에서 모든 줄을 가져올 수 있습니다.모듈이 포맷된 트레이스백에 포함할 소스 라인을 검색하는 데 사용됩니다.

선의 길이가 다르면 그렇게 많은 옵션이 없습니다.안타깝게도 다음 줄로 진행한 경우 줄 끝 문자를 처리해야 합니다.

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

0은 파일 읽기 작업이 버퍼링되지 않았음을 의미하며, 이는 매우 느리고 디스크 집약적임을 의미합니다. 1은 파일이 라인 버퍼링됨을 의미하며, 이는 개선 사항이 될 것입니다.1보다 이상. 1 이예상은 (8KB 는 8192 상이)일파다청니.당신은 여전히 그것을 통해 접속합니다.for line in open(etc):그러나 python은 처리된 각 버퍼 청크를 폐기하면서 한 번에 몇 개씩만 이동합니다.

아무도 이에 대해 언급하지 않은 것이 놀랍습니다.

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

저는 아마 풍부한 램 때문에 버릇이 없을 것입니다만, 15M은 크지 않습니다.이 크기의 파일을 메모리에 읽어 들이는 것이 제가 주로 하는 일입니다.그 후에 회선에 접속하는 것은 사소한 일입니다.

동일한 문제가 발생했습니다(대형 파일 특정 줄에서 검색해야 함).

물론 카운터가 대상 라인과 같을 때 파일의 모든 레코드를 실행하고 중지할 수 있지만 여러 개의 특정 행을 가져오려는 경우에는 효과적으로 작동하지 않습니다.이로 인해 주요 문제가 해결되었습니다. 즉, 필요한 파일 위치로 직접 이동하는 방법입니다.

저는 다음 결정을 내렸습니다.먼저 각 줄의 시작 위치(키는 줄 번호, 값 - 이전 줄의 누적 길이)로 사전을 완성했습니다.

t = open(file,’r’)
dict_pos = {}

kolvo = 0
length = 0
for each in t:
    dict_pos[kolvo] = length
    length = length+len(each)
    kolvo = kolvo+1

궁극적으로 목표 기능:

def give_line(line_number):
    t.seek(dict_pos.get(line_number))
    line = t.readline()
    return line

t.seek(line_number) – 파일을 라인 시작까지 가지치기하는 명령입니다.다음 번에 읽기 줄을 커밋하면 목표 줄을 얻을 수 있습니다.

이러한 접근 방식을 사용하여 상당한 시간을 절약했습니다.

읽지 않고는 모든 줄의 길이를 결정할 수 없기 때문에 시작 줄 전에 모든 줄을 반복할 수밖에 없습니다.당신이 할 수 있는 것은 그것을 멋지게 만드는 것뿐입니다.파일이 정말 큰 경우 생성기 기반 접근 방식을 사용할 수 있습니다.

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줄 위치합니다.
으로 점프해서 알 수.

mmap을 사용하여 선의 간격띄우기를 찾을 수 있습니다.파일을 처리하는 가장 빠른 방법은 MMAP인 것 같습니다.

예:

with open('input_file', "r+b") as f:
    mapped = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
    i = 1
    for line in iter(mapped.readline, ""):
        if i == Line_I_want_to_jump:
            offsets = mapped.tell()
        i+=1

그런 다음 f.seeek(아래)를 사용하여 필요한 라인으로 이동합니다.

특별히 만족할 만한 답변이 없으므로, 여기 도움이 될 작은 토막글이 있습니다.

class LineSeekableFile:
    def __init__(self, seekable):
        self.fin = seekable
        self.line_map = list() # Map from line index -> file position.
        self.line_map.append(0)
        while seekable.readline():
            self.line_map.append(seekable.tell())

    def __getitem__(self, index):
        # NOTE: This assumes that you're not reading the file sequentially.  
        # For that, just use 'for line in file'.
        self.fin.seek(self.line_map[index])
        return self.fin.readline()

사용 예:

In: !cat /tmp/test.txt

Out:
Line zero.
Line one!

Line three.
End of file, line four.

In:
with open("/tmp/test.txt", 'rt') as fin:
    seeker = LineSeekableFile(fin)    
    print(seeker[1])
Out:
Line one!

여기에는 많은 파일 검색이 포함되지만 전체 파일을 메모리에 저장할 수 없는 경우에 유용합니다.한 번의 초기 읽기를 수행하여 줄 위치를 가져온 다음(전체 파일을 읽지만 모두 메모리에 저장하지는 않음) 각 액세스에서 해당 위치를 검색합니다.

사용자의 재량에 따라 MIT 또는 Apache 라이센스로 위의 스니펫을 제공합니다.

파일의 위치(라인 번호가 아닌)를 미리 알고 있는 경우 file.seek()사용하여 해당 위치로 이동할 수 있습니다.

편집: linecache.getline(파일 이름, lineeno) 함수를 사용할 수 있습니다. 이 함수는 전체 파일을 메모리로 읽은 후에만 라인 번호의 내용을 반환합니다.파일 내에서 임의로 라인에 액세스하는 경우에는 좋지만(파이썬 자체가 트레이스백을 인쇄하기 위해 수행할 수도 있음) 15MB 파일에는 적합하지 않습니다.

처리할 파일은 무엇으로 생성됩니까?제어 대상인 경우 파일이 추가될 때 인덱스(어느 행이 어느 위치에 있는지)를 생성할 수 있습니다.인덱스 파일은 고정 줄 크기(스페이스 패딩 또는 0 패딩 번호)일 수 있으며 분명히 더 작을 것입니다.따라서 빠르게 읽고 처리할 수 있습니다.

  • 당신은 어느 노선을 원하십니까?
  • 인덱스 파일에서 해당 라인 번호의 바이트 오프셋을 계산합니다(인덱스 파일의 라인 크기가 일정하기 때문에 가능).
  • 색인 파일에서 줄을 가져오려면 검색 또는 기타 항목을 사용합니다.
  • 실제 파일의 해당 줄에 대한 바이트 오프셋을 가져오도록 구문 분석합니다.

라인 자체에 인덱스 정보가 포함되어 있습니까?각 행의 내용이 "와 같다면,<line index>:Data그 다음에seek()접근 방식은 파일을 통해 이진 검색을 수행하는 데 사용될 수 있습니다, 비록 양이Data변수입니다.파일의 중간 지점을 찾고, 줄을 읽으며, 인덱스가 원하는 인덱스보다 높거나 낮는지 확인하는 등의 작업을 수행할 수 있습니다.

그렇지 않다면, 당신이 할 수 있는 최선은 단지readlines()15MB를 모두 읽지 않으려면 다음을 사용할 수 있습니다.sizehint적어도 많은 것을 대체하려는 주장readline()호출 수가 적은 sreadlines().

텍스트 파일을 다루고 있고 리눅스 시스템을 기반으로 한다면 리눅스 명령을 사용할 수 있습니다.
저는 이게 잘 먹혔어요!

import commands

def read_line(path, line=1):
    return commands.getoutput('head -%s %s | tail -1' % (line, path))

line_to_jump = 141978
read_line("path_to_large_text_file", line_to_jump)

다음은 한 번에 한 줄씩 읽는 데 사용하는 예제입니다.DNS는 그 해결책을 지적했습니다.이 예제를 작성한 이유는 여기에 있는 다른 예제들이 한 줄로 되어 있기 때문입니다.

def getlineno(filename, lineno):
    if lineno < 1:
        raise TypeError("First line is line 1")
    f = open(filename)
    lines_read = 0
    while 1:
        lines = f.readlines(100000)
        if not lines:
            return None
        if lines_read + len(lines) >= lineno:
            return lines[lineno-lines_read-1]
        lines_read += len(lines)

print getlineno("nci_09425001_09450000.smi", 12000)

@syscall mmap을 사용하는 것으로 추정되는 훌륭하게 제안된 mmap.여기 또 다른 버전이 있습니다.

import mmap

LINE = 2  # your desired line

with open('data.txt','rb') as i_file, mmap.mmap(i_file.fileno(), length=0, prot=mmap.PROT_READ) as data:
  for i,line in enumerate(iter(data.readline, '')):
    if i!=LINE: continue
    pos = data.tell() - len(line)
    break

  # optionally copy data to `chunk`
  i_file.seek(pos)
  chunk = i_file.read(len(line))

print(f'line {i}')
print(f'byte {pos}')
print(f'data {line}')
print(f'data {chunk}')

이 함수를 사용하여 라인 n을 반환할 수 있습니다.

def skipton(infile, n):
    with open(infile,'r') as fi:
        for i in range(n-1):
            fi.next()
        return fi.next()

언급URL : https://stackoverflow.com/questions/620367/how-to-jump-to-a-particular-line-in-a-huge-text-file

반응형