- 締切済み
PHPでCSVファイルを編集したい
PHPを触りだして間もない者です。 PHPでCSVファイルを編集したいのですが、上手くいきません。 CSVファイルの中身は{商品番号,名前,住所,年齢}が数行入力されています。 具体的にはPHPで引数の商品番号を基にCSVファイルで編集する行数を決定して、その行の一部項目を変更したいのですが、良い方法はありますでしょうか?
- みんなの回答 (1)
- 専門家の回答
みんなの回答
- asciiz
- ベストアンサー率70% (6803/9674)
CSVファイルというのは、データベースファイルとしてとても扱いにくいものです。 レコード長が一定ではないため、「○○行目」に一気にアクセスできません。 ファイルの頭から一行ずつ読んで内容をチェックしつつ、該当行を見つけたら、新データを書き込む必要があります。 その後、ファイルの残りの部分をすべて読んで、結合します。 そういう作業を、データ1行更新するたびにやらなければいけません。 1レコード更新するたびに、CSVファイルほぼ全体のコピーが発生する。 これは、データベースファイルをCSVとしたときの大きな欠点といえます。 さらにそこに、Webアプリでは、「同じプログラムが、同時にいくつも起動される」ということが起こりうるのです。 ごくわずかな瞬間、ほぼ同時に、違う場所のデータ更新があったとします。 セッション1が、ファイルを頭から読み、更新場所を見つけます。 セッション2が、ファイルを頭から読み、別の更新場所を見つけます。 セッション1がデータ更新します。 セッション2がデータ更新します。 セッション1がファイルの残りの部分を書き出します。 セッション2がファイルの残りの部分を書き出します。 …その結果、データファイルは壊れます。 これを防ぐには、まず、一番最初のセッションが起動されたときに、「ファイルロック」を行い、「他のセッションはいじるな!」という宣言をします。 2番目以降に起動されたプログラムは、まずファイルロックのチェックをし、ロックされていたならば、しばらく待ちます。 セッション1は、処理を完了させて、ファイルロックを解除します。 待っていたセッション2が再度ファイルロックのチェックをし、ロック解除されていたならば、今度は自分がファイルロックして、処理を開始します。 処理を終えたら、ファイルロックを解除します。 これで少しは安全にCSVデータベースの更新ができます。 (それでもなんかのタイミングで壊れたりするんですが) CSVファイルよりも効率のいいデータベース形式があります。 「固定長レコード」です。 1レコードは1KB、と設計し、1KBの中で先頭から何バイト目までは○○のデータ、続いて何バイトは△△のデータ、というような設計を行います。 これならば、11件目にアクセスするならば、ファイルポインタを10KB位置に移動するだけですぐにデータを読み出すことができ、データファイル更新も10KB位置から1KBだけ上書きすれば、更新できることになります。 でも、「○○行目」ではなく「○○というデータ」を見つけたいならば、やはりファイルの頭から該当データを見つけるまで読み進めなければなりません。 固定長レコードの問題はもちろん、項目長をあらかじめ予測しなければいけないことと、データを保持していない部分もファイルサイズになってしまうこと。 1件20バイト前後のデータであっても、1レコード1KBで100件あれば、データベースサイズは100KBとなってしまいます。 そして万が一、1レコードが1KBに収まらなくなった場合には、1レコード長を大きくした新しいデータベースファイルに全件変換しなければなりません。 そしてそれを扱うプログラムも、全てフィールド位置を正確に更新しなければなりません。更新漏れ等があれば、データベースファイルは、壊れます。 そして結局、そういうことを効率的にやってくれるのが、MySQLやPostgreSQLなどの「データベースミドルウェア」になってくるんですね。 データベース作成やデータ更新などをSQL命令で行うことで、データベースファイルの完全性やファイルロック(レコードロック)を自動的にし、安全に更新してくれる。 さらにデータベースにインデックスをつければ、プログラムの方はまったく変えていないのに、「○○というデータ」というデータを探すのが高速になる。 何かデータ管理ことを行おうとすると、ナントカSQLというのがすぐに出てくるのも当然なのです…。 ---- しかしまあ、CSVでやってみたいのならそういうプログラムを組んでみてもいいでしょう。 (1)ファイルロックのチェック (2)ロックされていたらしばらく待ち、(1)に戻る (3)元CSVファイルオープン(Read) (4)更新用CSVファイルオープン(Write) (5)while 1行読んでEOFでないならば (6) (6)条件チェック、 (6-1)該当しないならそのまま更新用CSVファイルに書き込み (6-2)該当したら新データを更新用CSVファイルに書き込み (7)元CSV・更新用CSVファイルをクローズ (8)元CSVをバックアップファイル名にリネーム (9)更新用CSVファイルを元CSVファイル名にリネーム (10)ファイルロック解除 こんな感じになるでしょうか。 PHPプログラムがクライアントサイドだとすると、1レコード更新するたびにインターネットを通してCSVデータを丸々読んで、CSVデータを丸々書いて、ということになりますから、だいぶ効率の悪いことになりそうです。 サーバーサイドPHPでデータ更新するならば、データファイルはローカルにあるので多少マシになります。 私の知識もちょっと古いのでそんな泥臭いことになりますが、CSVでしたいならやはりそうなるかと…。