splice()の使い方について教えて下さい

このQ&Aのポイント
  • フリーのcgiカウンターにアクセス解析を追加したい場合、splice()を使用することでログを管理できます。
  • splice()は配列を変更するための関数で、指定した位置から指定された要素数分の要素を削除し、別の要素を挿入することができます。
  • しかし、splice()の使用方法については注意が必要で、削除された要素は別の変数で保持しておく必要があります。また、要素の削除や挿入によって配列のインデックスが変わるため、注意が必要です。
回答を見る
  • ベストアンサー

splice()の使い方について教えて下さい

ホームページのカウンターで、アクセス解析をしたくてフリーのcgiカウンターに手を加えました。 そして、新しいログが、ファイルの先頭に来るよう下記のようにしました。 $tmp ="\nカウント : \[ $pcount \]\n日  時 : \[ $time \]\nホ ス ト : \[ $host \]\n\n"; open(DATA,"+<$logfile2") || &error; @array = <DATA>; @arr = splice(@array, 2030); unshift @array, $tmp; seek(DATA,0,0); print DATA @array; close(DATA); 以前、こちらのサイトで『新しいデータをファイルの先頭から表示させる方法』について質問させていただきました。 そして、unshift と seek を使った方法を教えていただきました。 ただ、データが多くなるとこの方法では、データが多くなると処理に時間がかかると教えて頂いた為、私は、ログが約90件を超えたら古いデータを消そうと思い、このようにしました。 しかし、『@arr = splice(@array, 2030);』この部分が良くないようで、データの一部が残ってしまうのです。 splice()の使い方について詳しく教えて下さい。 よろしくお願い致します。

  • CGI
  • 回答数2
  • ありがとう数1

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

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

> spliceは、splice(対象配列、削除の開始位置)ではないのでしょうか? splice は 1~4個の引数を取ります。 2個の場合はその通りですね。 で、配列の中身は期待通りになっているけれども、ファイルはそうじゃないのでは? ということです。 つまり、ファイルポインタを先頭までまき戻して、そこから配列の内容を書き出しましたが、 ファイルのサイズは変わっていないので、仮に元のファイルのサイズが 書き出したサイズより大きければゴミが後ろにくっつくことになります。 で、そのサイズの調整をするのが truncateです。 spliceと同じく組み込み関数ですので、調べてみてください。

kyonmimi2006
質問者

お礼

sakusaker7さん、ありがとうございました。 seek(DATA,0,0); truncate(DATA,70000); print DATA @array; close(DATA); としたら、うまくいきました。 始めは、truncateの部分とprint部分を逆に書いていましたが、 それではうまくいかず、上記のようにしたところうまくいきました。 どうもありがとうございました。

その他の回答 (1)

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

90件を超えた分を消すというのと、spliceで指定している 2030という数字の関係がわかりません。 この2030の意味はなんですか? openした後の処理を見ると多分2030行ということなんでしょうけど。 あるいはファイルに書き出してからcloseする前に truncateを実行しとくとか。

kyonmimi2006
質問者

補足

sakusaker7さん、すみません。 90件ではなく、290件分でした。 $tmpに入れてあるデータが上記よりもう少しあり、7行分あるため、 2030としたのですが、2031行目以上のデータが、一部(一部の行の後半部分)が残っているのです。 spliceは、splice(対象配列、削除の開始位置)ではないのでしょうか? truncateを実行とは? ご指導、よろしくお願いします。

