Perlの質問です。CGIで呼ばれるプログラムでファイルの読み込みが失敗し困っています。

具体的には読み込み自体は成功するのですが、以下のような一般的(と思うんですが)複数行あるはずのデータが一行になってforeach が一回しか回らないという現象です。

if ( !open( FH, $filename ) ) {エラー処理}
my @array = <FH>;close(FH);
foreach my $line(@array){
ほにゃらら。
}

厄介なのは起きるときと起きない時があるところです。
成功するときは問題なく取れるが失敗すると数百行あっても一行として読み込まれてしまいます。
現象が出始めるとApacheのリスタートで直ります。
違うサーバで試しに移動してみると再現しません。

環境
Red Hat Enterprise Linux ES release 4
Apache2.0.52
Perl v5.8.5
mod_perl 1.99

use strict、warningsは問題があるプログラムではつけいるしエラー、警告は出ていません。
ただしつけてないプログラムが同じサーバに同居しています。
たぶんメモリ関係だと思うのですが。

なにか関連するモジュールでの不具合情報などありませんか?
情報がないとバージョンアップもできないので。

回答の条件
  • 1人2回まで
  • 登録:2009/07/10 14:06:54
  • 終了:2009/07/15 10:15:03

ベストアンサー

id:b-wind No.1

b-wind回答回数3344ベストアンサー獲得回数4402009/07/10 14:23:37

ポイント90pt

正直その情報量ではなんともいえないな。

どんなデータを読み込んでいるかも分からんので、推測になるがまずは改行コードでも疑ってみたら?

Perl 側の改行コード判定は $/ の変数の値だ。

perlvar - Perl で定義済みの変数


あとは一気に全部読み込もうとしてるがこれはメモリ使用量を食うのでお勧めはしない。

とはいえ、今回の現象とは関係ないだろうが。


あとはいまどきのコードとしてはファイルハンドルの使い方がうまくないな。

ファイルハンドルはグローバルスコープをもつので重複があると厄介

eval {
  open( my $fh, $filename ) ) or die "Can't open file!: $filename, $!";

  while ( my $line = <$fh> ){
    # ほにゃらら。
  }

  close($fh) or die "Can't close file!: $filename, $!";
}
if ( $@ ) { # $@ 変数にエラーメッセージが格納される。
 # エラー処理
}

バイナリファイルなら、もう一手間要るけど。

id:komamix

教えていただいた$/で$/="\n";と読み込む前に強制的に書き換えると現象が出なくなりました。

中に何が入っていたのかわかりませんが、何かのプログラムで書き換えられていたようです。

ただ読み込む前に全て代入しないと無理ですよね。

他の人の作ったプログラムも大量に載っているので…。

2009/07/10 15:52:45

その他の回答(1件)

id:b-wind No.1

b-wind回答回数3344ベストアンサー獲得回数4402009/07/10 14:23:37ここでベストアンサー

ポイント90pt

正直その情報量ではなんともいえないな。

どんなデータを読み込んでいるかも分からんので、推測になるがまずは改行コードでも疑ってみたら?

Perl 側の改行コード判定は $/ の変数の値だ。

perlvar - Perl で定義済みの変数


あとは一気に全部読み込もうとしてるがこれはメモリ使用量を食うのでお勧めはしない。

とはいえ、今回の現象とは関係ないだろうが。


あとはいまどきのコードとしてはファイルハンドルの使い方がうまくないな。

ファイルハンドルはグローバルスコープをもつので重複があると厄介

eval {
  open( my $fh, $filename ) ) or die "Can't open file!: $filename, $!";

  while ( my $line = <$fh> ){
    # ほにゃらら。
  }

  close($fh) or die "Can't close file!: $filename, $!";
}
if ( $@ ) { # $@ 変数にエラーメッセージが格納される。
 # エラー処理
}

バイナリファイルなら、もう一手間要るけど。

id:komamix

教えていただいた$/で$/="\n";と読み込む前に強制的に書き換えると現象が出なくなりました。

中に何が入っていたのかわかりませんが、何かのプログラムで書き換えられていたようです。

ただ読み込む前に全て代入しないと無理ですよね。

他の人の作ったプログラムも大量に載っているので…。

2009/07/10 15:52:45
id:b-wind No.2

b-wind回答回数3344ベストアンサー獲得回数4402009/07/10 16:22:17

ポイント10pt

ただ読み込む前に全て代入しないと無理ですよね。

他の人の作ったプログラムも大量に載っているので…。

そりゃあつらいな。

知ってのとおり、mod_perl は永続化する。

グローバル変数なんでいじった日には逆に他のプログラムのほうで逆のエラーが出る羽目になる。


場当たり的だが回避策としては、このぐらいか。

  • 前文読み込まれることを前提として、 split "\n" で各行に分ける
my @array = split "\n", <FH>;
  • ファイル読み込みを行っている CGI の先頭でグローバル変数を局所的に書き換える
use strict;
use warnings;

local $/ = "\n";

local 構文はレキシカルスコープだから他のプログラムに影響を与えることは無いはず。

もうちょっときれいな解決策もありそうだけどなー。

  • id:pahoo
    同じスクリプトで、同じファイルを読み込もうとしたとき、他のサーバでは常に成功するのですか? 他のサーバの環境(とくにOSとPerlのバージョン)は同じですか?
    「ただしつけてないプログラムが同じサーバに同居しています」←日本語としても意味が分からないので、他の言い方をしてもらえると助かります。
  • id:komamix
    他のサーバは予備機なので基本的にサーバ環境は全て同じです。ただ動いてるプログラムは全て同じです。

    「ただしつけてないプログラムが同じサーバに同居しています」
    失礼しました。

    use strict;
    use warnings;
    がついていない。あまり推奨されないプログラムも同じサーバに同居してるという意味です。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません