Разделите текстовый файл на 10 ГБ 1) с минимальным размером выходных файлов 40 МБ и 2) после определенной строки (</запись>)

Я получил большой текстовый файл (10 ГБ, .xml, содержит более чем 1 миллион тегов как это: <record>текст</record>) который я splitted в части для использования его. Но смочь автоматизировать мой рабочий процесс, необходимо, чтобы каждый расстается концы с определенным тегом: </record>. И также необходимо, чтобы каждая часть имела, по крайней мере, размер приблизительно 40 МБ.

2
задан 30 January 2019 в 22:04

1 ответ

Сценарий ниже частей (большой) файл в части. Я не использовал split команда, так как содержание Вашего файла должно быть "округлено" записями. Размер частей можно установить в главном разделе сценария.

Процедура

Трудности
Поскольку сценарий должен смочь иметь дело с огромными файлами, любой Python read() или readlines() не может использоваться; сценарий попытался бы загрузить целый файл сразу в память, которая будет, конечно, дросселировать Вашу систему. В то же время подразделения должны быть сделаны, "округлив" разделы целой записью. Сценарий должен поэтому так или иначе смочь определить или "считать" содержание файла.

То, что, кажется, единственная опция, должно использовать:

with open(file) as src:
    for line in src:

который читает файл линию за линией.

Подход
В сценарии я выбрал двухступенчатый подход:

  1. Проанализируйте файл (размер, количество частей, количество строк, количество записей, записей на раздел), затем создав список разделов или "маркеров" (с методической точностью индекс).
  2. чтение файла снова, но теперь выделение строк для разделения файлов.

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

Как я протестировал
Я создал xml файл немногим более, чем 10 ГБ, заполненных записями как Ваш пример. Я установил размер частей к 45mb. В моей not-so-recent системе (Pentium Двухъядерный ЦП E6700 3.20 ГГц × 2), анализ сценария произвел следующее:

analyzing file...

checking file size...
file size: 10767 mb
calculating number of slices...
239 slices of 45 mb
checking number of lines...
number of lines: 246236399
checking number of records...
number of records: 22386000
calculating number records per section ...
records per section: 93665

Затем это начало создавать части 45 МБ, беря appr. 25-27 секунд на часть для создания.

creating slice 1
creating slice 2
creating slice 3
creating slice 4
creating slice 5

и так далее...

Процессор был занят для 45-50% во время процесса, с помощью ~850-880mb моей памяти (4 ГБ). Компьютер был довольно применим во время процесса.

Целая процедура заняла полтора часа. В более свежей системе должно потребоваться существенно меньше времени.

Сценарий

#!/usr/bin/env python3

import os
import time

#---
file = "/path/to/big/file.xml" 
out_dir = "/path/to/save/slices"
size_ofslices = 45 # in mb
identifying_string = "</record>"
#---

line_number = -1
records = [0]

# analyzing file -------------------------------------------

print("analyzing file...\n")
# size in mb
print("checking file size...")
size = int(os.stat(file).st_size/1000000)
print("file size:", size, "mb")
# number of sections
print("calculating number of slices...")
sections = int(size/size_ofslices)
print(sections, "slices of", size_ofslices, "mb")
# misc. data
print("checking number of lines...")
with open(file) as src:
    for line in src:
        line_number = line_number+1
        if identifying_string in line:
            records.append(line_number)
# last index (number of lines -1)
ns_oflines = line_number
print("number of lines:", ns_oflines)
# number of records
print("checking number of records...")
ns_records = len(records)-1
print("number of records:", ns_records)
# records per section
print("calculating number records per section ...")
ns_recpersection = int(ns_records/sections)
print("records per section:", ns_recpersection)

# preparing data -------------------------------------------

rec_markers = [i for i in range(ns_records) if i% ns_recpersection == 0]+[ns_records]   # dividing records (indexes of) in slices
line_markers = [records[i] for i in rec_markers]                                        # dividing lines (indexes of) in slices
line_markers[-1] = ns_oflines; line_markers.pop(-2)                                     # setting lias linesection until last line

# creating sections ----------------------------------------

sl = 1
line_number = 0

curr_marker = line_markers[sl]
outfile = out_dir+"/"+"slice_"+str(sl)+".txt"

def writeline(outfile, line):
    with open(outfile, "a") as out:
        out.write(line)

with open(file) as src:
    print("creating slice", sl)
    for line in src:
        if line_number <= curr_marker:
            writeline(outfile, line)
        else:
            sl = sl+1
            curr_marker = line_markers[sl]
            outfile = out_dir+"/"+"slice_"+str(sl)+".txt"
            print("creating slice", sl)
            writeline(outfile, line)       
        line_number = line_number+1 

Как использовать

Скопируйте сценарий в пустой файл, установите путь в Ваш "большой файл", путь к каталогу для сохранения частей и размера частей. Сохраните его как slice.py и выполненный это командой:

/path/to/slice.py

Примечания

  • Размер большого файла должен превысить размер части по крайней мере несколько раз. Насколько больше различие более надежное размер (вывод) части будут.
  • Предположение было сделано этим, средний размер записей (замеченный в большем изображении) о том же. При рассмотрении огромного объема данных здесь, который можно было бы ожидать, это будет приемлемым предположением, но необходимо будет проверить (путем взгляда, если существует большая разница в размерах частей).
3
ответ дан 2 December 2019 в 02:59

Другие вопросы по тегам:

Похожие вопросы: