거대한 텍스트 파일에서 특정 줄로 이동하는 방법은 무엇입니까?
아래 코드에 대한 대안이 있습니까?
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()
것은 일반적으로이 크기의 파일로 수행하는 작업입니다. 그 후 라인에 액세스하는 것은 사소합니다.
모든 줄을 읽지 않고 길이를 결정할 수있는 방법이 없기 때문에 출발 선 전에 모든 줄을 반복 할 수밖에 없습니다. 당신이 할 수있는 일은 멋지게 보이게하는 것입니다. 파일이 정말 큰 경우 생성기 기반 접근 방식을 사용할 수 있습니다.
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입니다.
아무도 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
파일의 위치 (줄 번호가 아니라)를 미리 알고 있다면 file.seek () 를 사용 하여 해당 위치로 이동할 수 있습니다 .
Edit: you can use the linecache.getline(filename, lineno) function, which will return the contents of the line lineno, but only after reading the entire file into memory. Good if you're randomly accessing lines from within the file (as python itself might want to do to print a traceback) but not good for a 15MB file.
If you don't want to read the entire file in memory .. you may need to come up with some format other than plain text.
of course it all depends on what you're trying to do, and how often you will jump across the file.
For instance, if you're gonna be jumping to lines many times in the same file, and you know that the file does not change while working with it, you can do this:
First, pass through the whole file, and record the "seek-location" of some key-line-numbers (such as, ever 1000 lines),
Then if you want line 12005, jump to the position of 12000 (which you've recorded) then read 5 lines and you'll know you're in line 12005 and so on
What generates the file you want to process? If it is something under your control, you could generate an index (which line is at which position.) at the time the file is appended to. The index file can be of fixed line size (space padded or 0 padded numbers) and will definitely be smaller. And thus can be read and processed qucikly.
- Which line do you want?.
- Calculate byte offset of corresponding line number in index file(possible because line size of index file is constant).
- Use seek or whatever to directly jump to get the line from index file.
- Parse to get byte offset for corresponding line of actual file.
I have had the same problem (need to retrieve from huge file specific line).
Surely, I can every time run through all records in file and stop it when counter will be equal to target line, but it does not work effectively in a case when you want to obtain plural number of specific rows. That caused main issue to be resolved - how handle directly to necessary place of file.
I found out next decision: Firstly I completed dictionary with start position of each line (key is line number, and value – cumulated length of previous lines).
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
ultimately, aim function:
def give_line(line_number):
t.seek(dict_pos.get(line_number))
line = t.readline()
return line
t.seek(line_number) – command that execute pruning of file up to line inception. So, if you next commit readline – you obtain your target line.
Using such approach I have saved significant part of time.
You may use mmap to find the offset of the lines. MMap seems to be the fastest way to process a file
example:
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
then use f.seek(offsets) to move to the line you need
Do the lines themselves contain any index information? If the content of each line was something like "<line index>:Data
", then the seek()
approach could be used to do a binary search through the file, even if the amount of Data
is variable. You'd seek to the midpoint of the file, read a line, check whether its index is higher or lower than the one you want, etc.
Otherwise, the best you can do is just readlines()
. If you don't want to read all 15MB, you can use the sizehint
argument to at least replace a lot of readline()
s with a smaller number of calls to readlines()
.
Here's an example using 'readlines(sizehint)' to read a chunk of lines at a time. DNS pointed out that solution. I wrote this example because the other examples here are single-line oriented.
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)
If you're dealing with a text file & based on linux system, you could use the linux commands.
For me, this worked well!
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)
Can use this function to return line 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
'program tip' 카테고리의 다른 글
Google Play에서 Android 앱의 패키지 이름을 변경할 수 있나요? (0) | 2020.08.19 |
---|---|
Web Api 용 Xml 문서에 기본 프로젝트 이외의 문서를 포함하려면 어떻게해야합니까? (0) | 2020.08.19 |
Firefox에서 링크의 키보드 포커스를 허용하는 방법은 무엇입니까? (0) | 2020.08.19 |
'창'에서 'btoa'실행 실패 : 인코딩 할 문자열에 Latin1 범위를 벗어난 문자가 포함되어 있습니다. (0) | 2020.08.19 |
matplotlib에서 여러 서브 플롯을 얻으려면 어떻게해야합니까? (0) | 2020.08.19 |