Какой самый быстрый способ удалить число из начала такого количества файлов?
У меня есть 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!"