このような場合9万行まで空回しが発生し、空回ししている時間だけ処理時間が多くかかってしまいます。
どうにか空回しさせずに、CSVファイルを指定行から読み込ませたいのですが、
ご存じの方法などあれば、教えてください。
system関数とかを利用する場合の例なども詳しく教えて頂けますと、助かります。
【現在のコード】※簡素化のため、一部改変・省略済み
$csvfile = fopen('test.csv','r');
$offset = 90000;
while(($data = fgetcsv($csvfile,0,',')) !== FALSE){
$count = $count + 1;
if($count => $offset ){
echo($data[0]);
echo($data[1]);
echo($data[3]);
・・・
}
}
可変長の場合、空送り処理が必要になるのは、実はどの言語を用いていても同じ
問題は、言語の処理速度
コンパイルしてしまうCやJAVAを用いればより早く処理できる
phpはループを重ねれば重ねるほどメモリを喰らい続けるため、さらに事態は悪化する
CやJAVAが無理であればperl(pythonはcsvの取り扱いに少し癖がある)などを使うことを考えたほうがいいかもしれない
サーバにデータを送る前の段階や送る最中にファイルを分割しておくことも考えたほうがいいかもしれない
具体的にどうすべきかについてはさておき、今回の質問に直で答えるとすれば例えば下記のような具合
(テストデータはExcelで作成したものを利用しているため9万行というようなデータを吐き出せるシステムで作成したcsvファイルでも対応できるかは未確認。特に改行コードについては注意が必要)
<?php $filename = './test.csv'; $offset = 3; $path = realpath($filename);// php から見たパスとshellから見たパスは違うため $offsetByte = shell_exec('head -n ' . ($offset - 1) . ' ' . $path . ' | wc -c');// 読み飛ばすデータサイズ取得 $csvfile = fopen($filename, 'r'); fseek($csvfile, $offsetByte); // 読み飛ばす while(($data = fgetcsv($csvfile, 8192, ',')) !== FALSE){ echo($data[0]); echo($data[1]); echo($data[3]); } ?>
fgetcsv の第二引数が 0 の場合の処理と数値を指定した場合では内部処理が異なる
1024,2048,4096,8192などの数値(セクタサイズの倍数で、よく使われる数値)を入れておくと良い
事前処理で、例えば1ファイル1000行で複数ファイルに分割しておくとかでは駄目でしょうか?
9万30行目から読みたければ 91.csv を開いて最初の29行をスキップする、といった感じで。
10万行のCSVファイルを例えば1000行ないし1万行に分割するのに、
PHP上で制御できましたっけ???
仮に出来るとした場合、その処理の方が重くなったりはしませんか???
そうでないようであれば、ファイル分割のための関数などをご教示いただけないでしょうか?
読み込むべきCSVファイルが変化しないものであれば、事前に各行の位置(fseek関数で移動する位置。ファイル先頭からのバイト数)を記録した固定長インデックスファイル(1行につき12桁固定で十分でしょう)を作っておき、それを参照させるといいでしょう。
>読み込むべきCSVファイルが変化しないものであれば
CSVファイルは変化しません。
念のため確認ですが、インデックスファイルを作成するのに、
事前に10万行はループさせる必要があるということにはなりませんか???
となると、その処理にかかる負荷がどの程度になるのかにもよりますよね?
サンプルソースなどをご提示いただくことは可能でしょうか???
>このような場合9万行まで空回しが発生し、空回ししている時間だけ処理時間が多くかかってしまいます
本当にどれだけ時間がかかってるか計測済みですか?
感覚論で、処理時間がかかるといってるわけではないでしょか?
実際には大して時間はかかってませんよ。
CSVファイルのまま、何の小細工もしないで9行目から読むことはできません。
ファイルを分割して持つとかインデックスをもつとかするしかありません。
回答1、回答2に否定的で、CSVファイルはそのままの状態でというのなら
9万行空まわししかないです。実際にはそれほど時間はかかってません。
>CSVファイルを指定行から読み込ませたいのですが
CSVファイルで何万行も管理するのは無謀なんです。
DBで管理してDBから読み書きしてください。
DBが使えないのなら、現状のままでいくしかありません。
> 本当にどれだけ時間がかかってるか計測済みですか?
> 感覚論で、処理時間がかかるといってるわけではないでしょか?
> 実際には大して時間はかかってませんよ。
データの仕様上、カラムが30近く、あるカラムのデータはテキストベースで最大800文字程度。
計測済みの上での質問であり、より高速化させたいというのが願いです。
>CSVファイルのまま、何の小細工もしないで9行目から読むことはできません。
>ファイルを分割して持つとかインデックスをもつとかするしかありません。
そうなんですね、ありがとうございます。
>CSVファイルで何万行も管理するのは無謀なんです。
>DBで管理してDBから読み書きしてください。
CSVを読み込んでDBに登録させるという処理上のことです。
DB登録後は、SQL文のlimit等で制御している処理時間に問題はありません。
可変長の場合、空送り処理が必要になるのは、実はどの言語を用いていても同じ
問題は、言語の処理速度
コンパイルしてしまうCやJAVAを用いればより早く処理できる
phpはループを重ねれば重ねるほどメモリを喰らい続けるため、さらに事態は悪化する
CやJAVAが無理であればperl(pythonはcsvの取り扱いに少し癖がある)などを使うことを考えたほうがいいかもしれない
サーバにデータを送る前の段階や送る最中にファイルを分割しておくことも考えたほうがいいかもしれない
具体的にどうすべきかについてはさておき、今回の質問に直で答えるとすれば例えば下記のような具合
(テストデータはExcelで作成したものを利用しているため9万行というようなデータを吐き出せるシステムで作成したcsvファイルでも対応できるかは未確認。特に改行コードについては注意が必要)
<?php $filename = './test.csv'; $offset = 3; $path = realpath($filename);// php から見たパスとshellから見たパスは違うため $offsetByte = shell_exec('head -n ' . ($offset - 1) . ' ' . $path . ' | wc -c');// 読み飛ばすデータサイズ取得 $csvfile = fopen($filename, 'r'); fseek($csvfile, $offsetByte); // 読み飛ばす while(($data = fgetcsv($csvfile, 8192, ',')) !== FALSE){ echo($data[0]); echo($data[1]); echo($data[3]); } ?>
fgetcsv の第二引数が 0 の場合の処理と数値を指定した場合では内部処理が異なる
1024,2048,4096,8192などの数値(セクタサイズの倍数で、よく使われる数値)を入れておくと良い
とても参考になります!!!
ありがとうございます!!!
とても参考になります!!!
ありがとうございます!!!