2010-02-17 2 views
19

Я открываю файл в режиме добавления. Мне нужно заменить строки 2,3 и 4 в файле, а позже мне нужно добавить новые данные в конец файла.Как заменить строки в середине файла на Perl?

+1

Не похоже, что открытие файла в режиме * append * согласуется с заменой строки 2,3,4, которая уже написана. – huynhjl

+0

Как я могу отправить данные из одного файла в другой с нужными данными и добавить новые данные в конец – kkchaitu

+0

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

ответ

36

Я думаю, что это FAQ что я отправил на Stackoverflow больше всего. У perlfaq5 есть ответ How do I change, delete, or insert a line in a file, or append to the beginning of a file?.

Забудьте о том, как добавить режим добавления. Это просто сделает вашу жизнь труднее.


Основная идея вставки, изменения или удаления строки из текстового файла включает чтение и печать файла к точке, где вы хотите внести изменения, внесения изменений, а затем чтение и печать остальной файл. Perl не обеспечивает произвольный доступ к строкам (тем более, что разделитель ввода записей, $/, является изменяемым), хотя модули, такие как Tie::File, могут подделать его.

программа Perl-выполнять эти задачи, принимает основную форму открытия файла, печать его линии, а затем закрыть файл:

open my $in, '<', $file  or die "Can't read old file: $!"; 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

while(<$in>) 
    { 
    print $out $_; 
    } 

close $out; 

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

Чтобы добавить строки к началу, напечатайте эти строки, прежде чем вводить цикл, который печатает существующие строки.

open my $in, '<', $file  or die "Can't read old file: $!"; 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC 

while(<$in>) 
    { 
    print $out $_; 
    } 

close $out; 

Чтобы изменить существующие строки, вставьте код, чтобы изменить линии внутри цикла while. В этом случае код находит все нижние версии «perl» и верхние регистры.Это происходит для каждой строки, поэтому будьте уверены, что вы должны делать это на каждой линии!

open my $in, '<', $file  or die "Can't read old file: $!"; 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

print $out "# Add this line to the top\n"; 

while(<$in>) 
    { 
    s/\b(perl)\b/Perl/g; 
    print $out $_; 
    } 

close $out; 

Чтобы изменить только определенную линию, the input line number, $., полезно. Сначала прочитайте и распечатайте строки до тех, которые вы хотите изменить. Затем прочитайте одну строку, которую вы хотите изменить, измените ее и распечатайте. После этого прочитайте остальные строки и распечатайте их:

while(<$in>) # print the lines before the change 
    { 
    print $out $_; 
    last if $. == 4; # line number before change 
    } 

my $line = <$in>; 
$line =~ s/\b(perl)\b/Perl/g; 
print $out $line; 

while(<$in>) # print the rest of the lines 
    { 
    print $out $_; 
    } 

Чтобы пропустить линии, используйте элементы управления циклом. Следующий в этом примере пропускает строки комментариев, а последний останавливает всю обработку после того, как он встречает __END__ или __DATA__.

while(<$in>) 
    { 
    next if /^\s+#/;    # skip comment lines 
    last if /^__(END|DATA)__$/; # stop at end of code marker 
    print $out $_; 
    } 

ли один и тот же вид, что нужно удалить определенную строку с помощью следующей пропустить строки, которые вы не хотите показывать на выходе. Этот пример пропускает каждую пятую строку:

while(<$in>) 
    { 
    next unless $. % 5; 
    print $out $_; 
    } 

Если, по какой-то причине, вы действительно хотите видеть весь файл сразу, а не строка за строкой обработки, вы можете чавкать его (до тех пор, как вы может поместиться все это в памяти):

open my $in, '<', $file  or die "Can't read old file: $!" 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

my @lines = do { local $/; <$in> }; # slurp! 

    # do your magic here 

print $out @lines; 

модули, такие как File::Slurp и Tie::File может помочь с этим тоже. Однако, если вы не можете прочитать весь файл сразу. Perl не возвращает эту память операционной системе до завершения процесса.

Вы также можете использовать однострочные элементы Perl для изменения файла на месте. Все изменения все 'Fred' к 'Barney' в inFile.txt, переписывая файл с новым содержимым. С помощью переключателя -p Perl завершает цикл while по коду, указанному с помощью -e, и -i включает редактирование на месте. Текущая строка находится в $_. С -p Perl автоматически печатает значение $_ в конце цикла. См. perlrun для более подробной информации.

