2017-09-17 13 views
0

私はPerlを使用してファイルの内容を変更しようとしています。単一ファイルハンドルを使用してファイルの内容を変更する方法

次のスクリプトは正常に動作します。

#!/usr/bin/perl 

use strict; 
use warnings; 

open(FH,"test.txt") || die "not able to open test.txt $!"; 
open(FH2,">","test_new.txt")|| die "not able to opne test_new.txt $!"; 

while(my $line = <FH>) 
{ 
     $line =~ s/perl/python/i; 
     print FH2 $line; 
} 
close(FH); 
close(FH2); 

test.txtの内容:

im learning perl 
im in File handlers chapter 

test_new.txtでの出力:

im learning python 
im in File handlers chapter 

私はその後、私は、ファイルの内容を変更するために同じファイルハンドルを使用しようとすると期待される出力が得られない。次はこれを実行しようとするスクリプトです:test.txt

#!/usr/bin/perl 

use strict; 
use warnings; 

open(FH,"+<","test.txt") || die "not able to open test.txt $!"; 

while(my $line = <FH>) 
{ 
     $line =~ s/perl/python/i; 
     print FH $line; 
} 
close(FH); 

誤った出力:

im learning perl 
im learning python 
chapter 
chapter 

どのように私は、単一のファイルハンドルを使用してファイルの内容を変更できますか? Сухой[email protected]として

+2

実際には、 'perl -i -pe 's/perl/python/i' test.txt'でさえ、別のファイルに書きたいと思うでしょう。あるいは、一度にファイル全体を読んだり、変更したり、ファイル全体を同じハンドルに書き戻したりできます。 –

+0

@Сухой27コマンドでオプションが何をするか説明できます。つまり、-i -pe – kart1657

+1

ハンドラではなくファイル**ハンドル**です。 – melpomene

答えて

0

は、それが楽しく使用onliner perlの典型的な状況だ

に答え。

のperl -i -peさん/ perlの/パイソン/ i 'を

perlをオプション

  • -pの下に取り:回線ループでラインを作る(すべての行が$_に割り当て、評価後の印刷$_
  • -e:上記ループのコードブロックを評価する(正規表現はデフォルトオペランドとして$_とする)
  • -i:スクリプトの下に実行する場合

(あなたは-iの引数を渡すと、perlのその拡張子を持つ元のファイルを保存する)plcaeファイルの編集に

perlの-i.bak -pe "は、S/perlの/パイソン/私はあなたが変更されます

test.txtのtest.txt

im learning python 
im in File handlers chapter 

とあなたが(最後を除いて)ファイルから削除することはできませんtest.txt.bak

im learning perl 
im in File handlers chapter 
+1

これは2つのハンドルを使用することに注意してください。 – ikegami

2

で名付けられ、元のテキストファイルを取得します。
文字をファイルに挿入することはできません(最後を除く)。

ファイル内の文字を置き換えることができます。
ファイルに追加することができます。
ファイルを短くできます。
それです。

「Perl」をファイル内の「Python」に置き換えることができます。それらは同じ長さではないので、ファイルに文字を挿入する必要があります。そのことはできません。

残りのファイルをメモリにロードして2文字をさらに書き戻すことで、ファイルに効果的に文字を挿入することができます。しかし、非常に大きなファイルの場合、これを行うのは難しいことです。また、文字を挿入するたびにファイルの(おそらく非常に大きい)部分をコピーしてしまうので、非常に遅いです。

インプレース修正のもう1つの問題は、エラーから回復できないことです。何か問題が発生した場合、不完全または破損したファイルが残ってしまいます。

ファイルが小さく、何か問題が生じたときにデータを失うのが問題ない場合、最も簡単な方法は、ファイル全体をメモリにロードすることです。

open(my $fh, '<+', $qfn) 
    or die("Can't open \"$qfn\": $!\n"); 

my $file = do { local $/; <$fh> }; 

$file =~ s/Perl/Python/g; 

seek($fh, 0, SEEK_SET) 
    or die $!; 
print($fh $file) 
    or die $!; 
truncate($fh) 
    or die $!; 

より安全なアプローチは、データを新しいファイルに書き込んだり、完了したらファイルの名前を変更したりすることです。

my $new_qfn = $qfn . ".tmp"; 
open(my $fh_in, '<', $qfn) 
    or die("Can't open \"$qfn\": $!\n"); 
open(my $fh_out, '<', $new_qfn) 
    or die("Can't create \"$new_qfn\": $!\n"); 

while (<$fh_in>) { 
    s/Perl/Python/g; 
    print($fh_out $_); 
} 

close($fh_in); 
close($fh_out); 

rename($qfn_new, $qfn) 
    or die $!; 

この方法の欠点は、ファイルのパーミッションを変更する場合がありますし、ハードリンクではなく、新しいファイルの古い内容を指します。また、ファイルを作成するための権限も必要です。

関連する問題