• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:行数が30万件ほどあるCSVから、PHP経由でMysqlにデータを投入)

行数が30万件ほどあるCSVから、PHP経由でMysqlにデータを投入

このQ&Aのポイント
  • 行数が30万件ほどあるCSVから、PHP経由でMysqlにデータを投入しようとしています。
  • 2000件ごとにファイルを分割し、再度各ファイルを読み込みなおして、insertしようと考えました。
  • ファイル分割で2000件ごとに区切った場合、最後の2000件に満たない端数分をファイルに落とす方法がわかりません。

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

  • ベストアンサー
  • duron
  • ベストアンサー率77% (73/94)
回答No.4

1で書いたようにwhileを抜けた後にcountをチェックしてください。 $countが0より大きいということはファイルに書き出されていないデータがあるということです。 ファイルポインタの位置を調べて~云々のことをすればループ内で出力できると思いますが まぁそこはあまり考えないようにしました。 以下修正(間違ってた箇所があったらゴメンネ)--------------------------------------- define("READ_FILE", "./csv/base_file.csv"); $i = "0"; //総行数カウンター $count = "0"; //処理件数カウンター $max = "50"; //ファイルあたりの行数 $file_count = "0"; //ファイル名につける連番 $line=""; //←コレを忘れないように $RF = fopen( READ_FILE, "r") or die("ファイルが開けません\n"); while (($data = fgetcsv($RF)) !== false) { $count++; //1行目はフィールド名だったのをすっかり忘れていたので追加 //2行目から処理 if($i > 0){ //フィールドのデータをいろいろいじるのでsprintf $lines.= sprintf("%s,%s\n", $data[0], $data[1] ); } if($count == $max){ //ファイル名生成 $fileno = sprintf("%03d",$file_count); $filename = "./files/datafile_".$fileno.".dat"; $WF = fopen($filename, "w"); fputs($WF, $lines); fclose($WF); //書き込みデータを空にする $lines = ""; $file_count++; $count = "0"; } $i++; } if($count == $max){ //←ココでチェックです //ファイル名生成 $fileno = sprintf("%03d",$file_count); $filename = "./files/datafile_".$fileno.".dat"; $WF = fopen($filename, "w"); fputs($WF, $lines); fclose($WF); } fclose($RF);

すると、全ての回答が全文表示されます。

その他の回答 (4)

  • duron
  • ベストアンサー率77% (73/94)
回答No.5

おっと、下のwhile抜け後のcountチェックはif($count > 0){です、すいません。 忘れてましたが1つ目のファイルが1行少なくなるのを防ぐには if($i > 0){}の中にcount++;を移動してください。 これで「$lineに追加されている行数」という意味合いになります。

すると、全ての回答が全文表示されます。
  • smileeeen
  • ベストアンサー率70% (21/30)
回答No.3

本題についてはNo.1、No.2さんが回答して下さっているので、 ちょっとしたアドバイスを。 zerofillという関数を自作されていますが、 通常の0フィルの処理であれば、PHPの組み込み関数で実現可能です。 $fileno = zerofill($file_count);  ↓ $fileno = sprintf("%04d", $file_count); これで4桁未満の値の場合は、上位の桁を0で埋めてくれます。 ご参考までに。

yasagure-kun
質問者

お礼

ありがとうございます。

すると、全ての回答が全文表示されます。
  • duron
  • ベストアンサー率77% (73/94)
回答No.2

先ほど1で回答したものですが whileループ内で[$count == $max]となるのは一回前の処理が2000件目だったとき(ループの最後でインクリメントしているため)になります。 そのため2001件目のデータがファイルには保存されないことになってしまいます。 またループに入った際はちょうど2000件出力が行われた場合でもcountは必ず1以上になってしまいます。 そのためループ内の最初でcountをインクリメントする(今処理しているデータはファイルに書き込むn件目という意味合いにする)といいと思います。 また、最初のif($count < $max)は不要($maxに到達した時点で0クリアされるのだから条件は必ず満たす)です。

yasagure-kun
質問者

お礼

ありがとうございます。いただいたアドバイスを元に書き直しました。 サンプルデータの数を減らしてテストをしてみました。 base_file.csv:153行分のテキストファイル また、すっかり忘れていましたが、1行目はフィールド名なので、必要データは2行目からと なります。 $count加算の直後に、2行目以上の判定を追加しています。 今回の趣旨とは異なりますが、この場合1つ目のファイルだけは49行なんですよね。 どうしたらいいかわかりませんでしたが、とりあえずデータに抜けはなかったのでよしとします。 ただ、[$count == $max]では、1行目~100行目までしかファイル書き出しができず、 残りの53行分を判定処理する方法がわかりません。 $countが$maxに達したかの判定の次に、残りの分をどうにかする処理を入れるのかと思いますが、 どうしたらいいのでしょうか。 以下サンプルコード--------------------------------------- define("READ_FILE", "./csv/base_file.csv"); $i = "0"; //総行数カウンター $count = "0"; //処理件数カウンター $max = "50"; //ファイルあたりの行数 $file_count = "0"; //ファイル名につける連番 $RF = fopen( READ_FILE, "r") or die("ファイルが開けません\n"); while (($data = fgetcsv($RF)) !== false) { $count++; //1行目はフィールド名だったのをすっかり忘れていたので追加 //2行目から処理 if($i > 0){ //フィールドのデータをいろいろいじるのでsprintf $lines.= sprintf("%s,%s\n", $data[0], $data[1] ); } if($count == $max){ //ファイル名生成 $fileno = sprintf("%03d",$file_count); $filename = "./files/datafile_".$fileno.".dat"; $WF = fopen($filename, "w"); fputs($WF, $lines); fclose($WF); //書き込みデータを空にする $lines = ""; $file_count++; $count = "0"; } //ここでもう一度判定? $i++; } fclose($RF);

すると、全ての回答が全文表示されます。
  • duron
  • ベストアンサー率77% (73/94)
回答No.1

whileループ内でcountがmaxに到達しないうちにループを抜ける条件($dataが取得できない)になってしまうための問題です。 whileループを抜けた後にcountが0より大きかったらループ内のif($count == $max)でやっている処理を行うようにしたらどうでしょうか?

すると、全ての回答が全文表示されます。

関連するQ&A