- ベストアンサー
1行目と2行目の間にデータを書き出すには・・・。
私はプログラマではないのですが、会社でPHPプログラムの修正を頼まれてしまいました。 ■現在のプログラム ----------------------------------- $fp = fopen( $CSVFileName, "a+" ); $a = fseek($fp,0,SEEK_END); $ret = fputs( $fp, $CSV_SJIS); fclose($fp); ----------------------------------- 現在は、以上のような方法で新しいデータを追加しているのですが、これをデータファイルの2行目に追加するように変更して欲しいと言われています。 なぜ、そのような要求が出たかというと、データファイルというのがCSV形式のファイルで、1行目にはExcelで処理するための列名(項目名)が入っています。よって2行目に新しいデータを追加したいのです。 どなたか詳しい方がいらっしゃいましたら、回答をお願い致します。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
# 考え方の問題だけですが、、、 私なら安全性を考えて、 1) $CSVFileNameを読み取りモードで開く 2) 作業用ファイルを書き込みモードで開く 3) $CSVFileNameから1行目を読み込み作業用ファイルへ書き込む 4) 作業用ファイルへ2行目を書き込む 5) $CSVFileNameから2行目以降を読み込み作業用ファイルへ書き込む 6) $CSVFileName、作業用ファイルをクローズする 7) $CSVFileNameを適当な名前にリネーム、 8) 作業用ファイルを$CSVFileNameへリネーム とします。 これなら正しく処理が行われなければ6)の直後にexitすれば、過去の正しいデータが残るので、ファイルの中身がデタラメ or 空っぽといった事態には対処可能です。 # どのくらいミッションクリティカルなのかにもよりますが、、、
その他の回答 (2)
- duckling
- ベストアンサー率47% (88/185)
PHPではピンポイントで行を追加することは出来ないので、 「2行目に新しいデータを追加した状態の情報」を 新しくファイルに上書きする、という方法しかありません。 保存する時にどうこうする、というよりも、 「そのまま保存してもOKな変数を作成する」、ということですね。 ------------------------------------------- 名前,メール,色 aaa,aaa@aa.jp,青 bbb,bbb@bb.jp,赤 ------------------------------------------- ↑上の古い情報に、下の新しい情報を「上書きする」 ------------------------------------------- 名前,メール,色 ccc,ccc@cc.jp,黄色 aaa,aaa.aa.jp,青 bbb,bbb@bb.jp,赤 ------------------------------------------- ↑つまりは、これを作成する。 $myfile = file("ファイルネーム"); でファイルを開くと、内容が $myfile(配列) に格納されるので、 for などを使って2行目に新しい情報を追加し、 それを、ファイルに上書きする、という方法です。 これだと、作業用ファイルも要りません。 変数の2行目に、うまいこと新しい情報を叩き込むことが出来たら、 後はそれを保存すればいいだけですから。 (注意: 配列をそのまま保存しても「Array」という文字列になるだけなので 配列を分解してただの文字列(変数)に結合してしまいましょう。
お礼
ducklingさん、解答ありがとうございます。お返事が遅れてしまい申し訳ありません。 > $myfile = file("ファイルネーム"); > でファイルを開くと、内容が $myfile(配列) に格納されるので、 > for などを使って2行目に新しい情報を追加し、 > それを、ファイルに上書きする、という方法です。 なるほど。この方法なら私でも何とかなるかもしれません。 > 配列をそのまま保存しても「Array」という文字列になるだけなので・・・ これは配列をファイルに書き出す場合のことでしょうか。「配列を分解してただの文字列(変数)に結合」の部分を、もう少し詳しく説明していただけると助かります。 お時間に余裕のある時で構いませんので、もう少しだけアドバイスをお願いいたします。m(__)m
- Mizyu
- ベストアンサー率41% (245/593)
fseek($fp,0,SEEK_END); で、書き出す場所を選んでいるわけです。 二番目に0がありますよね。これは0バイト目の位置から始まっているわけです。 なので、本来なら 最初の行である場所、(0から改行コードのある場所)までを抽出して そこへファイルポインタを持っていって(これがfseekですね) そこから書く、という仕様にすると思うのですが 一行目が何バイトと決まっているのであれば、その数値を0のところにいれてやればよいです。 一行目が50バイトだとしたら fseek($fp,50,SEEK_END); とすれば二行目からの書き足しになるはずです。
お礼
早速のご回答ありがとうございます。 > 0から改行コードのある場所までを抽出して・・・そこから書く 各レコードのバイト数は決まっていないので、この方法を採ることになると思います。 もしご迷惑でなければ、fseekを使った具体的な処理方法を教えてください。よろしくお願いいたします。
お礼
早速のご回答ありがとうございます。 なるほど、確かに安全な方法ですね。私の知識で対応できるか判りませんが、ちょっと試してみます。 また解らないことが出てきた場合には、ここで質問させてください。宜しくお願いいたします。
補足
度々すみません。 何とか、教えて頂いた方法で会社の要求に応えることが出来ました。本当にありがとうございます。 ただ・・・一点だけ気になることが。なぜか 7)部分で思ったとおりの処理をしてくれません。$CSVFileNameをenq.bakとリネームしたいのですが、実際には元のファイルが削除されてしまいます。しかし8)の処理は正常に処理されています。 ■私が書いたソース ------------------------------------------------- $fp = fopen( $CSVFileName, "r" ); $new_fp = fopen( $TMP_FileName, "w" ); $buffer = fgets( $fp, 4096 ); $ret = fputs( $new_fp, $buffer ); if( !$fp ) { # エラー画面を出力後、処理終了 $message = "<b>CSVファイル出力エラー</b>"; $message .= "<br>"; ErrorForm1( $message ); exit; } //CSVに書込対象のものをSJISに変換する $CSV_SJIS = i18n_convert( $CSV, "SJIS", "EUC-JP" ); $ret = fputs( $new_fp, $CSV_SJIS ); while ( !feof( $fp ) ) { $buffer = fgets( $fp, 4096 ); $ret = fputs( $new_fp, $buffer ); } fclose( $new_fp ); fclose( $fp ); //$CSVFileNameをenq.bakにリネーム if( !rename( "$CSVFileName", "enq.bak" ) ){ # エラー画面を出力後、処理終了 $message = "<b>ファイル( $CSVFileName -> enq.bak )のリネームエラー</b>"; $message .= "<br>"; ErrorForm1( $message ); exit; } //$TMP_FileNameを$CSVFileNameにリネーム if( !rename( "$TMP_FileName", "$CSVFileName" ) ){ # エラー画面を出力後、処理終了 $message = "<b>ファイル( $TMP_FileName -> $CSVFileName )のリネームエラー</b>"; $message .= "<br>"; ErrorForm1( $message ); exit; } ------------------------------------------------- 原因は何でしょうか・・・。なぜ7)のリネーム処理だけが実行されていないのか、もし間違いがあれば指摘して頂けませんか?宜しくお願いいたします。