source

큰 파일을 한 줄씩 읽는 방법

gigabyte 2023. 1. 22. 22:29
반응형

큰 파일을 한 줄씩 읽는 방법

파일 전체의 각 행에 걸쳐 반복하고 싶다.이를 위한 한 가지 방법은 전체 파일을 읽고 목록에 저장한 다음 관심 행을 확인하는 것입니다.이 방법은 메모리를 많이 사용하기 때문에 다른 방법을 찾고 있습니다.

지금까지의 코드:

for each_line in fileinput.input(input_file):
    do_something(each_line)

    for each_line_again in fileinput.input(input_file):
        do_something(each_line_again)

나타납니다.device active.

좋은 의견이라도 있나?

목적은 쌍별 문자열 유사도를 계산하는 것입니다. 즉, 파일의 각 행에 대해 다른 행과의 Levenshtein 거리를 계산하고 싶습니다.

파일을 완전히 읽는 올바른 방법은 다음과 같습니다.

with open(...) as f:
    for line in f:
        # Do something with 'line'

with문은 내부 블록에서 예외가 발생하는 경우를 포함하여 파일 열기 및 닫기를 처리합니다.for line in f는 파일 오브젝트 「」를 합니다.f버퍼링된 I/O 및 메모리 관리를 자동으로 사용하기 때문에 대용량 파일에 대해 걱정할 필요가 없습니다.

그것을 할 수 있는 확실한 방법은 하나, 그리고 가급적 하나뿐이어야 합니다.

메모리 효율이 뛰어난 2가지 방법(첫 번째가 최선) -

  1. 입니다.with.5 - python 2.5 이상부터 지원
  2. 입니다.yield

1. 사용방법with

with는 - 1) 후 .장점 - 1) 파일오브젝트는 종료 후 자동으로 닫힙니다.with 내부에서의 with 3) memory(메모리) 3. memory(메모리forf비용이 많이 드는 관리를 합니다.내부적으로 버퍼링된 IO(비용이 많이 드는 IO 작업에 최적화됨) 및 메모리 관리를 수행합니다.

with open("x.txt") as f:
    for line in f:
        do something with data

2. 사용법yield

경우에 따라서는 각 반복에서 읽을 양을 보다 세밀하게 제어해야 할 수도 있습니다.이 경우 반복 사용 및 산출.이 방법에서는 마지막에 파일을 명시적으로 닫아야 합니다.

def readInChunks(fileObj, chunkSize=2048):
    """
    Lazy function to read a file piece by piece.
    Default chunk size: 2kB.

    """
    while True:
        data = fileObj.read(chunkSize)
        if not data:
            break
        yield data

f = open('bigFile')
for chunk in readInChunks(f):
    do_something(chunk)
f.close()

함정 완전성을 위해 - 아래 방법은 대용량 파일을 읽기에는 적합하지 않거나 우아하지 않습니다.다만, 대략적인 이해를 위해서 읽어 주세요.

Python에서 파일에서 행을 읽는 가장 일반적인 방법은 다음을 수행하는 것입니다.

for line in open('myfile','r').readlines():
    do_something(line)

이 되면, 「 」, 「 」, 「 」, 「 」, 「 」, 「 」로 표시됩니다.readlines())read()function)은 파일 전체를 메모리에 로드하고 그 위에서 반복합니다.는 조금 더 접근법의 첫 두 을 하는 것이 좋습니다.fileinput를 들어 과 같습니다

import fileinput

for line in fileinput.input(['myfile']):
    do_something(line)

fileinput.input()은 줄을 읽지만, 난 하거나 심지어file비단뱀

레퍼런스

  1. Python (문 포함)

줄바꿈을 삭제하려면

with open(file_path, 'rU') as f:
    for line_terminated in f:
        line = line_terminated.rstrip('\n')
        ...

범용 줄바꿈 지원으로 모든 텍스트 파일 행은 다음과 같이 끝납니다.'\n' 「 」는 「 」입니다.'\r','\n' , 「」'\r\n'

편집 - 범용 줄바꿈 지원을 지정하려면:

  • 2 - Unix ® Python 2 -open(file_path, mode='rU')- 필수
  • ® Python 2 - Windows ® Python 2 -open(file_path, mode='rU') - 션션
  • Python 3 -open(file_path, newline=None) - 션션

newline은 "Python 3" 입니다.None . 。mode로 "이러다"로 설정되어 있습니다.'r'★★★★★★★★★★★★★★★★★★★★★★★.U되지 않습니다.의2에서는, Windows 의 Python 2 를 변환하는 .\r\n로로 합니다.\n.

문서:

네이티브 회선 종단자를 보존하려면 , 다음의 순서에 따릅니다.

with open(file_path, 'rb') as f:
    with line_native_terminated in f:
        ...

