while等で9万行目以降まで空回しさせれば、9万行目以降からデータ読み込みさせることは可能ですが、

このような場合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]);
・・・
}
}

回答の条件
  • 1人3回まで
  • 13歳以上
  • 登録:2010/05/24 14:16:26
  • 終了:2010/05/31 14:20:03

ベストアンサー

id:koriki-kozou No.4

koriki-kozou回答回数480ベストアンサー獲得回数792010/05/25 14:21:16

ポイント30pt

可変長の場合、空送り処理が必要になるのは、実はどの言語を用いていても同じ

問題は、言語の処理速度

コンパイルしてしまう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などの数値(セクタサイズの倍数で、よく使われる数値)を入れておくと良い

id:sandbox69

とても参考になります!!!

ありがとうございます!!!

2010/05/26 01:03:25

その他の回答(3件)

id:y-kawaz No.1

y-kawaz回答回数1421ベストアンサー獲得回数2262010/05/24 14:22:24

ポイント30pt

事前処理で、例えば1ファイル1000行で複数ファイルに分割しておくとかでは駄目でしょうか?

9万30行目から読みたければ 91.csv を開いて最初の29行をスキップする、といった感じで。

id:sandbox69

10万行のCSVファイルを例えば1000行ないし1万行に分割するのに、

PHP上で制御できましたっけ???

仮に出来るとした場合、その処理の方が重くなったりはしませんか???

そうでないようであれば、ファイル分割のための関数などをご教示いただけないでしょうか?

2010/05/24 18:46:10
id:Bombastus No.2

ホーエンハイム回答回数409ベストアンサー獲得回数522010/05/24 16:09:00

ポイント30pt

読み込むべきCSVファイルが変化しないものであれば、事前に各行の位置(fseek関数で移動する位置。ファイル先頭からのバイト数)を記録した固定長インデックスファイル(1行につき12桁固定で十分でしょう)を作っておき、それを参照させるといいでしょう。

id:sandbox69

>読み込むべきCSVファイルが変化しないものであれば

CSVファイルは変化しません。

念のため確認ですが、インデックスファイルを作成するのに、

事前に10万行はループさせる必要があるということにはなりませんか???

となると、その処理にかかる負荷がどの程度になるのかにもよりますよね?

サンプルソースなどをご提示いただくことは可能でしょうか???

2010/05/24 18:52:36
id:hanako393 No.3

hanako393回答回数1142ベストアンサー獲得回数872010/05/24 20:44:04

>このような場合9万行まで空回しが発生し、空回ししている時間だけ処理時間が多くかかってしまいます

本当にどれだけ時間がかかってるか計測済みですか?

感覚論で、処理時間がかかるといってるわけではないでしょか?

実際には大して時間はかかってませんよ。

CSVファイルのまま、何の小細工もしないで9行目から読むことはできません。

ファイルを分割して持つとかインデックスをもつとかするしかありません。

回答1、回答2に否定的で、CSVファイルはそのままの状態でというのなら

9万行空まわししかないです。実際にはそれほど時間はかかってません。

>CSVファイルを指定行から読み込ませたいのですが

CSVファイルで何万行も管理するのは無謀なんです。

DBで管理してDBから読み書きしてください。

DBが使えないのなら、現状のままでいくしかありません。

id:sandbox69

> 本当にどれだけ時間がかかってるか計測済みですか?

> 感覚論で、処理時間がかかるといってるわけではないでしょか?

> 実際には大して時間はかかってませんよ。

データの仕様上、カラムが30近く、あるカラムのデータはテキストベースで最大800文字程度。

計測済みの上での質問であり、より高速化させたいというのが願いです。

>CSVファイルのまま、何の小細工もしないで9行目から読むことはできません。

>ファイルを分割して持つとかインデックスをもつとかするしかありません。

そうなんですね、ありがとうございます。

>CSVファイルで何万行も管理するのは無謀なんです。

>DBで管理してDBから読み書きしてください。

CSVを読み込んでDBに登録させるという処理上のことです。

DB登録後は、SQL文のlimit等で制御している処理時間に問題はありません。

2010/05/25 00:31:11
id:koriki-kozou No.4

koriki-kozou回答回数480ベストアンサー獲得回数792010/05/25 14:21:16ここでベストアンサー

ポイント30pt

可変長の場合、空送り処理が必要になるのは、実はどの言語を用いていても同じ

問題は、言語の処理速度

コンパイルしてしまう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などの数値(セクタサイズの倍数で、よく使われる数値)を入れておくと良い

id:sandbox69

とても参考になります!!!

ありがとうございます!!!

2010/05/26 01:03:25
  • id:sandbox69
    質問要素が一点抜けていました。
    PHPの話題です。失礼いたしました。
  • id:b-wind
    「行」を単位とする限り、固定長フォーマットでもなければ特定行の位置指定は困難なわけで
    単純な方法では無理だろうねぇ。
  • id:sandbox69
    >b-wind
    >「行」を単位とする限り、固定長フォーマットでもなければ特定行の位置指定は困難なわけで
    >単純な方法では無理だろうねぇ。
    やはりそうですかぁ。ご回答ありがとうございます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません