• 締切済み

下のディレクトリ(3つ)に含まれる同じファイル名のテキストを結合し,カレントディレクトリに出力する

いつもお世話になっております.環境はWindows XPのActiveperlです. やりたいことは「下のディレクトリ(3つ)に含まれる同じファイル名のテキストを結合し,カレントディレクトリに出力する」ことです.具体的にはいかのようにしたいと思っています. 現在のディレクトリ/a/1.txt a b c 現在のディレクトリ/b/1.txt d e f 現在のディレクトリ/c/1.txt g h i 現在のディレクトリ/1.txt a b c d e f g h i ここで私は以下のプログラムを作成しました. use strict; use warnings; my $dirname1 = './a/'; my $dirname2 = './b/'; my $dirname3 = './c/'; opendir(DIR1, $dirname1) or die "$dirname1: $!"; while (my $dir1 = readdir(DIR1)) { next unless (-f $dir1); next unless ($dir1 =~ /\.txt$/); opendir(DIR2, $dirname2) or die "$dirname2: $!"; while (my $dir2 = readdir(DIR2)) { next unless (-f $dir2); next unless ($dir2 =~ /\.txt$/); opendir(DIR3, $dirname3) or die "$dirname3: $!"; while (my $dir3 = readdir(DIR3)) { next unless (-f $dir3); next unless ($dir3 =~ /\.txt$/); if (($dir1 == $dir2) && ($dir2 == $dir3)){ open(FILE1, $dir1) or die "$dir1: $!"; my $line1 = <FILE1>; close(FILE1); open(FILE2, $dir2) or die "$dir2: $!"; my $line2 = <FILE2>; close(FILE2); open(FILE3, $dir3) or die "$dir3: $!"; my $line3 = <FILE3>; close(FILE3); my $joint_line = $line1.$line2.$line3; open(NEWFILE, "> $dir1") or die "$dir1: $!"; print NEWFILE $joint_line; close(NEWFILE); } } } } closedir(DIR1); closedir(DIR2); closedir(DIR3); ですが,以下のようなエラーが発生しています. closedir() attempted on invalid dirhandle DIR2 at joint.pl line 51. closedir() attempted on invalid dirhandle DIR3 at joint.pl line 52. ディレクトリハンドルが使われているけれど閉じているか実際にはディレクトリハンドルでは無い時にこれらの警告が発行されるとこの警告がでるようですが,どのようにしたら解決できるのでしょうか.よろしくお願いします.

みんなの回答

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

そもそも、あるディレクトリにあるファイル名を取り出すのに opendir/reeaddir/closedir を使うこともないと思います。 @files = grep { -f } glob("$dir/*.txt"); てな感じで一気にリストが取れるのではないかと。

oswll
質問者

お礼

sakusaker7様 ご回答ありがとうございます. @files1 = grep { -f } glob("$dir1/*.txt"); @files2 = grep { -f } glob("$dir2/*.txt"); @files3 = grep { -f } glob("$dir3/*.txt"); で@filesに格納したあと,結合はどのようにするのでしょうか. *.txtで同じ場合,結合とするのですが,ヒントをいただけないでしょうか.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

ん~, なんか勘違いされてるような気が.... まず, my $dir = './a/'; my %fcount; opendir(DIR, $dir1); for my $filename (readdir(DIR)) { $fcount{$filename}++ if -f "$dir1$filename" && $filename =~ /\.txt$/; } closedir(DIR); とやると, ハッシュ %fcount は ./a の中にあるテキストファイルのみ 1 という値を持ちます. なので, 同じことを他のディレクトリに対しても行えば, 各ファイル名に対して「何個のディレクトリの中にあるか」がわかります. 今の場合は「3個のディレクトリにある」ファイル名に対して処理をするわけですから, %fcount の値が 3 であるようなキーに対して処理すればいいということになります. 現状では readdir が 3重ループになってますが, これなら 3回ループするだけなので高速であることが期待できます.