바이너리 에서는, 수에는 「이행」, 「이행」이 붙어 있습니다.in각 행에는 파일에 있는 모든 터미네이터가 포함됩니다.

@katrielalex답변, Python의 open() 문서 및 iPython 실험 덕분에.

python 파일을 읽을 수 있는 방법은 다음과 같습니다.

f = open(input_file)
for line in f:
    do_stuff(line)
f.close()

완전한 리스트는 할당되지 않습니다.그것은 선을 넘어 반복된다.

내가 어디서 왔는지에 대한 어떤 맥락이 앞에 있다.코드 스니펫은 끝에 있습니다.

가능하면 H2O와 같은 오픈 소스 툴을 사용하여 초고성능 병렬 CSV 파일 읽기를 수행하지만 이 툴은 기능 세트에 제한이 있습니다.적절한 지도 학습을 위해 H2O 클러스터에 공급하기 전에 데이터 사이언스 파이프라인을 만들기 위해 많은 코드를 작성하게 됩니다.

UCI repo의 8GB HIGGS 데이터셋이나 데이터 사이언스용 40GB CSV 파일도 멀티프로세싱 라이브러리의 풀 오브젝트나 맵 기능과 병행하여 매우 빠르게 읽고 있습니다.예를 들어, 가장 가까운 근접 검색을 사용한 클러스터링과 DBSCAN 및 마르코프 클러스터링 알고리즘은 심각한 메모리 및 벽 클럭 시간 문제를 우회하기 위해 몇 가지 병렬 프로그래밍 기술을 필요로 합니다.

저는 보통 먼저 gnu 툴을 사용하여 파일을 행 단위로 분할한 후 python 프로그램에서 그것들을 찾아 읽기 위해 그것들을 모두 글로벌 파일 마스크하는 것을 좋아합니다.저는 1000개 이상의 부분 파일을 자주 사용하고 있습니다.이러한 기술을 사용하면 처리 속도와 메모리 제한에 큰 도움이 됩니다.

panda dataframe.read_csv는 단일 스레드이기 때문에 병렬 실행을 위해 map()을 실행하여 판다를 매우 빠르게 만들 수 있습니다.htop을 사용하면 기존 시퀀셜 팬더 dataframe.read_csv의 경우 디스크가 아니라 하나의 코어로 100% CPU가 실제로 pd.read_csv의 병목 현상을 확인할 수 있습니다.

덧붙이자면, 고속 비디오 카드 버스에서는 SSD를 사용하고 있습니다만, SATA6 버스에서는 회전하는 HD를 사용하지 않고, CPU 코어도 16개 사용하고 있습니다.

또한 일부 애플리케이션에서는 하나의 빅 파일을 여러 개의 부품 파일로 미리 분할하는 것이 아니라 하나의 거대 파일 내에서 모든 CSV 파일을 병렬로 읽고 서로 다른 오프셋으로 각 워커를 파일로 시작하는 것이 효과적이라는 것을 알게 되었습니다.각 병렬 워커에서 python의 파일 seek()와 tell()을 사용하여 빅 파일 내의 서로 다른 바이트 오프셋 시작 바이트 및 끝 바이트 위치에서 동시에 빅 텍스트 파일을 스트립으로 읽습니다.바이트에 대해 regex findall을 실행하여 라인피드 수를 반환할 수 있습니다.이것은 부분적인 합계입니다.마지막으로 작업자가 종료한 후 지도 함수가 반환될 때 부분 합계를 합산하여 글로벌 합계를 구합니다.

다음은 병렬 바이트 오프셋 트릭을 사용한 벤치마크의 예입니다.

2개의 파일을 사용하고 있습니다.HIGGS.csv는 8GB입니다.UCI 머신 러닝 저장소에서 가져온 것입니다.all_bin .csv는 40.4GB이며 현재 프로젝트에서 가져온 것입니다.Linux와 함께 제공되는 GNU wc 프로그램과 제가 개발한 순수 python fastread.py 프로그램 두 가지를 사용하고 있습니다.

HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv

HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb  2 09:00 all_bin.csv

ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496

real    0m8.920s
user    1m30.056s
sys 2m38.744s

In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175

이는 약 4.5GB/s(45Gb/s)의 파일 슬래핑 속도입니다.그건 회전식 하드디스크가 아니야, 친구이것은 실제로 삼성 Pro 950 SSD입니다.

다음은 C 컴파일 프로그램인 gnu wc에 의해 행계수된 동일한 파일의 속도 벤치마크입니다.