perl -pi -e 's/Fred/Barney/' inFile.txt 

Чтобы сделать резервную копию inFile.txt, дать -i файла расширения для добавления:

perl -pi.bak -e 's/Fred/Barney/' inFile.txt 

Чтобы изменить только пятой строке, можно добавить тест проверки $., количество линейного входа , то только выполнить операцию, когда тест пройден:

perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt 

Чтобы добавить строки до определенной строки, можно добавить строку до Perl печатает(или строки!):

perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt 

Вы можете даже добавить строку в начало файла, так как текущие принтами линии в конце цикла:

perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt 

Чтобы вставить строку после одного уже в файл, используйте переключатель -n. Это точно так же, как -p, за исключением того, что он не печатает $_ в конце цикла, поэтому вам нужно сделать это самостоятельно.В этом случае сначала напечатайте $_, затем распечатайте строку, которую вы хотите добавить.

perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt 

Чтобы удалить строки, напечатайте только те, которые вы хотите.

perl -ni -e 'print unless /d/' inFile.txt 

    ... or ... 

perl -pi -e 'next unless /d/' inFile.txt 
+0

Неправильная ссылка на часто задаваемые вопросы, правильная ссылка: http://learn.perl.org/faq/perlfaq5.html#How-do-I-change-delete-or-insert-a-line-in-a- файл или-конкатенирующего к-начало-о-а-файла. Я попытался отредактировать его, но редактор не позволил мне сэкономить, выбросив сообщение о вводе кода. –

+0

Исправлено, спасибо. ФАКУ изменили URL-адреса. –

0

Если открыть файл в режиме дописывания, то вы не можете заменить линию, которая уже была в файле, когда вы открыли его. Файл append означает, что ваша программа имеет возможность читать файл и добавлять его к концу.

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

Я думаю, я не совсем понимаю назначение.

+0

@hobbs, см. Perl doc, http://perldoc.perl.org/perlopentut.html Он говорит, что режим + >> (чтение и добавление) «... позволит вам читать в любой точке файла, но все записи всегда будут идти до конца ». Поэтому будьте осторожны, реализация одной системы не означает, что она правильная. –

4

Вы можете сделать это с помощью Tie::File. (Имейте в виду, что ему придется переписать весь файл, чтобы заменить исходные строки, но Tie :: File скроет данные от вас.)

3

Хорошая Perl-идиома - читать и записывать стандартный ввод и вывод. При необходимости вы можете перенаправить и перенаправить. Через оператора <> (перенос на чтение), Perl откроет файлы, которые вы передаете в качестве аргумента в командной строке.

Чтобы ответить на ваш вопрос, несколько строк кода (как чистый, насколько это возможно):

#!/usr/bin/env perl 
use strict; use warnings; 

while (<>) { 
    if ($. == 2) { 
    print "new data", "\n"; 
    next; 
    } 
    if ($. == 3) { 
    print "very new data", "\n"; 
    next; 
    } 
    print; 
} 

print "more data", "\n"; 

Затем называем это таким образом: Perl yourscript.pl входной_файл> выходной_файл

Если вы хотите открыть файлы самостоятельно (здесь мы просто пропустить ненужные строки):

my open $in_fh, '<', $inputfile 
    or die "Can't open file $inputfile: $!"; 

my open $out_fh, '>', $outputfile 
    or die "Can't open file $output: $!"; 

while (my $line = <$in_fh>) { 
    next if ($. == 2 or $. == 3 or $. == 4); 
    print $out_fh $line; 
} 
print $out_fh "...whatever\n"; 
-3
use File::Copy; 

     copy("/file1.txt","/file1_old.txt"); 
     open(FILEHANDLE,">file1.txt"); 
     open(FILEHANDLE1,"<file1_old.txt"); 

     my $linecount=1; 
     while(<FILEHANDLE1>) 
     { 
      print $_."\n"; 

      if($linecount>4) 
      { 
       print FILEHANDLE "$_"; 
      } 
      $linecount++; 
     } 

     { 
       ## new data will be placed 
     } 
     #####close the file handle 
     close(FILEHANDLE1); 
     close(FILEHANDLE); 
+1

Это довольно неэффективный метод. 'copy' считывает и записывает весь файл, а затем вы читаете и записываете его снова. Было бы лучше пропустить копию, прочитать файл file1.txt, записать в файл1.new, а затем переименовать file1.new в файл file1.txt. – cjm

Смежные вопросы