プログラムのアクセスカウンターをするプログラムを作成しましたが、アクセスカウンターのデータが消去されてしまいます。
プログラム抜粋
(ここから)
#アクセスカウンターカウント数計上ロジックを入れる
$data = "";
open(IN11,"$countcsv") || &error(" countcsv をopen出来ません");
flock(IN11,1);
while($lines11 = <IN11>) {
($seq,$acc) = split("\,", $lines11);
if ($page == $seq) {$acc = $acc +1; }
$data .= "$seq,$acc\n"
}
close(IN11);
open(IN21,">$countcsv")|| &error(" countcsv をopen出来ません");
flock(IN21,2);
print IN21 "$data";
close(IN21);
(ここまで)
count.csvの構成は以下のようになってます。
(ここから)
1,0
2,0
3,0
4,0
5,0
6,0
7,0
8,0
9,0
10,0
(ここまで)
カウンターを計測するデータ(行数)が多いと、データが全てなくなってしまいます。
ファイルロックの方法に問題があると思ってますが、どこが悪いのかがわかりません。
ご教授いただけますと助かります。
よろしくお願いいたします。
No.2ベストアンサー
- 回答日時:
問題点は4つあります。
今回の不具合においては1と2が致命的。
3は比較的軽微なバグ。
4以降は推奨される書き方です。
1.読み込み処理と書き込み処理が分かれているのにロックを個別に行っている。
「データを読む~データを改変する~データを書く」を一度のロックで行わないと
途中で他のプロセス処理が割り込む可能性がある。その結果、複数のプロセスが
矛盾するデータを書き込もうとした場合にいずれかのデータが失われる。
回避方法としては、下記のいずれかが有効。
・1つのファイルに対する読み書きの場合は1回のオープン+ロックで済ませる。
・複数ファイルを同時に処理する必要がある場合には、ロック用ファイルを用意し
これに対してロックを行ってからすべての処理を行う。
あるいは、処理の順番的に必ず最初にオープンするデータファイルがある場合は
これに対してロックをかけ、すべての処理を行ってから最初のファイルを最後に
クローズすることでロック用ファイルを兼ねる。
2.(上記と併せて)書き込み処理時に上書きモード'>'でオープンしている。
上書きモードでは、ファイルオープン時にファイル内容は一度すべて消去される。
この状態で1.の状況が発生した場合、ちょうど消去されたばかりのファイルを
別プロセスが読み込むために、既存データが消えることになる。
ファイルロックはファイルオープンとは同時には行うことができないため、
ロックがかかるまでに時差が発生することに注意する。
3.1行読み出し $lines11 = <IN11> において、末尾の改行を削除していない
$accに改行がついたままになっている。$accに変更があった行だけは数値代入の
副作用で改行が外れるが、変更がなかった行は改行がついたままの状態で
書き込み時にさらに改行が付加されるため、データに意図しない空行が発生する。
4.Perl4の文法で記述されている。
Perl4の文法でも、正しく記述すればこれ自体が不具合を起こすことはないが、
プログラムが大規模になるほどスクリプトのデバッグが難しくなる。
Perl5では、以下のような機能が用意されている。
・宣言されていない変数などを文法エラーにする use strict; プラグマ
変数名のタイプミスを検出できる
・未定義値に対する演算などに警告を出す use warnings; プラグマ
変数の初期値設定忘れを防ぐ。ハッシュキーの打ち間違いが見つかることも。
・ブロック内でのみ使用できるローカル変数の宣言 my
変数名の重複による誤動作等を防ぎ、変数の局所化によって見通しが良くなる
・ファイルハンドルにもmy変数を使える
Perl4ではグローバル変数としてしか扱えなかったファイルハンドルを局所化
できる。スクリプト内でファイルハンドルが重複することによる誤動作を防ぐ。
上記を踏まえて修正したスクリプトは以下になります:
sub count_up {
my($countcsv, $page) = @_;
use Fcntl;
sysopen(my $fh, $countcsv, O_CREAT|O_RDWR) or error(" countcsv をopen出来ません");
flock($fh, 2);
seek($fh, 0, 0);
my $data = '';
while(my $line = <$fh>) {
chomp $line;
my($seq, $acc) = split /,/, $line;
if($page == $seq) { $acc++; }
$data .= "$seq,$acc\n";
}
seek($fh, 0, 0);
print $fh $data;
truncate($fh, tell($fh));
close($fh);
}
count_up($countcsv, $page);
この回答への補足
アドバイスありがとうございます。
丁寧な回答に感謝いたします。
まだ内容を全て理解できていないところがございますが実践してみます。
確認後お礼をいれます。
お礼が遅れました。
最初は正常に動作しませんでしたが、やっと動作するようになりました。
ありがとうございます。
また基本的な考え方についての間違い指摘にも感謝いたします。
No.1
- 回答日時:
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) pythonのこのエラーがわかりません 3 2022/11/16 14:54
- その他(プログラミング・Web制作) pandasでまとめてインデックスを削除するにはどうすればいいですか? たとえば、以下のプログラムで 1 2022/07/31 23:09
- その他(プログラミング・Web制作) ColabでのPytorchのエラー 1 2022/11/19 20:51
- C言語・C++・C# pythonのファイルの並びでの読み込みとリストについて 4 2022/04/13 03:52
- Ruby パイソンでテキストファイルが読み込めない 1 2022/11/14 16:42
- その他(プログラミング・Web制作) Python - Excel で Webからデータを連続取得したいのですが エラーが出ます 1 2023/07/06 20:08
- その他(プログラミング・Web制作) python 気象データの取得 2 2023/06/20 23:54
- その他(プログラミング・Web制作) atcoder python コードへの助言 2 2022/08/12 15:31
- その他(プログラミング・Web制作) python 3.10で 同じlistに同じ構文で同じデータ代入した結果が異なる現象発生 7 2022/06/18 11:08
- Ruby 教えてください 2 2023/01/04 17:50
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBAでCSVファイルの特定行を書...
-
MATLAB グローバル変数の宣言
-
openした後、closeしないでプロ...
-
ExcelをCSV書き出す場合のシー...
-
perl で googleAPIを呼び出す...
-
Perl Vlookupみたいに
-
VBAでCSVファイルを途中行まで...
-
CSVが可変長の場合の検索方法
-
cgiで表示するhtmlページ内でバ...
-
perlで容量の大きいCSVファイル...
-
alarmのタイムアウト後の処理で...
-
JavaでCSVファイルを高速に読む...
-
エクセルVBA コードが同じでも...
-
ReadLineでの読み出し行を指定する
-
VBAで巨大なファイルの途中から...
-
ADOによるCSVファイルからのデ...
-
Perlでファイルの列を削除する。
-
Perlで特定行から特定行までを...
-
バッチファイルの作り方(CSV→...
-
C言語で特定の行を抽出する方法...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBAでCSVファイルの特定行を書...
-
ExcelをCSV書き出す場合のシー...
-
VBAでCSVファイルを途中行まで...
-
VBAで巨大なファイルの途中から...
-
openした後、closeしないでプロ...
-
エクセルVBA コードが同じでも...
-
ReadLineでの読み出し行を指定する
-
JavaでCSVファイルを高速に読む...
-
perlで、後ろの行を読んで、前...
-
Perlの変数に文字数制限(容量...
-
エクセルVBAでCSVファイ...
-
perlにて2つのファイル比較
-
MATLAB グローバル変数の宣言
-
C#でCSVファイルを逐一更新したい
-
CSVが可変長の場合の検索方法
-
他のサーバーにあるファイルの...
-
動画像から静止画を取り出すには
-
perlで容量の大きいCSVファイル...
-
外部サーバーにあるファイルを...
-
1ファイルずつ読み込みたい
おすすめ情報