2013-05-20 2 views
3

У меня есть набор довольно больших файлов (около 50 мегабайт каждый и не менее сотни), но мне нужно вставить небольшой заголовок (около 2 дюжин строк) на каждый для обработки цели. Я надеялся написать сценарий в bash или python для этого, но я не могу найти функцию постоянного времени, которая позволит мне вставлять в начало текстового файла. Если это не постоянное время, я думаю, что это займет слишком много времени, чтобы закончить. У кого-нибудь есть опыт в этой проблеме?Модификация текстового файла с постоянным временем

+4

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

+2

... но если вы позже планируете 'open()' файлы в Python (или каком-то другом языке) обрабатывать их, вы можете подделать файл-подобный объект, который «притворяется», что у них есть «маленький заголовок» «добавлено к ним, вместо того, чтобы изменять фактические файлы, считая, что это приемлемая альтернатива. – Aya

ответ

2

Я считаю, что это близко к лучшим вы будете делать (Баш):

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) 

Однако, если вы хотите, чтобы это было строго безопасными, вы должны сделать это так же, как скрипт Баша, поэтому в конечном итоге может быть небольшая разница в скорости.

+1

Проверка 'OLDSIZE' /' NEWSIZE' кажется излишней; вы не делаете ничего подобного в версии Python. Существует нет (значимой) разницы в производительности при записи во временный файл и переименование по сравнению с перезаписью существующего файла. – chepner

+0

@chepner: True IFF временный файл находится в одной файловой системе ('/ tmp' часто находится в собственной файловой системе. Это, безусловно, здесь, на Arch Linux). Из-за этого я намеренно сделал версии разными. Кроме того, команда cat может потенциально выходить из строя (из космоса), и вы не хотите перезаписывать усеченную версию. – kampu

+0

Хороший вопрос о работе с файлами в кросс-файловой системе. – chepner

3

Вы не можете вставлять текст в файл Unix в постоянное время, ни в начале, ни в середине. С другой стороны, в зависимости от обработки, которую вы имеете в виду, есть небольшой шанс, что вы можете полностью избежать вставки. Он работает , если ваш инструмент обработки может читать из трубы. Тогда вы могли бы сделать что-то вроде

cat headerfile datafile | myprocessingtool 

так, что файл данных фактически не изменяется.

+0

Для пояснения, когда я сказал постоянное время, я имел в виду постоянное время относительно измененного файла. Очевидно, что он должен быть линейным относительно введенного текста. Разве это еще не возможно? – user2401982

+2

@ user2401982 При добавлении к файлу время, затраченное (по крайней мере теоретически), пропорционально размеру новых данных, которые вы добавляете, но если вы добавляете или вставляете, это пропорционально сумме размеров как исходный файл, так и новые данные. – Aya

4

Как и в ответе Уве, но если ваш инструмент обработки может принимать только параметры как имена файлов, вы можете подделать один с помощью 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 

... будет транслировать содержимое двух файлов, а не создавать новый файл.