oswll
質問者

お礼

Tacosan様 ご回答ありがとうございます. 以下のように組んでみたのですがうまくいきません. use strict; use warnings; my $dir1 = './a/'; my $dir2 = './b/'; my $dir3 = './c/'; my %fcount; opendir(DIR1, $dir1); for my $filename1 (readdir(DIR1)) { $fcount{$filename}++ if -f "$dir1/$filename" && $filename =~ /\.txt$/; } closedir(DIR1); opendir(DIR2, $dir2); for my $filename2 (readdir(DIR2)) { $fcount{$filename}++ if -f "$dir2/$filename" && $filename =~ /\.txt$/; } closedir(DIR2); opendir(DIR3, $dir3); for my $filename3 (readdir(DIR3)) { $fcount{$filename}++ if -f "$dir3/$filename" && $filename =~ /\.txt$/; } closedir(DIR); if ($fcount == 3){ my $line = $filename1.$filename2.$filename3; open(NEWFILE, "> ./out/$dir") or die "$dir: $!"; print NEWFILE $line; close(NEWFILE); } 間違っている点をご連絡ください.よろしくお願いします.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

あれ? ディレクトリハンドルってブロックスコープなんだっけ.... とりあえず, もとのプログラムで closedir(DIR2) や closedir(DIR3) を適切な位置 (それぞれのディレクトリハンドルを opendir したブロックの最後) に移せば, エラーそのものは出ないと思う.... けど, それだけでは正しく動かないはず. まずはじめに 3つのディレクトリから「共通のファイル名」を選んでおき, それらに対して改めてマージするというように書いた方が安全だと思う. 今のままでも (一部を修正すれば) 動くけど, 明らかに無駄.

oswll
質問者

お礼

Tacosan様 ご回答ありがとうございます. それでは,入力ファイルと出力ファイル(入力名と出力名が同じため1つ)を作っておいて,それを参照してディレクトリから読み込んでマージがいいですし,早いんですね.明日早速試してみます.

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

opendir して中身を取り出したら、次のopendirをする前にclosedirする。

oswll
質問者

お礼

sakusaker7様 ご回答ありがとうございます. > opendir して中身を取り出したら、次のopendirをする前にclosedirする。 とは以下のようなごとでしょうか. use strict; use warnings; my $dirname1 = './1-5/'; my $dirname2 = './6-10/'; my $dirname3 = './11-12/'; opendir(DIR1, $dirname1) or die "$dirname1: $!"; while (my $dir1 = readdir(DIR1)) { next unless (-f $dir1); next unless ($dir1 =~ /\.txt$/); open(FILE1, $dir1) or die "$dir1: $!"; my $line1 = <FILE1>; close(FILE1); closedir(DIR1); #←ここに挿入 opendir(DIR2, $dirname2) or die "$dirname2: $!"; while (my $dir2 = readdir(DIR2)) { next unless (-f $dir2); next unless ($dir2 =~ /\.txt$/); open(FILE2, $dir2) or die "$dir2: $!"; my $line2 = <FILE2>; close(FILE2); closedir(DIR2); #←ここに挿入 opendir(DIR3, $dirname3) or die "$dirname3: $!"; while (my $dir3 = readdir(DIR3)) { next unless (-f $dir3); next unless ($dir3 =~ /\.txt$/); open(FILE3, $dir3) or die "$dir3: $!"; my $line3 = <FILE3>; close(FILE3); closedir(DIR3); #←ここに挿入 if (($dir1 eq $dir2) && ($dir2 eq $dir3)){ my $joint_line = $line1.$line2.$line3; open(NEWFILE, "> $dir1") or die "$dir1: $!"; print NEWFILE $joint_line; close(NEWFILE); } } } } そうしますと,エラーは出ないのですが出力されません. なぜなのでしょうか.よろしくお願いします.{}の位置が違うのでしょうか.

関連するQ&A