멋진 점은 이 경우 내 순수 파이썬 프로그램이 기본적으로 gnu wc 컴파일된 C 프로그램의 속도와 일치한다는 것입니다.Python은 해석은 되지만 C는 컴파일 되어 있기 때문에 매우 흥미로운 속도입니다.여러분도 동의하실 거라고 생각합니다.물론 wc는 병렬 프로그램으로 변경해야 합니다. 그러면 내 파이톤 프로그램이 완전히 망가질 것입니다.그러나 현재로선 gnu wc는 순차적인 프로그램일 뿐이다.당신이 할 수 있는 일을 하면, 파이썬은 오늘날 병행할 수 있습니다.Cython 컴파일이 (잠시 후) 도움이 될 것 같습니다.메모리 매핑 파일도 아직 탐색되지 않았습니다.

HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv

real    0m8.807s
user    0m1.168s
sys 0m7.636s


HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.257s
user    0m12.088s
sys 0m20.512s

HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv

real    0m1.820s
user    0m0.364s
sys 0m1.456s

결론:C프로그램에 비해 순수 파이썬 프로그램으로는 속도가 좋습니다.그러나 적어도 라인카운팅 목적으로 C 프로그램 상에서 Pure Python 프로그램을 사용하는 것은 충분하지 않습니다.일반적으로 이 기술은 다른 파일 처리에 사용할 수 있기 때문에 이 파이썬 코드는 여전히 유효합니다.

질문:.정규식을 한 번만 컴파일하여 모든 작업자에게 전달하면 속도가 향상됩니까?답변: 이 응용 프로그램에서는 regex 프리 컴파일은 도움이 되지 않습니다.그 이유는 모든 작업자가 프로세스 직렬화와 생성에 따른 오버헤드가 지배적이기 때문이라고 생각합니다.

한가지 더요.병렬 CSV 파일 읽기에도 도움이 됩니까?디스크가 병목현상입니까, 아니면 CPU입니까?stackoverflow에 대한 소위 최상위 등급의 답변에는 파일을 읽기 위해 하나의 스레드만 있으면 된다는 일반적인 dev wise가 포함되어 있으며, 이는 최선의 방법이라고 그들은 말합니다.그래도 확실한가요?

이하에 대해 설명하겠습니다.

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.256s
user    0m10.696s
sys 0m19.952s

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000

real    0m17.380s
user    0m11.124s
sys 0m6.272s

오, 그래, 그래.병렬 파일 읽기가 꽤 잘 작동합니다.그래, 그렇지!

추신. 알고 싶은 사람이 있을 경우 단일 작업자 프로세스를 사용할 때 balance factor가 2이면 어떻게 됩니까?음, 끔찍해.

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000

real    1m37.077s
user    0m12.432s
sys 1m24.700s

고속 판독의 주요 부분.py python 프로그램:

fileBytes = stat(fileName).st_size  # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)


def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'):  # counts number of searchChar appearing in the byte range
    with open(fileName, 'r') as f:
        f.seek(startByte-1)  # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
        bytes = f.read(endByte - startByte + 1)
        cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
    return cnt

PartitionDataToWorkers의 def는 일반적인 순차 코드입니다.병렬 프로그래밍이 어떤 건지 다른 사람이 연습하고 싶어할까 봐 빼놨어요.어려운 부분은 무료로 배포했습니다. 테스트되고 작동하는 병렬 코드입니다. 학습 효과를 위해.

덕택:Arno와 Cliff의 오픈소스 H2O 프로젝트와 H2O 스태프의 훌륭한 소프트웨어와 교육 비디오는 위와 같은 순수한 파이썬 고성능 병렬 바이트 오프셋 리더에 영감을 주었습니다.H2O는 Java를 사용하여 병렬 파일 읽기를 수행하며, python 및 R 프로그램에서 호출할 수 있으며, 대용량 CSV 파일을 읽는 데 있어 지구상의 그 어떤 것보다도 빠릅니다.

Katrielalex는 하나의 파일을 열고 읽을 수 있는 방법을 제공했습니다.

그러나 알고리즘이 파일의 각 행에 대해 파일 전체를 읽는 방식입니다.즉, 파일 읽기 및 Levenshtein 거리 계산의 총량은 N이 파일 내의 행의 양일 경우 N*N이 됩니다.당신은 파일 크기를 걱정하고 메모리에 보관하고 싶지 않기 때문에, 나는 2차 실행 시간이 걱정됩니다.알고리즘은 O(n^2) 클래스의 알고리즘으로 전문화를 통해 개선할 수 있습니다.

메모리 대 런타임의 트레이드오프는 이미 알고 계실 것입니다만, 복수의 Levenshtein 거리를 병렬로 계산하는 효율적인 방법이 있는지 조사해 보시기 바랍니다.그렇다면 여기에서 귀사의 솔루션을 공유하는 것이 좋습니다.

파일에는 몇 줄의 행이 있으며, 어떤 종류의 머신(메모리와 CPU의 전력)에서 알고리즘이 실행되어야 하며, 허용되는 실행 시간은 얼마나 됩니까?

