回答編集履歴
7
NoRewindIteratorは内側じゃないとダメっぽい
answer
CHANGED
|
@@ -16,13 +16,15 @@
|
|
|
16
16
|
$file->setFlags(File::READ_CSV | File::DROP_NEW_LINE); // CSVモード (但し空行読み飛ばしモードは使えない)
|
|
17
17
|
$file->setCsvControl("\t"); // セパレータをタブ文字に
|
|
18
18
|
|
|
19
|
+
// Rewindされないようにラップする
|
|
20
|
+
$it = new NoRewindIterator($file);
|
|
19
21
|
// 空行を読み飛ばすようにラップする
|
|
20
|
-
$it = new CallbackFilterIterator($
|
|
22
|
+
$it = new CallbackFilterIterator($it, function ($row) { return $row !== [null]; });
|
|
21
23
|
// $pオフセットから$e件に制限するようにラップする
|
|
22
24
|
$it = new LimitIterator($it, $p, $e);
|
|
23
25
|
|
|
24
|
-
//
|
|
26
|
+
// 配列に変換
|
|
25
|
-
$records = iterator_to_array(
|
|
27
|
+
$records = iterator_to_array($it);
|
|
26
28
|
|
|
27
29
|
?>
|
|
28
30
|
<!DOCTYPE html>
|
6
もうちょいシンプルに
answer
CHANGED
|
@@ -18,13 +18,11 @@
|
|
|
18
18
|
|
|
19
19
|
// 空行を読み飛ばすようにラップする
|
|
20
20
|
$it = new CallbackFilterIterator($file, function ($row) { return $row !== [null]; });
|
|
21
|
-
// rewindさせないようにラップする
|
|
22
|
-
$it = new NoRewindIterator($it);
|
|
23
21
|
// $pオフセットから$e件に制限するようにラップする
|
|
24
22
|
$it = new LimitIterator($it, $p, $e);
|
|
25
23
|
|
|
26
|
-
// 配列に変換
|
|
24
|
+
// rewindを防ぎながら配列に変換
|
|
27
|
-
$records = iterator_to_array($it);
|
|
25
|
+
$records = iterator_to_array(new NoRewindIterator($it));
|
|
28
26
|
|
|
29
27
|
?>
|
|
30
28
|
<!DOCTYPE html>
|
5
バグ修正 \(File::READ_AHEADおよびFile::SKIP_EMPTYはHTTP URLに対しては使えない模様\)
answer
CHANGED
|
@@ -13,15 +13,19 @@
|
|
|
13
13
|
|
|
14
14
|
// SplFileObjectでURLをオープンする
|
|
15
15
|
$file = new File('http://example.com/ttt.txt', 'rb');
|
|
16
|
-
$file->setFlags(File::READ_CSV | File::
|
|
16
|
+
$file->setFlags(File::READ_CSV | File::DROP_NEW_LINE); // CSVモード (但し空行読み飛ばしモードは使えない)
|
|
17
17
|
$file->setCsvControl("\t"); // セパレータをタブ文字に
|
|
18
18
|
|
|
19
|
-
// SplFileObjectはイテレータでもあるが,iterator_to_array適用時に
|
|
20
|
-
// rewind処理が発生してしまうのでNoRewindIteratorでラップする。
|
|
21
|
-
// 更に,必要な部分だけを効率的に残せるLimitIteratorでラップする。
|
|
22
|
-
//
|
|
19
|
+
// 空行を読み飛ばすようにラップする
|
|
20
|
+
$it = new CallbackFilterIterator($file, function ($row) { return $row !== [null]; });
|
|
21
|
+
// rewindさせないようにラップする
|
|
22
|
+
$it = new NoRewindIterator($it);
|
|
23
|
+
// $pオフセットから$e件に制限するようにラップする
|
|
23
|
-
$
|
|
24
|
+
$it = new LimitIterator($it, $p, $e);
|
|
24
25
|
|
|
26
|
+
// 配列に変換
|
|
27
|
+
$records = iterator_to_array($it);
|
|
28
|
+
|
|
25
29
|
?>
|
|
26
30
|
<!DOCTYPE html>
|
|
27
31
|
|
4
蛇足
answer
CHANGED
|
@@ -55,4 +55,6 @@
|
|
|
55
55
|
- [ob_start](http://php.net/manual/ja/function.ob-start.php)を使って出力HTMLのバッファリングを行っている
|
|
56
56
|
- エラーや例外が発生したときには正常系で使うHTMLのバッファを破棄してエラー用のHTMLに切り替える処理を書いている
|
|
57
57
|
|
|
58
|
-
上記を満たす場合,一時的な配列を生成する必要すらありません。イテレータのまま
|
|
58
|
+
上記を満たす場合,一時的な配列を生成する必要すらありません。イテレータのまま`foreach`で回してもらって構いません。ただし条件を満たしていないのにやってしまうと,`foreach`ループ中に通信障害が発生したときにHTMLが中途半端な状態でぶっ壊れて出力されてしまうので注意。
|
|
59
|
+
|
|
60
|
+
一度配列を作る意味としては,「一度作ってしまえば配列は絶対に壊れることが無い」と保証できるからですね。HTTP経由でURLをオープンしているイテレータは不安定なことを意識しなければなりません。
|
3
蛇足
answer
CHANGED
|
@@ -48,4 +48,11 @@
|
|
|
48
48
|
<li><?=($i+1)."\t".implode("\t", array_map('htmlspecialchars', $record))?></li>
|
|
49
49
|
<?php endforeach; ?>
|
|
50
50
|
</ul>
|
|
51
|
-
```
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
蛇足ですが,
|
|
54
|
+
|
|
55
|
+
- [ob_start](http://php.net/manual/ja/function.ob-start.php)を使って出力HTMLのバッファリングを行っている
|
|
56
|
+
- エラーや例外が発生したときには正常系で使うHTMLのバッファを破棄してエラー用のHTMLに切り替える処理を書いている
|
|
57
|
+
|
|
58
|
+
上記を満たす場合,一時的な配列を生成する必要すらありません。イテレータのままそのまま`foreach`で回してもらって構いません。(条件を満たしていないのにやってしまうと,`foreach`ループ中に通信障害が発生したときにHTMLが中途半端な状態でぶっ壊れて出力されてしまうので注意)
|
2
LimitIterator使ったほうがよさそう
answer
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
[
|
|
1
|
+
[NoRewindIterator](http://php.net/manual/ja/class.norewinditerator.php) なんてあったんですね,勉強になりました。不可逆なストリームを扱う際には必須ですね。
|
|
2
2
|
|
|
3
|
+
あと調べていたら[LimitIterator](http://php.net/manual/ja/class.limititerator.php)なるものもあるようです!一度全部配列に変換してから切り取るよりも,部分的にイテレータの段階で読み捨てを行ったほうがメモリ効率が圧倒的にいいので是非こちらで。
|
|
4
|
+
|
|
3
5
|
```php
|
|
4
6
|
<?php
|
|
5
7
|
|
|
@@ -14,9 +16,11 @@
|
|
|
14
16
|
$file->setFlags(File::READ_CSV | File::SKIP_EMPTY | File::READ_AHEAD | File::DROP_NEW_LINE); // CSVモード
|
|
15
17
|
$file->setCsvControl("\t"); // セパレータをタブ文字に
|
|
16
18
|
|
|
17
|
-
// イテレータ
|
|
19
|
+
// SplFileObjectはイテレータでもあるが,iterator_to_array適用時に
|
|
18
|
-
//
|
|
20
|
+
// rewind処理が発生してしまうのでNoRewindIteratorでラップする。
|
|
21
|
+
// 更に,必要な部分だけを効率的に残せるLimitIteratorでラップする。
|
|
22
|
+
// 最後に配列に変換する。
|
|
19
|
-
$records =
|
|
23
|
+
$records = iterator_to_array(new LimitIterator(new NoRewindIterator($file), $p, $e));
|
|
20
24
|
|
|
21
25
|
?>
|
|
22
26
|
<!DOCTYPE html>
|
1
シングルクオート派
answer
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
$e = filter_input(INPUT_GET, 'e');
|
|
11
11
|
|
|
12
12
|
// SplFileObjectでURLをオープンする
|
|
13
|
-
$file = new File(
|
|
13
|
+
$file = new File('http://example.com/ttt.txt', 'rb');
|
|
14
14
|
$file->setFlags(File::READ_CSV | File::SKIP_EMPTY | File::READ_AHEAD | File::DROP_NEW_LINE); // CSVモード
|
|
15
15
|
$file->setCsvControl("\t"); // セパレータをタブ文字に
|
|
16
16
|
|