関連するQ&A

  • array_searchを使って外部ファイルから目的のキーを取得したい

    array_searchを使って外部ファイルから目的のキーを取得したいのですが どうしてもFALSEを返されてしまいます。 以下が構文です。 <?php $file = file_get_contents("arr.php"); $arr =explode("\n",$file); $delstr="DEF"; $hoge = in_array($delstr,$arr,1); if($hoge !== false){ array_splice($arr,$hoge,1); } var_dump($hoge); print_r($arr); ?> 3日くらい悩んでいます。 どうかご教授よろしくお願い致します。

    • 締切済み
    • PHP
  • ログファイルの記録数

    # ログ更新 unshift(@new,"$num<>$addr\n"); open(OUT,">$logfile") || &error("Write Error: $logfile"); print OUT @new; close(OUT); 上記ログの書込みに、最大保存数を設定したいのですが、どのようにすればいいのでしょうか。 $max = 3; とした場合、3行超えたら古いファイルを消したいと考えています。よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • ファイルの先頭に追加書込みする方法について教えて下さい

    今まで、単にファイルの最後にデータを追加するように 下記のように書いていた部分を open(OUT,">>$logfile2") || &error; print OUT "カウント : \[ $pcount \]\n日  時 : \[ $time \]\n"; close(OUT); ファイルの先頭に追加していくようにしたいのですが、うまくいきません。 ミスティーネット・Perl・CGI講座というサイトを参考に下記のようにしてみました。 open(DATA,"+<$logfile2") || &error; seek(DATA,0,0); print DATA "\nカウント : \[ $pcount \]\n日  時 : \[ $time \]\n"; close(DATA); このように書くと追加書込みではなく、書き換えになってしまいます。 また、+<の部分を>>にすると変更前と同様、ファイルの最後に追加されてしまいます。 どこがどういけないのか判る方がみえましたら教えて下さい。 よろしくお願いいたします。

    • ベストアンサー
    • CGI
  • ログファイルへの書き込みがうまくいきません

    ------------------------------------------ open(LOG,"+<$filename") || die "Error!\n"; @logs=<LOG>; flock(LOG,2); unshift(@logs,"$array[0],$array[1],$array[2],$array[3],$array[4]\n"); print LOG @logs; flock(LOG,8); close(LOG); ------------------------------------------ この$array[0]~$array[4]にはそれぞれ、「<option value="1">1</option>」の様な、プルダウンメニューの「1~10」までの数字が入っています。 この数字を$filenameへ書き込みたいのですが、中々うまくいかずに困っています。 ちなみに、一応書き込めるには書き込めるのですが、$filenameを開くと、 ------------------------ 1,1,1,1,1 6,4,1,9,6 1,1,1,1,1 9,1,2,4,4 1,1,1,1,1 3,0,1,9,5 1,1,1,1,1 ------------------------ このような形になってしまいます。何がいけないのでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl
  • PHPに関する質問です。

    PHPに関する質問です。 データベースからfetchしたデータを 10件づつとりだしグループ化して、最後の残りが8件以下の場合は、各グループの配列の先頭に加えるという処理を行う際に、このような記述をしているのですが、 $data = array(); // 保存する配列 $ct1 = 0; $ct2 = 0; while($row = $res->fetch(PDO::FETCH_NUM)) { if ($ct2 === 10) { $ct1++; $ct2 = 0; } if ($ct2 === 0) { $data[$ct1] = array(); } $data[$ct1][] = $row; $ct2++; } if (count($data[$ct1]) < 8) { $arr = array_pop($data); $x = floor(count($arr) / count($data)); // 各要素に割り当てる数 for ($i = 0; $i < count($data); $i++) { for ($j = 0; $j < $x; $j++) { array_push($data[$i], array_pop($arr)); } } $t = 0; while (count($arr) > 0) { // 最後のあまりを先頭に追加 array_push($data[$t], array_pop($arr)); $t++; } } この処理だと、生成された配列が3次元になってしまいます。 Array ( [0] => Array ( [0] => Array ( [0] => あ ) [1] => Array ( [0] => あ) [2] => Array ( [0] => あ) [3] => Array ( [0] => あ) [4] => Array ( [0] => あ) [5] => Array ( [0] => あ ) [6] => Array ( [0] => あ ) [7] => Array ( [0] => あ) [8] => Array ( [0] => あ ) [9] => Array ( [0] => あ ) [10] => Array ( [0] => あ) ) [1] => Array ( [0] => Array ( [0] => あ) [1] => Array ( [0] => あ) [2] => Array ( [0] =>あ ) [3] => Array ( [0] => あ ) [4] => Array ( [0] => あ ) [5] => Array ( [0] => あ ) [6] => Array ( [0] => あ) [7] => Array ( [0] => あ ) [8] => Array ( [0] => あ ) [9] => Array ( [0] => あ ) [10] => Array ( [0] => あ ) ) [2] => Array ( [0] => Array ( [0] => あ ) [1] => Array ( [0] => あ) [2] => Array ( [0] => あ ) [3] => Array ( [0] => あ ) [4] => Array ( [0] => あ) [5] => Array ( [0] => あ ) [6] => Array ( [0] => あ ) [7] => Array ( [0] => あ ) [8] => Array ( [0] => あ ) [9] => Array ( [0] => あ) [10] => Array ( [0] => あ ) ) [3] => Array ( [0] => Array ( [0] => あ ) [1] => Array ( [0] => あ ) [2] => Array ( [0] => あ ) [3] => Array ( [0] => あ ) [4] => Array ( [0] => あ ) [5] => Array ( [0] => あ) [6] => Array ( [0] => あ ) [7] => Array ( [0] => あ ) [8] => Array ( [0] => あ ) [9] => Array ( [0] => あ) ) ) これを array([0]=>array(あ,あ,あ,あ,あ,あ,あ)[1]=>array(あ,あ,あ,あ,あ,あ,あ)) のように2次元で取り出すには、どのように行えばいいでしょうか。 この後の処理としては、 $key = 'a'; array_search($key,$data) のようにキーを取得したいと考えています。 宜しくお願いします。

    • 締切済み
    • PHP
  • Perl 先頭行に追加

    恐れ入ります。 Perlで、配列がカンマで区切られたデータを読み込み、 その先頭行にデータを挿入したいのですが、 中々うまくいきません。 データ(/data/xxx.txt)の中身は、 test,test2 bbb,bbb2 ccc,ccc2 という感じで、カンマで区切られて改行で並んでいます。 そこに新たに$dateと$contで受けたデータを先頭行に追加する感じです。 open(FILE,"<./data/xxx.txt"); while($temp = <FILE>){ @temp=split(/,/,$temp); push(@ddr,"$temp[0]","$temp[1]"); } seek(@ddr,0,0); unshift(@ddr,($date,$cont."\n")); open(FILE,">./data/xxx.txt"); $new=join(",",@ddr); print FILE $new; close(FILE); このように書いていますが、 print FILE @ddr とすると、配列が壊れた状態(全て繋がる)で先頭行には挿入されたのですが、カンマで区切って配列にして並べようとしたら、 test,test2 ,bbb,bbb2, ,,ccc,ccc2,, という感じで上手く並びません。 よろしくおねがいします。

    • ベストアンサー
    • Perl
  • PHPの勉強として掲示板を作成しているのですが、謎の二重書き込みに出会

    PHPの勉強として掲示板を作成しているのですが、謎の二重書き込みに出会い躓いています。 下記はテストとして書いた、状況が再現されるソースです。 <?php $filename = './test.dat'; if($_REQUEST) { $data = file($filename); $newdata = "{$_REQUEST['newdata']}\n"; $logfile = @fopen($filename, "r+"); flock($logfile, LOCK_EX); foreach($data as $value) { fputs($logfile, $value); } fputs($logfile, $newdata); flock($logfile, LOCK_UN); fclose($logfile); } ?> <html> <head><title>TEST</title></head> <body> <form action="test.php"> <input type="text" name="newdata"> <input type="submit"> </form> </body> </html> 5、6行目で $newdata = "{$_REQUEST['newdata']}\n"; $data[] = $newdata; とした場合、DATを逆順にして $newdata = $_REQUEST['newdata']; $array_unshift = $newdata; とした場合、また、そこで追加せずに書き込み処理を $logfile = @fopen($filename, "r+"); while(!feof($logfile)) { $data[] = fgets($logfile); } fputs($logfile,$newdata); foreach($data as $value) { fputs($logfile, $value); } とした場合、など…どうやってもなぜか同じ症状が出ます。 しかももっと不思議なのは、どこでおかしくなっているのか調べようと思い途中にprint_r($data)を入れると、場所によってはなぜか二重書き込みが起きなかったりするのです。 検索しても同じ状況は見つけられずどうしたものかと悩んでおります。 情報が足りないかもしれませんが、何か気づいた方がいましたら教えてください。よろしくお願いします。

    • ベストアンサー
    • PHP
  • flockのタイミング

    掲示板のスクリプトを作っています。 ログは1行ごとに1記事分のデータが格納されているので、書き込み処理の場合は、 $lines = file("./log.dat"); としていったん配列にログを読み込み、 array_unshift($lines, $new_data); 等して、新しい記事のデータを配列の先頭に追加し、 $fp = fopen("./log.dat", "wb"); foreach ($lines as $line) { fputs($fp, $_); } fclose($fp); として、最終的にログに書き込みます。 Perlを扱っているときは(複数更新すべきログファイルがあったので)、別途ロックファイルを作ってそれに対してflockをかけるという方法を行っていましたが、今回はログファイルが1つであるのでそのログファイル自体にflockをかけようと思っています。 しかし、fileで最初にopenしているため、ファイルポインタが取得できず、flockをかけるタイミングは、本当の書き込み作業の部分(fopen)からかけるしかなさそうなのですが、これは危険ではないでしょうか? それと、マニュアルに、 注意: flock()は、ファイルポインタを必要とするため、 (fopen()へ引数"w"または"w+"を指定して)書き込 みモードでオープンすることにより丸めるファイルにアクセス保護する 特別なロックファイルを使用する必要があるかもしれません。 とかいてありますが、この意味がいまいちわからず、困惑しています。

    • ベストアンサー
    • PHP
  • 改行コードの変換と削除

    改行コード変換メソッドで$dataには配列形式のデータが入ります。 public function v_line($val, $arr = false) { $line = ''; if(is_array($val)){ return array_map(array($this, 'v_line'), $val); } return str_replace(array("\r", "\n"), $line, $val); } //メソッド実行 $this->v_line($data); この結果全ての改行コードが削除されます。これを特定のキーのみ削除ではなく"\n"に 統一させるように変換したいのですがどのようにすればできますでしょうか? //改行コード削除しないキー配列 $arr = array('comment01', 'comment02'); //$arrのキーのみ改行コードを変換しその他は改行コード削除 $this->v_line($data, $arr);

    • ベストアンサー
    • PHP
  • SPOOLのログについて

    sysユーザで入るスクリプトを作成しているのですが、そこで、ログ出力の設定をしようと考えています。 spool ログファイル名 だけだと、ログファイルは上書きされてしまうようですが、追加書きにできないでしょうか? スクリプトの頭の部分は以下のようになっています。 -------------------- setenv DAY `date '+%Y%m'` setenv LOGFILE /tmp/test_${DAY}.log sqlplus -s /nolog << EOF connect /as sysdba spool $LOGFILE --------------------- なお、毎日cronで実行し、結果を月ごとにまとめたいと考えています。 何か、いい方法があれば教えてください。

専門家に質問してみよう