코드는 다음과 같습니다.

with f_outer as open(input_file, 'r'):
    for line_outer in f_outer:
        with f_inner as open(input_file, 'r'):
            for line_inner in f_inner:
                compute_distance(line_outer, line_inner)

그러나 문제는 거리(매트릭스)를 어떻게 저장하느냐이며, 처리를 위해 외부 라인(outer_line)을 준비하거나 중간 결과를 캐싱하여 재사용할 수 있는 이점을 얻을 수 있는가 하는 것입니다.

fileinput.input()의 python 문서에서 다음 절차를 수행합니다.

이 작업은 에 됩니다.sys.argv[1:]로는 " " " 입니다sys.stdin가 있는

또한 함수의 정의는 다음과 같습니다.

fileinput.FileInput([files[, inplace[, backup[, mode[, openhook]]]]])

행간을 읽으면, 이것은 나에게 말한다.files리스트가 될 수 있기 때문에, 다음과 같은 것을 얻을 수 있습니다.

for each_line in fileinput.input([input_file, input_file]):
  do_something(each_line)

자세한 내용은 여기를 참조해 주세요.

#Using a text file for the example
with open("yourFile.txt","r") as f:
    text = f.readlines()
for line in text:
    print line
  • 읽기 위해 파일 열기(r)
  • 파일 전체를 읽고 각 행을 목록(텍스트)에 저장합니다.
  • 각 행을 인쇄하는 리스트를 반복해 주세요.

예를 들어 특정 행의 길이가 10보다 큰지 확인하려면 이미 사용 가능한 행으로 작업합니다.

for line in text:
    if len(line) > 10:
        print line

마지막 위치에서 큰 파일을 자주 읽어야 합니까?

Apache access.log 파일을 하루에 여러 번 잘라내는 스크립트를 작성했습니다.그래서 마지막 실행 시 구문 분석된 마지막 줄에 위치 커서를 설정해야 했습니다.이를 위해 저는file.seek() ★★★★★★★★★★★★★★★★★」file.seek()파일에 커서를 저장할 수 있는 메서드입니다.

내 코드:

ENCODING = "utf8"
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))

# This file is used to store the last cursor position
cursor_position = os.path.join(CURRENT_FILE_DIR, "access_cursor_position.log")

# Log file with new lines
log_file_to_cut = os.path.join(CURRENT_FILE_DIR, "access.log")
cut_file = os.path.join(CURRENT_FILE_DIR, "cut_access", "cut.log")

# Set in from_line 
from_position = 0
try:
    with open(cursor_position, "r", encoding=ENCODING) as f:
        from_position = int(f.read())
except Exception as e:
    pass

# We read log_file_to_cut to put new lines in cut_file
with open(log_file_to_cut, "r", encoding=ENCODING) as f:
    with open(cut_file, "w", encoding=ENCODING) as fw:
        # We set cursor to the last position used (during last run of script)
        f.seek(from_position)
        for line in f:
            fw.write("%s" % (line))

    # We save the last position of cursor for next usage
    with open(cursor_position, "w", encoding=ENCODING) as fw:
        fw.write(str(f.tell()))

디폴트 파일 로딩은 매우 느리므로 사용하지 않는 것이 좋습니다.numpy 함수와 IOpro 함수(numpy.loadtxt() 등)를 조사해야 합니다.

http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html

https://store.continuum.io/cshop/iopro/

그런 다음 쌍별 작업을 청크로 나눌 수 있습니다.

import numpy as np
import math

lines_total = n    
similarity = np.zeros(n,n)
lines_per_chunk = m
n_chunks = math.ceil(float(n)/m)
for i in xrange(n_chunks):
    for j in xrange(n_chunks):
        chunk_i = (function of your choice to read lines i*lines_per_chunk to (i+1)*lines_per_chunk)
        chunk_j = (function of your choice to read lines j*lines_per_chunk to (j+1)*lines_per_chunk)
        similarity[i*lines_per_chunk:(i+1)*lines_per_chunk,
                   j*lines_per_chunk:(j+1)*lines_per_chunk] = fast_operation(chunk_i, chunk_j) 

데이터를 청크로 로드한 후 매트릭스 연산을 수행하는 것이 요소별로 수행하는 것보다 훨씬 빠릅니다.

큰 파일을 한 줄씩 읽는 가장 좋은 방법은 python 열거 함수를 사용하는 것입니다.

with open(file_name, "rU") as read_file:
    for i, row in enumerate(read_file, 1):
        #do something
        #i in line of that line
        #row containts all data of that line

언급URL : https://stackoverflow.com/questions/8009882/how-to-read-a-large-file-line-by-line

반응형