У меня есть набор довольно больших файлов (около 50 мегабайт каждый и не менее сотни), но мне нужно вставить небольшой заголовок (около 2 дюжин строк) на каждый для обработки цели. Я надеялся написать сценарий в bash или python для этого, но я не могу найти функцию постоянного времени, которая позволит мне вставлять в начало текстового файла. Если это не постоянное время, я думаю, что это займет слишком много времени, чтобы закончить. У кого-нибудь есть опыт в этой проблеме?Модификация текстового файла с постоянным временем
ответ
Я считаю, что это близко к лучшим вы будете делать (Баш):
MYHEADER=/path/to/the/header
HEADERSIZE=$(stat --format %s "$MYHEADER")
for FILENAME in $FILES; do
OLDSIZE=$(stat --format %s "$FILENAME")
cat "$MYHEADER" "$FILENAME" > /tmp/headerize.tmp
NEWSIZE=$(stat --format %s /tmp/headerize.tmp)
EXPECTEDSIZE=$(($HEADERSIZE+$OLDSIZE))
if [ "$NEWSIZE" -eq "$EXPECTEDSIZE" ]; then
mv /tmp/headerize.tmp "$FILENAME"
else
echo "Something odd happened when processing $FILENAME, headerization skipped for this file."
fi
done
Если у вас есть серьезно жалкая система или слишком высокие стандарты, как долго слишком долго, это должно завершить в порядочном время. И это включает проверку ошибок. Вы должны убедиться, что ваш заголовок заканчивается в новой строке, конечно, иначе финальная строка заголовка и первая строка текстового файла будут объединены.
Единственная оставшаяся оптимизация здесь заключается в обеспечении того, чтобы временный файл записывался в ту же файловую систему, что и исходные файлы; это потенциально ускорит команду mv.
В целом, вставка содержимого происходит медленно. Это верно, будь то в памяти или на диске. Я считаю, что вы будете никогда не найдете постоянное время-решение. Но вам, вероятно, на самом деле не нужен один для одноразового пакетного задания.
Это ИМО - самая быстрая реализация, которую вы можете сделать в Python. Так как он не создает временный файл, он может быть быстрее, чем версия Баша:
MYHEADERPATH=/path/to/the/header
with open(MYHEADERPATH, 'r') as f:
header = f.read()
for filename in files:
with open(filename, 'r') as f:
content = f.read()
with open(filename, 'w') as f:
f.write(header + content)
Однако, если вы хотите, чтобы это было строго безопасными, вы должны сделать это так же, как скрипт Баша, поэтому в конечном итоге может быть небольшая разница в скорости.
Проверка 'OLDSIZE' /' NEWSIZE' кажется излишней; вы не делаете ничего подобного в версии Python. Существует нет (значимой) разницы в производительности при записи во временный файл и переименование по сравнению с перезаписью существующего файла. – chepner
@chepner: True IFF временный файл находится в одной файловой системе ('/ tmp' часто находится в собственной файловой системе. Это, безусловно, здесь, на Arch Linux). Из-за этого я намеренно сделал версии разными. Кроме того, команда cat может потенциально выходить из строя (из космоса), и вы не хотите перезаписывать усеченную версию. – kampu
Хороший вопрос о работе с файлами в кросс-файловой системе. – chepner
Вы не можете вставлять текст в файл Unix в постоянное время, ни в начале, ни в середине. С другой стороны, в зависимости от обработки, которую вы имеете в виду, есть небольшой шанс, что вы можете полностью избежать вставки. Он работает , если ваш инструмент обработки может читать из трубы. Тогда вы могли бы сделать что-то вроде
cat headerfile datafile | myprocessingtool
так, что файл данных фактически не изменяется.
Для пояснения, когда я сказал постоянное время, я имел в виду постоянное время относительно измененного файла. Очевидно, что он должен быть линейным относительно введенного текста. Разве это еще не возможно? – user2401982
@ user2401982 При добавлении к файлу время, затраченное (по крайней мере теоретически), пропорционально размеру новых данных, которые вы добавляете, но если вы добавляете или вставляете, это пропорционально сумме размеров как исходный файл, так и новые данные. – Aya
Как и в ответе Уве, но если ваш инструмент обработки может принимать только параметры как имена файлов, вы можете подделать один с помощью mkfifo(1)
.
Например, в bash
...
echo 'My header' > header.txt
echo 'My content' > content.txt
mkfifo fakefile.txt
cat header.txt content.txt > fakefile.txt &
cat fakefile.txt
... будет транслировать содержимое двух файлов, а не создавать новый файл.
Нет, не в постоянное время. Вы не можете добавлять данные в файл без перезаписи всего файла. Это фундаментальное ограничение файловых систем, а не языков программирования. – Chewie
... но если вы позже планируете 'open()' файлы в Python (или каком-то другом языке) обрабатывать их, вы можете подделать файл-подобный объект, который «притворяется», что у них есть «маленький заголовок» «добавлено к ним, вместо того, чтобы изменять фактические файлы, считая, что это приемлемая альтернатива. – Aya