
行数が30万件ほどあるCSVから、PHP経由でMysqlにデータを投入しようとしています。
2000件ごとにファイルを分割し、再度各ファイルを読み込みなおして、insertしようと考えました。
ところが、ファイル分割で2000件ごとに区切った場合、最後の2000件に満たない端数分をファイルに落とす方法がわかりません。
どなたか教えていただけないでしょうか。
※かなり冗長な書き方をしているかと思いますので、改善点等あればご指摘いただければ幸いです。
以下サンプルコード------------------------------------------------------
$count = "0";
$max = "2000"; //ファイルあたりの行数
$file_count = "0"; //ファイル名につける連番
$RF = fopen( "base_file.csv", "r") or die("ファイルが開けません");
while (($data = fgetcsv($RF)) !== false) {
if($count < $max){
//順番を入れ替えたり、データをいじるかもしれないのでsprintf
$lines.= sprintf("%s,%s,%s,%s,%s,%s,%s\n",
$data[0],
$data[1],
$data[2],
str_replace(" "," ",$data[3]), //全角スペースを半角に変換
$data[4],
$data[5],
$data[6]
);
}
if($count == $max){
//ファイル名生成
$fileno = zerofill($file_count);
$filename = "./files/datafile_".$fileno.".dat";
$WF = fopen($filename, "w");
fputs($WF, $lines);
fclose($WF);
//書き込みデータを空にする
$lines = "";
$file_count++;
$count = "0";
}
$count++;
}
fclose($RF);
//ファイル名の連番を0で埋める
function zerofill($val){
if($val < 100){
if($val < 10){
$ret = "0".$val;
}
$ret = "00".$val;
}
return $ret;
}
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);
No.5
- 回答日時:
おっと、下のwhile抜け後のcountチェックはif($count > 0){です、すいません。
忘れてましたが1つ目のファイルが1行少なくなるのを防ぐには
if($i > 0){}の中にcount++;を移動してください。
これで「$lineに追加されている行数」という意味合いになります。
No.3
- 回答日時:
本題についてはNo.1、No.2さんが回答して下さっているので、
ちょっとしたアドバイスを。
zerofillという関数を自作されていますが、
通常の0フィルの処理であれば、PHPの組み込み関数で実現可能です。
$fileno = zerofill($file_count);
↓
$fileno = sprintf("%04d", $file_count);
これで4桁未満の値の場合は、上位の桁を0で埋めてくれます。
ご参考までに。
No.2
- 回答日時:
先ほど1で回答したものですが
whileループ内で[$count == $max]となるのは一回前の処理が2000件目だったとき(ループの最後でインクリメントしているため)になります。
そのため2001件目のデータがファイルには保存されないことになってしまいます。
またループに入った際はちょうど2000件出力が行われた場合でもcountは必ず1以上になってしまいます。
そのためループ内の最初でcountをインクリメントする(今処理しているデータはファイルに書き込むn件目という意味合いにする)といいと思います。
また、最初のif($count < $max)は不要($maxに到達した時点で0クリアされるのだから条件は必ず満たす)です。
ありがとうございます。いただいたアドバイスを元に書き直しました。
サンプルデータの数を減らしてテストをしてみました。
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);
No.1
- 回答日時:
whileループ内でcountがmaxに到達しないうちにループを抜ける条件($dataが取得できない)になってしまうための問題です。
whileループを抜けた後にcountが0より大きかったらループ内のif($count == $max)でやっている処理を行うようにしたらどうでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP PHPでCookieを使った訪問回数について 1 2023/05/28 14:10
- その他(プログラミング・Web制作) Fortranでの出力ファイル 2 2023/03/21 21:25
- その他(プログラミング・Web制作) データ解析ソフトRでのファイル入力read.csvがエラーになります 7 2022/03/27 22:11
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- C言語・C++・C# pythonのファイルの並びでの読み込みとリストについて 4 2022/04/13 03:52
- その他(プログラミング・Web制作) pythonのこのエラーがわかりません 3 2022/11/16 14:54
- その他(プログラミング・Web制作) ColabでのPytorchのエラー 1 2022/11/19 20:51
- PHP PHP ページング データベース 1 2022/06/16 10:30
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- Visual Basic(VBA) VBAのユーザーフォームのテキストボックスに入力制限をしたい 6 2022/11/15 08:28
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
自動で番号を振りたい
-
Resource id #3 と表示されま...
-
C言語でCSVファイルの行数を読...
-
CSVデータを使ったページングと...
-
エラーメッセージ(無効な間接...
-
curlをPHPで書く方法
-
stdClass Objectを連想配列のよ...
-
配列一致(要素順番は違うが内容...
-
配列をループでたくさん宣言し...
-
PHPでテキストファイルを読み込...
-
読み(あ行~わ行)ごとに分け...
-
$_SESSIONに二次元配列を使える...
-
プルダウンメニューにDBの内容...
-
配列の添え字が小数だとどうなる?
-
配列を回すとき、最後の要素だ...
-
Smartyについて
-
cakephpでのトランザクション処...
-
2つの連想配列を比較して一致す...
-
sortableで並べ替えてDBに保...
-
PHPの配列の中の要素の日付でソ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
【PHP】csvファイルへの書き出...
-
C言語でCSVファイルの行数を読...
-
csvの内容を行単位で削除したい
-
Resource id #3 と表示されま...
-
別ファイルの構造体の値を読み...
-
While文を使って配列の中身を全...
-
複数行のデータのPOST処理に関して
-
CSVでアップロードしたデータの...
-
PHPでCSVの一部の行を編集したい
-
自動で番号を振りたい
-
CSVファイルの最終行のデー...
-
PHPで、CSVファイルを、指定し...
-
stdClass Objectを連想配列のよ...
-
PHP5でCSVの指定行データだけを...
-
ブログのトラックバックについて
-
PHPで外部ファイルを読み込むと...
-
◆速い、ファイル読み込みは?
-
バイナリファイルの内容を、そ...
-
行数が30万件ほどあるCSVから、...
-
PHP 別ドメインへのファイル保存法
おすすめ情報