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

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

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

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

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

Ответы [ 14 ]

32 голосов
/ 05 февраля 2010

в linux есть команда split

split -l 100000 file.txt

будет разбит на файлы с одинаковым размером строки 100 000

15 голосов
/ 15 ноября 2008

Проверьте os.stat() для размера файла и file.readlines([sizehint]). Эти две функции должны быть всем, что вам нужно для чтения, и, надеюсь, вы знаете, как писать:)

9 голосов
/ 15 мая 2012

В качестве альтернативного метода, используя библиотеку журналов:

>>> import logging.handlers
>>> log = logging.getLogger()
>>> fh = logging.handlers.RotatingFileHandler("D://filename.txt", 
     maxBytes=2**20*100, backupCount=100) 
# 100 MB each, up to a maximum of 100 files
>>> log.addHandler(fh)
>>> log.setLevel(logging.INFO)
>>> f = open("D://biglog.txt")
>>> while True:
...     log.info(f.readline().strip())

Ваши файлы будут выглядеть следующим образом:

filename.txt (конец файла)
filename.txt.1
filename.txt.2
...
filename.txt.10 (начало файла)

Это быстрый и простой способ сделать огромный файл журнала соответствующим вашей RotatingFileHandler реализации.

5 голосов
/ 05 февраля 2010

Этот метод генератора (медленный) способ получить часть строк, не разрушая вашу память.

import itertools

def slicefile(filename, start, end):
    lines = open(filename)
    return itertools.islice(lines, start, end)

out = open("/blah.txt", "w")
for line in slicefile("/python27/readme.txt", 10, 15):
    out.write(line)
4 голосов
/ 07 июня 2018

Теперь есть модуль pypi, который вы можете использовать для разбиения файлов любого размера на куски. Проверьте это

https://pypi.org/project/filesplit/

4 голосов
/ 24 декабря 2014

Хотя ответ Райана Гинстрома верен, это займет больше времени, чем следовало (как он уже отметил) Вот способ обойти множественные вызовы itertools.islice путем последовательной итерации по дескриптору открытого файла:

def splitfile(infilepath, chunksize):
    fname, ext = infilepath.rsplit('.',1)
    i = 0
    written = False
    with open(infilepath) as infile:
        while True:
            outfilepath = "{}{}.{}".format(fname, i, ext)
            with open(outfilepath, 'w') as outfile:
                for line in (infile.readline() for _ in range(chunksize)):
                    outfile.write(line)
                written = bool(line)
            if not written:
                break
            i += 1
4 голосов
/ 05 февраля 2010

не забудьте seek () и mmap () для произвольного доступа к файлам.

def getSomeChunk(filename, start, len):
    fobj = open(filename, 'r+b')
    m = mmap.mmap(fobj.fileno(), 0)
    return m[start:start+len]
4 голосов
/ 15 ноября 2008

Вы можете использовать wc и split (см. Соответствующие страницы), чтобы получить желаемый эффект. В bash:

split -dl$((`wc -l 'filename'|sed 's/ .*$//'` / 3 + 1)) filename filename-chunk.

производит 3 части одного и того же количества строк (конечно, с ошибкой округления в последнем) с именами от filename-chunk.00 до filename-chunk.02.

2 голосов
/ 15 октября 2015

использование - split.py имя файла splitsizeinkb

import os
import sys

def getfilesize(filename):
   with open(filename,"rb") as fr:
       fr.seek(0,2) # move to end of the file
       size=fr.tell()
       print("getfilesize: size: %s" % size)
       return fr.tell()

def splitfile(filename, splitsize):
   # Open original file in read only mode
   if not os.path.isfile(filename):
       print("No such file as: \"%s\"" % filename)
       return

   filesize=getfilesize(filename)
   with open(filename,"rb") as fr:
    counter=1
    orginalfilename = filename.split(".")
    readlimit = 5000 #read 5kb at a time
    n_splits = filesize//splitsize
    print("splitfile: No of splits required: %s" % str(n_splits))
    for i in range(n_splits+1):
        chunks_count = int(splitsize)//int(readlimit)
        data_5kb = fr.read(readlimit) # read
        # Create split files
        print("chunks_count: %d" % chunks_count)
        with open(orginalfilename[0]+"_{id}.".format(id=str(counter))+orginalfilename[1],"ab") as fw:
            fw.seek(0) 
            fw.truncate()# truncate original if present
            while data_5kb:                
                fw.write(data_5kb)
                if chunks_count:
                    chunks_count-=1
                    data_5kb = fr.read(readlimit)
                else: break            
        counter+=1 

if __name__ == "__main__":
   if len(sys.argv) < 3: print("Filename or splitsize not provided: Usage:     filesplit.py filename splitsizeinkb ")
   else:
       filesize = int(sys.argv[2]) * 1000 #make into kb
       filename = sys.argv[1]
       splitfile(filename, filesize)
2 голосов
/ 16 ноября 2008

Я написал программу, и она работает нормально. Так что спасибо Камилю Кисиелю за то, что я начал.
(Обратите внимание, что FileSizeParts () - это функция, не показанная здесь)
Позже я могу приступить к созданию версии, которая выполняет двоичное чтение, чтобы узнать, быстрее ли это.

def Split(inputFile,numParts,outputName):
    fileSize=os.stat(inputFile).st_size
    parts=FileSizeParts(fileSize,numParts)
    openInputFile = open(inputFile, 'r')
    outPart=1
    for part in parts:
        if openInputFile.tell()<fileSize:
            fullOutputName=outputName+os.extsep+str(outPart)
            outPart+=1
            openOutputFile=open(fullOutputName,'w')
            openOutputFile.writelines(openInputFile.readlines(part))
            openOutputFile.close()
    openInputFile.close()
    return outPart-1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...