• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:1ファイルずつ読み込みたい)

ファイルを順次読み込みながら処理する方法について

このQ&Aのポイント
  • ウィンドウズ環境でactive perlを利用して、あるディレクトリに2000件のファイルがあります。これらのファイルを1つずつ読み込んで置換処理を行いたいです。しかし、ファイル数が多すぎてメモリ不足になり中断されてしまいます。対策として、ディレクトリの中のファイルを1つずつ順次読み込んで処理する方法を教えてください。
  • ディレクトリの中にある2000件のファイルをactive perlを使用して読み込んで置換処理を行いたいです。しかし、ファイルを一度に全て読み込むとメモリ不足になって中断されてしまいます。どのようにすれば1つずつファイルを読み込みながら処理できるでしょうか?
  • ウィンドウズ環境のactive perlを使用して、ディレクトリ内の2000件のファイルを1つずつ読み込んで置換処理を行いたいです。ただし、ファイルの数が多くてメモリが足りず、処理が中断されてしまいます。解決策として、ファイルを順次読み込んで処理する方法を教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

まず、<*.html>が原因かどうかの確認。 @files = <*.html> ; だけのスクリプトが動作するかどうか。 動作しないようなら、ここでのメモリ不足なので、対策をする。 例えば、opendir, readdir, closedir を使う。 my $dirname = '.' ; opendir my $dp, $dirname ; while(my $fname = readdir $dp){ # 今回はカレントディレクトリなので不要だが # readdirでは名前しか得られないので、実際にopenなどで使うには # opendirに使ったディレクトリを追加する my $fullname = $dirname . '/' . $fname # html以外は対象外 if ( $fname !~ /.*\.html$/ ) { next ; } ... $fname/$fullnameについての処理 ... } closedir $dp; 動作するようなら、その後の処理が問題。 今のやり方(一時ファイルに出力→リネーム)でやるなら、@record=<IN_FILE>;などと全部取り込まなくても、一行ずつ処理すればいい。 @record=<IN_FILE>; foreach $record (@record){ $record =~s/aaa/bbb/isg; } print OUT @record → while(my $record = <IN_FILE>){ $record =~ s/aaa/bbb/isg; print OUT $record }

shishi16
質問者

補足

早速回答いただきありがとうございます。 @files = <*.html> ;は作動しました。 while(my $record = <IN_FILE>){ $record =~ s/aaa/bbb/isg; print OUT $record; } もうまくいきました。本当に有難うございます。 実は多分「opendir, readdir, closedir 」を使うのだろうなと考えていたため、 一時ファイルに出力→リネームの場合に対応する方法があるとは考えてもいませんでした。 質問内容について聞けば全てに応用できると思っていたのですが、応用できないパターンが出てきてしまいました。 新規にファイルを作るパターンもよく利用しておりこちらもメモリー不足で悩んでいます。 こちらもディレクトリーの中に2000位のファイルが入っており、 1ファイルはおおよそ3000行くらいです。 このファィルから特定の情報を抜き出し、一つのファイル(下記の場合はichiran.html)として出力します。 元のファイル一つに対し抜き出した情報は1行しかありませんので出来上がったichiran.htmlは2000行程度のファイルです。 下記のようなperlの場合はどのようにすればいいのでしょうか。 追加で申し訳ありませんがよろしくお願いします。 foreach(<*.html>) { open(IN_FILE, $_) ; @record=<IN_FILE>; foreach $item (@record){ #項目 if ($item=~ /.*<[^>]*Title\">([^>]*)<.*/si) { $koumoku= "$1"; $item= ""; } #原価 elsif ($item=~ /.*<[^>]*Price\">([^>]*)<.*/si) { $kakaku="$1"; $item= "<tr><td>$koumoku<\/td><td>$kakaku<\/td><\/tr> } else { $item="" ; } } @total = (@total, @record); } close( IN_FILE); $out_file="./ichiran.html"; open(OUT_FILE, ">>$out_file") ; print OUT_FILE @total; close( OUT_FILE);

その他の回答 (2)

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

「元のファイル一つに対し抜き出した情報は1行しかありません」ということがわかっているなら, わざわざ巨大な配列を作らなくていいのでは? もちろん「ファイルを一度に読み込む」ことが必要な処理だとも思えない. push なんてのもあるけど.

shishi16
質問者

お礼

何度もありがとうございます。 わかりにくい書き方で申し訳ありません。 個々のファイル内の抜き出すデーターは2行にわかれているものもあり、一旦全部読み込み整理しています。 ただしディレクトリーの中のファイルをすべて読み込む必要はなく、ここを何とかしたかったのですが、同じ物を何度も読み込んでしまいうまくいきませんでした。 教えていただいた内容を比べると if ( $fname !~ /.*\.html$/ ) { next ; } の部分が不足していました。 お陰様で、ディレクトリーの中のファイルを1つずつ読み込むことができるようになり、全て解決しました。 ありがとうございます。

回答No.2

active perlのことはよくわかんないけど、ファイルないの置換するだけなら perl -i.bak -pe"s/aaa/bbb/isgo;" *.html とかじゃだめなのです?

shishi16
質問者

お礼

早速回答いただきありがとうございます。 質問の書き方が悪くて申し訳ありません。 $record =~s/aaa/bbb/isg; の部分は「なにか処理をする」という程度の意味で書いおり、実際には置換以外の処理もしています。

関連するQ&A