Как мне разбить огромный текстовый файл в Python - PullRequest
22 голосов
/ 15 ноября 2008

У меня огромный текстовый файл (~ 1 ГБ), и, к сожалению, используемый мной текстовый редактор не будет читать такой большой файл. Однако, если я смогу просто разделить его на две или три части, у меня все будет в порядке, поэтому в качестве упражнения я хотел написать программу на python для этого.

Я думаю, что программа должна найти размер файла, разделить это число на части, и для каждой части прочитать до этого момента кусками, записав в имя файла выходной файл .nnn, затем чтение до следующего переноса строки и запись его, затем закрытие выходного файла и т. д. Очевидно, что последний выходной файл просто копируется в конец входного файла.

Можете ли вы помочь мне с ключевыми частями, относящимися к файловой системе: размером файлов, чтением и записью кусками и чтением до перевода строки?

Сначала я напишу этот код, поэтому нет необходимости давать мне полный ответ, если только он не однострочный; -)

Ответы [ 14 ]

1 голос
/ 02 декабря 2013

Это сработало для меня

import os

fil = "inputfile"
outfil = "outputfile"

f = open(fil,'r')

numbits = 1000000000

for i in range(0,os.stat(fil).st_size/numbits+1):
    o = open(outfil+str(i),'w')
    segment = f.readlines(numbits)
    for c in range(0,len(segment)):
        o.write(segment[c]+"\n")
    o.close()
0 голосов
/ 26 сентября 2017

Вот скрипт Python, который вы можете использовать для разделения больших файлов, используя subprocess:

"""
Splits the file into the same directory and
deletes the original file
"""

import subprocess
import sys
import os

SPLIT_FILE_CHUNK_SIZE = '5000'
SPLIT_PREFIX_LENGTH = '2'  # subprocess expects a string, i.e. 2 = aa, ab, ac etc..

if __name__ == "__main__":

    file_path = sys.argv[1]
    # i.e. split -a 2 -l 5000 t/some_file.txt ~/tmp/t/
    subprocess.call(["split", "-a", SPLIT_PREFIX_LENGTH, "-l", SPLIT_FILE_CHUNK_SIZE, file_path,
                     os.path.dirname(file_path) + '/'])

    # Remove the original file once done splitting
    try:
        os.remove(file_path)
    except OSError:
        pass

Вы можете назвать это внешне:

import os
fs_result = os.system("python file_splitter.py {}".format(local_file_path))

Вы также можете импортировать subprocess и запускать его прямо в вашей программе.

Проблема с этим подходом заключается в большом использовании памяти: subprocess создает разветвление с объемом памяти, равным размеру вашего процесса, и, если память процесса уже загружена, она удваивает ее за время выполнения. То же самое с os.system.

Вот еще один чистый способ сделать это на python, хотя я не тестировал его на больших файлах, он будет медленнее, но потребляет меньше памяти:

CHUNK_SIZE = 5000

def yield_csv_rows(reader, chunk_size):
    """
    Opens file to ingest, reads each line to return list of rows
    Expects the header is already removed
    Replacement for ingest_csv
    :param reader: dictReader
    :param chunk_size: int, chunk size
    """
    chunk = []
    for i, row in enumerate(reader):
        if i % chunk_size == 0 and i > 0:
            yield chunk
            del chunk[:]
        chunk.append(row)
    yield chunk

with open(local_file_path, 'rb') as f:
    f.readline().strip().replace('"', '')
    reader = unicodecsv.DictReader(f, fieldnames=header.split(','), delimiter=',', quotechar='"')
    chunks = yield_csv_rows(reader, CHUNK_SIZE)
    for chunk in chunks:
        if not chunk:
            break
        # Do something with your chunk here

Вот еще один пример использования readlines():

"""
Simple example using readlines()
where the 'file' is generated via:
seq 10000 > file
"""
CHUNK_SIZE = 5


def yield_rows(reader, chunk_size):
    """
    Yield row chunks
    """
    chunk = []
    for i, row in enumerate(reader):
        if i % chunk_size == 0 and i > 0:
            yield chunk
            del chunk[:]
        chunk.append(row)
    yield chunk


def batch_operation(data):
    for item in data:
        print(item)


with open('file', 'r') as f:
    chunks = yield_rows(f.readlines(), CHUNK_SIZE)
    for _chunk in chunks:
        batch_operation(_chunk)
0 голосов
/ 24 мая 2014

У меня было требование разделить CSV-файлы для импорта в Dynamics CRM, поскольку ограничение размера файла для импорта составляет 8 МБ, а файлы, которые мы получаем, намного больше. Эта программа позволяет пользователю вводить FileNames и LinesPerFile, а затем разбивает указанные файлы на требуемое количество строк. Я не могу поверить, как быстро это работает!

# user input FileNames and LinesPerFile
FileCount = 1
FileNames = []
while True:
    FileName = raw_input('File Name ' + str(FileCount) + ' (enter "Done" after last File):')
    FileCount = FileCount + 1
    if FileName == 'Done':
        break
    else:
        FileNames.append(FileName)
LinesPerFile = raw_input('Lines Per File:')
LinesPerFile = int(LinesPerFile)

for FileName in FileNames:
    File = open(FileName)

    # get Header row
    for Line in File:
        Header = Line
        break

    FileCount = 0
    Linecount = 1
    for Line in File:

        #skip Header in File
        if Line == Header:
            continue

        #create NewFile with Header every [LinesPerFile] Lines
        if Linecount % LinesPerFile == 1:
            FileCount = FileCount + 1
            NewFileName = FileName[:FileName.find('.')] + '-Part' + str(FileCount) + FileName[FileName.find('.'):]
            NewFile = open(NewFileName,'w')
            NewFile.write(Header)

        NewFile.write(Line)
        Linecount = Linecount + 1

    NewFile.close()
0 голосов
/ 15 ноября 2008

Или Python-версия wc и split:

lines = 0
for l in open(filename): lines += 1

Затем некоторый код для чтения первых строк / 3 в один файл, следующих строк / 3 в другой и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...