Какой самый быстрый способ удалить число из начала такого количества файлов?

У меня есть 1000 файлов, каждый из которых содержит миллион строк. Каждая строка имеет следующую форму:

a number,a text

Я хочу удалить все числа в начале каждой строки каждого файла. в том числе,

Пример:

14671823,aboasdyflj -> aboasdyflj

Что я делаю, это:

os.system("sed -i -- 's/^.*,//g' data/*")

и это работает нормально, но это занимает огромное количество времени.

Какой самый быстрый способ сделать это?

Я пишу в Python.

4 ответа

Решение

Это намного быстрее:

cut -f2 -d ',' data.txt > tmp.txt && mv tmp.txt data.txt

Для файла с 11 миллионами строк это заняло менее одной секунды.

Чтобы использовать это для нескольких файлов в каталоге, используйте:

TMP=/pathto/tmpfile
for file in dir/*; do
    cut -f2 -d ',' "$file" > $TMP && mv $TMP "$file"
done

Стоит упомянуть, что на выполнение вещи часто требуется гораздо больше времени, чем на использование отдельного файла. Я попробовал вашу команду sed, но переключился с места на временный файл. Общее время сократилось с 26 до 9 секунд.

Я бы использовал GNU awk (чтобы использовать -i inplace редактирование файла) с , в качестве разделителя полей, нет дорогостоящих манипуляций с Regex:

awk -F, -i inplace '{print $2}' file.txt

Например, если имена файлов имеют общий префикс, такой как fileВы можете использовать оболочку globbing:

awk -F, -i inplace '{print $2}' file*

awk будет обрабатывать каждый файл как отдельный аргумент при применении изменений на месте.


Как примечание, вы можете просто запустить команду оболочки непосредственно в оболочке вместо того, чтобы обернуть ее в os.system() что небезопасно и устарела, кстати, в пользу subprocess,

Это, вероятно, довольно быстрый и родной питон. Уменьшенные петли и использование csv.reader & csv.writer которые скомпилированы в большинстве реализаций:

import csv,os,glob
for f1 in glob.glob("*.txt"):
    f2 = f1+".new"
    with open(f1) as fr, open(f2,"w",newline="") as fw:
        csv.writer(fw).writerows(x[1] for x in csv.reader(fr))
    os.remove(f1)
    os.rename(f2,f1)  # move back the newfile into the old one

может быть writerows часть может быть еще быстрее, используя map & operator.itemgetter удалить внутреннюю петлю:

csv.writer(fw).writerows(map(operator.itemgetter(1),csv.reader(fr)))

Также:

  • он переносим во всех системах, включая Windows без MSYS
  • он останавливается за исключением случая, когда проблема позволяет избежать разрушения ввода
  • временный файл специально создается в той же файловой системе, поэтому удаление + переименование происходит очень быстро (в отличие от перемещения временного файла для ввода между файловыми системами, что потребовало бы shutil.move & будет копировать данные)

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

FILES = ['a', 'b', 'c', 'd']
CORES = 4

q = multiprocessing.Queue(len(FILES))

for f in FILES:
    q.put(f)

def handler(q, i):
    while True:
        try:
            f = q.get(block=False)
        except Queue.Empty:
            return
        os.system("cut -f2 -d ',' {f} > tmp{i} && mv tmp{i} {f}".format(**locals()))

processes = [multiprocessing.Process(target=handler, args=(q, i)) for i in range(CORES)]

[p.start() for p in processes]
[p.join() for p in processes]

print "Done!"
Другие вопросы по тегам