2010-08-11 3 views
1

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

#--------------------------------------------------------------------------- 
#!/usr/bin/perl 

open IFILE, "text3.txt" or die "File not found"; 
open OFILE, ">text4.txt" or die "File not found"; 

my $lineno = 0; 

while(<IFILE>) 
{ 
@var=<IFILE>; 
$lineno++; 
print OFILE "@var"; 
} 

close(<IFILE>); 
close(<OFILE>); 
#--------------------------------------------------------------------------- 

Проблема в том, что она читает и пишет contens, но не все. text3.txt имеет четыре строки. Вышеприведенный скрипт читается только со второй строки и записывается в text4.txt. Итак, наконец, я получаю только три строки (line.no 2 to line.no 4) text3.txt.

Что не так с вышеуказанной программой. Я не знаю, как проверить поток выполнения на скриптах Perl. Пожалуйста, помогите мне.

Я совершенно не знаком с программированием. Я считаю, что все это помогло бы мне изменить карьерный путь.

Спасибо заранее,

Виджай

+2

Начиная с вашего вопроса, делая грубые замечания другим пользователям переполнения стека, я хочу прекратить чтение. Так я и сделал. –

+0

Извините, Грег Хьюджилл. Но в прошлый раз это действительно повредило мне. Это только второй раз, когда я использую переполнение стека. В первый раз, я получил очень плохой комментарий. Надеюсь, что вы понимаете. – Invincible

+2

Извините, что у вас был плохой первый опыт. Тем не менее, я настоятельно рекомендую вам удалить грубые комментарии о других пользователях из этих (и будущих) вопросов. Каждый вопрос в Stack Overflow стоит на собственном опыте, и вы не хотите, чтобы его называли парнем, который всегда говорит о других пользователях в первом абзаце. –

ответ

0

Существует несколько вопросов, о которых вы можете подумать, если вы строго копируете файл, вы можете использовать модуль File :: Copy.

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

Это зависит от того, что вы делаете внизу.Кроме того, если у вас есть огромный двоичный файл, каждая строка в цикле while может оказаться огромной, поэтому, если память действительно является проблемой, вы можете использовать более низкоуровневое чтение на основе потоков, больше информации об I/O: http://oreilly.com/catalog/cookbook/chapter/ch08.html

Мое предложение было бы использовать очиститель PBP предложенный способ:

#!/usr/bin/perl 

use strict; 
use warnings; 
use English qw(-no_match_vars); 

my $in_file = 'text3.txt'; 
my $out_file = 'text4.txt'; 

open my $in_fh, '<', $in_file or die "Unable to open '$in_file': $OS_ERROR"; 
open my $out_fh, '>', $out_file or die "Unable to open '$out_file': $OS_ERROR"; 

while (<$in_fh>) { 
    # $_ is automatically populated with the current line 
    print { $out_fh } $_ or die "Unable to write to '$out_file': $OS_ERROR"; 
} 

close $in_fh or die "Unable to close '$in_file': $OS_ERROR"; 
close $out_fh or die "Unable to close '$out_file': $OS_ERROR"; 

ИЛИ просто распечатать весь в-файл непосредственно:

#!/usr/bin/perl 

use strict; 
use warnings; 
use English qw(-no_match_vars); 

my $in_file = 'text3.txt'; 
my $out_file = 'text4.txt'; 

open my $in_fh, '<', $in_file or die "Unable to open '$in_file': $OS_ERROR"; 
open my $out_fh, '>', $out_file or die "Unable to open '$out_file': $OS_ERROR"; 

local $INPUT_RECORD_SEPARATOR; # Slurp mode, read in all content at once, see: perldoc perlvar 

print { $out_fh } <$in_fh> or die "Unable to write to '$out_file': $OS_ERROR";; 

close $in_fh or die "Unable to close '$in_file': $OS_ERROR"; 
close $out_fh or die "Unable to close '$out_file': $OS_ERROR"; 

Кроме того, если вы просто хотите, чтобы применить регулярное выражение или подобное файлу быстро, вы можете посмотреть на ключ -i команда perl: perldoc perlrun

perl -p -i.bak -e 's/foo/bar/g' text3.txt; # replace all foo with bar in text3.txt and save original in text3.txt.bak 
+0

Возможно, стоит упомянуть, что PBP означает «Perl Best Practices» Дамиана Конвей * http://oreilly.com/catalog/9780596001735/ – Telemachus

+0

Благодарим вас за объяснение и пример кода. SOF действительно помогает. Я должен был использовать гораздо раньше в своей карьере. Еще раз, спасибо. – Invincible

3

<IFILE> читает одну строку из IFILE (только один, потому что это в скалярном контексте). Итак, while(<IFILE>) читает первую строку, затем <IFILE> в контексте списка внутри блока while читает остальные. То, что вы хотите сделать, это:

# To read each line one by one: 
while(!eof(IFILE)) { # check if end of file is reached instead of reading a line 
    my $line = <IFILE>; # scalar context, reads only one line 
    print OFILE $line; 
} 

# Or to read the whole file at once: 
my @content = <IFILE>; # list context, read whole file 
print OFILE @content; 
+0

Большое спасибо, JKramer. Теперь он отлично работает. Не могли бы вы предложить мне несколько учебников, чтобы узнать больше о Perl? – Invincible

+0

@Invincible: [Learning Perl] (http://learn.perl.org/books.html) настоятельно рекомендуется (и один из авторов даже является постоянным участником Stack Overflow!). –

+0

Единственная книга Perl, которую я когда-либо читал, была [Эффективный Perl] (http://www.amazon.com/Effective-Perl-Programming-Idiomatic-Development/dp/0321496949/ref=sr_1_1?ie=UTF8&s=books&qid=1281522398&sr= 8-1), но я предполагаю, что он предназначен для программистов, которые уже знают этот язык. – jkramer

1

Проблема заключается в том, что эта линия ...

while(<IFILE>) 

... читает одну строку из text3.txt, а затем эта линия ...

@var=<IFILE>; 

... читает ВСЕ оставшиеся строки из text3.txt.

Вы можете сделать это в любом случае, путем петли с while или сразу с @var=<IFILE>, но попытка сделать то и другое не будет работать.

+0

Большое спасибо. – Invincible

0

Когда вы закрываете файлы, использовать только

close(IFILE); 
close(OFILE); 

При окружать дескриптор файла с угловыми скобками, как <IFILE>, Perl интерпретирует, что означает «читать строку текста из файла внутри угла кронштейны". Вместо чтения из файла вы хотите закрыть сам файл.

1

Так я бы написал код в вашем вопросе.

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

# don't need to use "or die ..." when using the autodie module 
open my $input, '<', 'text3.txt'; 
open my $output, '>', 'text4.txt'; 

while(<$input>){ 
    my $lineno = $.; 
    print {$output} $_; 
} 
# both files get closed automatically when they go out of scope 
# so no need to close them explicitly 

Я бы рекомендовал всегда положить use strict и use warnings в начале всех файлов Perl. По крайней мере, пока вы не знаете точно, почему это рекомендуется.

Я использовал autodie, так что мне не нужно было проверять возвращаемое значение open вручную. (autodie был добавлен в ядро ​​в версии 5.10.1)

Я использовал три аргумента форму open, поскольку она является более надежной.

Важно отметить, что while (<$input>){ ... } преобразуется в while (defined($_ = <$input>)){ ... } компилятором. Это означает, что текущая строка находится в переменной $_.

Я также использовал специальную переменную $., чтобы получить номер текущей строки, вместо того, чтобы пытаться отслеживать номер самостоятельно.

+0

Большое спасибо! – Invincible

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