대용량 텍스트 파일을 메모리에 로드하지 않고 한 줄씩 읽는 방법은 무엇입니까?
대용량 파일(5GB 이상)을 메모리에 로드하지 않고 한 줄씩 읽고 싶다.사용할 수 없습니다readlines()메모리에 매우 큰 목록이 생성되기 때문입니다.
를 사용하다for한 줄씩 읽을 수 있도록 파일 객체를 루프합니다.사용하다with open(...)다음 내용을 읽은 후 컨텍스트 매니저가 파일을 닫도록 합니다.
with open("log.txt") as infile:
for line in infile:
print(line)
파일 개체를 반복기로만 사용하면 됩니다.
for line in open("log.txt"):
do_something_with(line)
최신 Python 버전에서 컨텍스트 매니저를 사용하는 것이 더 좋습니다.
with open("log.txt") as fileobject:
for line in fileobject:
do_something_with(line)
그러면 파일도 자동으로 닫힙니다.
구식 접근법:
fh = open(file_name, 'rt')
line = fh.readline()
while line:
# do stuff with line
line = fh.readline()
fh.close()
다음을 시도해 보십시오.
with open('filename','r',buffering=100000) as f:
for line in f:
print line
대신 반복기를 사용하는 것이 좋습니다.
관련: - 여러 입력 스트림의 행에 걸쳐 반복합니다.
문서에서:
import fileinput
for line in fileinput.input("filename", encoding="utf-8"):
process(line)
이렇게 하면 파일 전체가 한 번에 메모리에 복사되지 않습니다.
파일에 줄바꿈이 없는 경우 다음과 같이 하십시오.
with open('large_text.txt') as f:
while True:
c = f.read(1024)
if not c:
break
print(c,end='')
@john-la-rooy의 답변이 그렇게 쉽게 보일 수 있다는 것을 믿을 수 없었다.그래서 제가 만든 게cp한 줄 한 줄 읽고 쓰는 명령을 사용합니다.CRAZY FAST 입니다.
#!/usr/bin/env python3.6
import sys
with open(sys.argv[2], 'w') as outfile:
with open(sys.argv[1]) as infile:
for line in infile:
outfile.write(line)
그 화재 프로젝트는 지난 6년 동안 많은 진전을 이뤘다.팬더 기능의 유용한 서브셋을 포함하는 간단한 API를 가지고 있습니다.
dask.dataframe은 내부적으로 청킹을 처리하고 병렬 가능한 많은 작업을 지원하며 메모리 내 작업을 위해 슬라이스를 팬더로 쉽게 내보낼 수 있습니다.
import dask.dataframe as dd
df = dd.read_csv('filename.csv')
df.head(10) # return first 10 rows
df.tail(10) # return last 10 rows
# iterate rows
for idx, row in df.iterrows():
...
# group by my_field and return mean
df.groupby(df.my_field).value.mean().compute()
# slice by column
df[df.my_field=='XYZ'].compute()
메모리 문제를 일으키지 않고 모든 크기의 텍스트 파일을 로드하기 위한 코드를 제공합니다.기가바이트 크기의 파일 지원
https://gist.github.com/iyvinjose/e6c1cb2821abd5f01fd1b9065cbc759d
data_loading_sys.py 파일을 다운로드하여 코드로 Import합니다.
사용.
import data_loading_utils.py.py
file_name = 'file_name.ext'
CHUNK_SIZE = 1000000
def process_lines(data, eof, file_name):
# check if end of file reached
if not eof:
# process data, data is one single line of the file
else:
# end of file reached
data_loading_utils.read_lines_from_file_as_data_chunks(file_name, chunk_size=CHUNK_SIZE, callback=self.process_lines)
process_lines 메서드는 콜백 함수입니다.모든 행에 대해 호출되며 파라미터 데이터는 한 번에 파일의 한 행을 나타냅니다.
시스템 하드웨어 구성에 따라 CHUNK_SIZE 변수를 구성할 수 있습니다.
이건 어때?파일을 읽으면 운영 체제가 다음 행을 캐시하기 때문에 파일을 청크로 나눈 다음 한 줄씩 읽습니다.파일을 한 줄씩 읽는 경우 캐시된 정보를 효율적으로 사용할 수 없습니다.
대신 파일을 청크로 나누고 전체 청크를 메모리에 로드한 후 처리를 수행합니다.
def chunks(file,size=1024):
while 1:
startat=fh.tell()
print startat #file's object current position from the start
fh.seek(size,1) #offset from current postion -->1
data=fh.readline()
yield startat,fh.tell()-startat #doesnt store whole list in memory
if not data:
break
if os.path.isfile(fname):
try:
fh=open(fname,'rb')
except IOError as e: #file --> permission denied
print "I/O error({0}): {1}".format(e.errno, e.strerror)
except Exception as e1: #handle other exceptions such as attribute errors
print "Unexpected error: {0}".format(e1)
for ele in chunks(fh):
fh.seek(ele[0])#startat
data=fh.read(ele[1])#endat
print data
감사해요!최근에 python 3으로 변환했는데, 큰 파일을 읽기 위해 readline(0)을 사용하는 것에 당황하고 있습니다.이것으로 문제가 해결되었다.하지만 각 줄을 맞추려면 몇 가지 단계를 더 밟아야 했습니다.각 행의 앞에는 "b"가 붙었는데, 아마 바이너리 형식이었던 것 같습니다."decode(utf-8)"를 사용하여 ASCII가 변경되었습니다.
그리고 각 행의 중간에 있는 "=\n"을 제거해야 했습니다.
그리고 새 선에서 선을 뺐어요.
b_data=(fh.read(ele[1]))#endat This is one chunk of ascii data in binary format
a_data=((binascii.b2a_qp(b_data)).decode('utf-8')) #Data chunk in 'split' ascii format
data_chunk = (a_data.replace('=\n','').strip()) #Splitting characters removed
data_list = data_chunk.split('\n') #List containing lines in chunk
#print(data_list,'\n')
#time.sleep(1)
for j in range(len(data_list)): #iterate through data_list to get each item
i += 1
line_of_data = data_list[j]
print(line_of_data)
다음은 Arohi의 코드에서 "인쇄 데이터" 바로 위에 시작하는 코드입니다.
이에 대해 제가 찾은 최고의 해결 방법은 330MB 파일로 시도했습니다.
lineno = 500
line_length = 8
with open('catfour.txt', 'r') as file:
file.seek(lineno * (line_length + 2))
print(file.readline(), end='')
여기서 line_length는 한 줄의 문자 수입니다.예를 들어 "abcd"의 행 길이는 4입니다.
'\n' 문자를 건너뛰고 다음 문자로 이동하기 위해 행 길이를 2개 추가했습니다.
이것은 꽤 오래전에 회답이 끝난 것을 알고 있습니다만, 여기에서는 메모리의 오버헤드를 없애지 않고 병행할 수 있는 방법이 있습니다(각 회선을 풀로 보내려고 했을 경우).readJ를 스왑합니다.SON_line2는 합리적인 기능으로 기능합니다.여기서 요점을 설명하겠습니다.
속도 향상은 파일 크기 및 각 행에서 수행하는 작업에 따라 달라집니다. 그러나 JSON 리더를 사용하여 읽는 최악의 경우 아래 설정에서 ST와 유사한 성능을 볼 수 있습니다.
누군가에게 도움이 되었으면 합니다.
def readJSON_line2(linesIn):
#Function for reading a chunk of json lines
'''
Note, this function is nonsensical. A user would never use the approach suggested
for reading in a JSON file,
its role is to evaluate the MT approach for full line by line processing to both
increase speed and reduce memory overhead
'''
import json
linesRtn = []
for lineIn in linesIn:
if lineIn.strip() != 0:
lineRtn = json.loads(lineIn)
else:
lineRtn = ""
linesRtn.append(lineRtn)
return linesRtn
# -------------------------------------------------------------------
if __name__ == "__main__":
import multiprocessing as mp
path1 = "C:\\user\\Documents\\"
file1 = "someBigJson.json"
nBuffer = 20*nCPUs # How many chunks are queued up (so cpus aren't waiting on processes spawning)
nChunk = 1000 # How many lines are in each chunk
#Both of the above will require balancing speed against memory overhead
iJob = 0 #Tracker for SMP jobs submitted into pool
iiJob = 0 #Tracker for SMP jobs extracted back out of pool
jobs = [] #SMP job holder
MTres3 = [] #Final result holder
chunk = []
iBuffer = 0 # Buffer line count
with open(path1+file1) as f:
for line in f:
#Send to the chunk
if len(chunk) < nChunk:
chunk.append(line)
else:
#Chunk full
#Don't forget to add the current line to chunk
chunk.append(line)
#Then add the chunk to the buffer (submit to SMP pool)
jobs.append(pool.apply_async(readJSON_line2, args=(chunk,)))
iJob +=1
iBuffer +=1
#Clear the chunk for the next batch of entries
chunk = []
#Buffer is full, any more chunks submitted would cause undue memory overhead
#(Partially) empty the buffer
if iBuffer >= nBuffer:
temp1 = jobs[iiJob].get()
for rtnLine1 in temp1:
MTres3.append(rtnLine1)
iBuffer -=1
iiJob+=1
#Submit the last chunk if it exists (as it would not have been submitted to SMP buffer)
if chunk:
jobs.append(pool.apply_async(readJSON_line2, args=(chunk,)))
iJob +=1
iBuffer +=1
#And gather up the last of the buffer, including the final chunk
while iiJob < iJob:
temp1 = jobs[iiJob].get()
for rtnLine1 in temp1:
MTres3.append(rtnLine1)
iiJob+=1
#Cleanup
del chunk, jobs, temp1
pool.close()
이 기능은 병렬로 작업하고 데이터 청크만 읽으면서 새 행으로 깨끗한 상태를 유지하려는 경우에 유용합니다.
def readInChunks(fileObj, chunkSize=1024):
while True:
data = fileObj.read(chunkSize)
if not data:
break
while data[-1:] != '\n':
data+=fileObj.read(1)
yield data
언급URL : https://stackoverflow.com/questions/6475328/how-can-i-read-large-text-files-line-by-line-without-loading-them-into-memory
'programing' 카테고리의 다른 글
| PHP - 두 배열이 동일한지 확인합니다. (0) | 2022.10.23 |
|---|---|
| 봄 3.0에 포함할 메이븐 종속성은 무엇입니까? (0) | 2022.10.22 |
| MySQL에서 행 수 증가 속도 향상 (0) | 2022.10.22 |
| 지정된 디렉토리의 파일을 반복하려면 어떻게 해야 합니까? (0) | 2022.10.22 |
| 타임스탬프를 읽을 수 있는 날짜/시간 PHP로 변환 (0) | 2022.10.22 |