応用
巨大なCSVファイルからデータを取り出しDBに保存する処理を、分割で処理にするのに役立つ。色はにほへど 散りぬるを 我が世たれぞ 常ならむ 有為の奥山 今日越えて 浅き夢見じ 酔ひもせず
<?php $txtFn='test3.txt'; $txtFn = mb_convert_encoding ( $txtFn, 'SJIS', 'UTF-8' );//全角ファイル名に対応 echo "<table border='1'><thead><tr><th>offset</th><th>行テキスト</th></tr></thead><tbody>"; if ($fp = fopen ( $txtFn, "r" )) { fseek($fp, 54);//54バイト目から読み込む $data = array (); while ( false !== ($line = fgets ( $fp )) ) { $offset=ftell($fp); echo "<tr><td>{$offset}</td><td>{$line}</td></tr>"; } } fclose ( $fp ); echo '</tbody></table>'; ?>
offset | 行テキスト |
---|---|
67 | 常ならむ |
83 | 有為の奥山 |
99 | 今日越えて |
115 | 浅き夢見じ |
130 | 酔ひもせず |
<?php
$mem1 = memory_get_usage();
$fn = "big.csv";
$fsize = filesize ($fn);
echo "ファイルサイズ:{$fsize}<br>";
$end_flg = false;
$offset = 0;
$str_size_total = 0;
for($x_i=0;$x_i<1000000;$x_i++){
if ($fp = fopen ( $fn, "r" )) {
fseek( $fp, $offset );
for($i=0;$i<1000;$i++){
$line = fgets ($fp);
if($line == false){
$end_flg=true;
break;
}
$str_size_total += strlen($line);
//echo $line . '<br>';
}
$offset = ftell($fp);
fclose($fp);
}
$mem2 = memory_get_usage() - $mem1;
echo "----------{$x_i} {$mem2}<br>";
if($end_flg == true){
echo '終了しました。<br>';
break;
}
}
echo "文字サイズ合計:{$str_size_total}";
?>
出力
ファイルサイズ:54349576 ----------0 648 ----------1 520 ----------2 584 ----------3 520 ----------4 584 ----------5 200 ----------6 584 ----------7 584 ----------8 456 ----------9 584 ----------10 520 ----------11 520 ----------12 456 ----------13 520 ----------14 456 ----------15 520 ----------16 520 ----------17 520 ----------18 520 ----------19 520 ----------20 584 ----------21 584 ----------22 584 ----------23 520 ----------24 520 ----------25 584 ~ 省略 ~ ----------165 616 ----------166 552 ----------167 488 ----------168 616 ----------169 552 ----------170 232 終了しました。 文字サイズ合計:54349576
<?php
// 最大20行までのテキストを出力する
$fn = "test.txt";
if ($fp = fopen ( $fn, "r" )) {
for($i=0;$i<20;$i++){
$line = fgets ($fp);
if($line == false) break; // ファイル内テキストが末尾に達したら処理抜け
echo $line . '<br>';
}
}
fclose ( $fp );
?>
Warning: POST Content-Length of 16698999 bytes exceeds the limit of 8388608 bytes in Unknown on line 0
POSTデータの容量を増やすphp.iniの設定
php.iniをテキストエディタで開き、「post_max_size」の値を増やせばよい。post_max_size=8M
post_max_size=80M
色はにほへど 散りぬるを 我が世たれぞ 常ならむ 有為の奥山 今日越えて 浅き夢見じ 酔ひもせず
<?php $txtFn='test3.txt'; $txtFn = mb_convert_encoding ( $txtFn, 'SJIS', 'UTF-8' );//全角ファイル名に対応 echo '<pre>'; if ($fp = fopen ( $txtFn, "r" )) { fseek($fp, 54);//54バイト目から読み込む $line = fgets ( $fp ); echo $line; $offset=ftell($fp); echo '→次のオフセット:'.$offset; } fclose ( $fp ); echo '</pre>'; ?>
常ならむ →次のオフセット:67
/**
* テキストファイルの先頭行文字列を取得する
* @param string $fn テキストファイルパス
* @return string 先頭行文字列
*/
private function getHeadsFromTextfile($fn){
$head_str = '';
if ($fp = fopen ( $fn, "r" )) {
$head_str = fgets ($fp);
}
fclose ( $fp );
$head_str = $this->deleteBom($head_str); // UTF8ファイルのテキストに付いているBOMを除去する
return $head_str;
}
/**
* UTF8ファイルのテキストに付いているBOMを除去する
* @param string $str UTF8ファイルから取得したテキストの文字列
* @return string BOMを除去した文字列
*/
private function deleteBom($str){
if (($str == NULL) || (mb_strlen($str) == 0)) {
return $str;
}
if (ord($str{0}) == 0xef && ord($str{1}) == 0xbb && ord($str{2}) == 0xbf) {
$str = substr($str, 3);
}
return $str;
}
$wave_dash1 = '〜'; // 波ダッシュ → 文字参照は「 〜」 $tilde1=preg_replace("/\xE3\x80\x9C/", "\xEF\xBD\x9E", $wave_dash1); echo $wave_dash1.' → '.$tilde1;
〜 → ~
サンプル
$first_date='2015-1-1'; $end_date = date('Y-m-d'); $month_range=4; $format='Y-m-d H:i:s'; $res = splitByMonthRange($first_date,$end_date,$month_range,$format); echo var_dump($res); /** * 期間を指定月間で分割 * * 期間は開始日と終了日で指定する。 * 開始日に月末日を指定すると月がずれて分割されてしまう。 * なので、開始日や終了日はなるべく第一日(月の初日)を指定する。 * * @param string/date $first_date 期間の開始日(月の第一日) * @param string/date $end_date 期間の終了日 * @param int $month_range 指定月間 * @param string $format 返りデータの日付フォーマット(省略可、秒単位まで指定可) * @return array 分割日付リスト */ function splitByMonthRange($first_date,$end_date,$month_range,$format='Y-m-d'){ $start = new DateTime($first_date); $end = new DateTime($end_date); $interval = DateInterval::createFromDateString($month_range.' month'); $period = new DatePeriod($start,$interval,$end); $dates = array(); foreach($period as $d){ $dates[] = $d->format($format); } return $dates; }
出力
array (size=5) 0 => string '2015-01-01 00:00:00' (length=19) 1 => string '2015-05-01 00:00:00' (length=19) 2 => string '2015-09-01 00:00:00' (length=19) 3 => string '2016-01-01 00:00:00' (length=19) 4 => string '2016-05-01 00:00:00' (length=19)サンプル
;メモリ上限 memory_limit = 500M ;POST最大サイズ post_max_size = 500M ;アップロード最大サイズ upload_max_filesize = 500M
$text = "シャムネコ\nやぎ\rハイイロオオカミ\r\nライオンタマリン"; $ary =preg_split( "/\R/", $text ); echo var_dump($ary);
array( (int) 0 => 'シャムネコ', (int) 1 => 'やぎ', (int) 2 => 'ハイイロオオカミ', (int) 3 => 'ライオンタマリン' )
注意
Ajaxで送られてきた日本語文字列に対して「/\R/」で分割するとバグが起こる。
<?php
$str = "い\nろ \r\nは\rにほ\r\n";
echo json_encode($str) . '<br>';
$str1 = alignLineFeedCodes($str);
$str2 = alignLineFeedCodes($str,"\r\n");
$str3 = alignLineFeedCodes($str,"\r");
echo json_encode($str1) . '<br>';
echo json_encode($str2) . '<br>';
echo json_encode($str3) . '<br>';
/**
* 改行コードを統一する
* @param string $str 改行コードを含む文字列
* @param string $code 統一する改行コード
* @return string 改行コードを統一した文字列
*/
function alignLineFeedCodes($str,$code="\n"){
return preg_replace("/\r\n|\r|\n/", $code, $str);
}
?>
$list=array("カラス","","スズメ","ムクドリ"); $list = array_filter($list, "strlen");// 空白行を除去(indexの降り直しは行われない) $list = array_values($list);// インデックスの振り直し echo var_dump($list);
array (size=3) 0 => string 'カラス' (length=9) 1 => string 'スズメ' (length=9) 2 => string 'ムクドリ' (length=12)
/** * 緯度経度を度分秒表記(60進数)から10進数に変換 * @param string or array $p 60進数緯度経度 * - 例 * - 26,40,32.73 * - 26度40分32.73秒 * - 26°40’32.73” * - 26,40'32.73" * - N26,40'32.73" * - array(26,40,32.73) * @return 10進数緯度経度 */ function latlon60to10($p){ $res = null; if(is_array($p)){ $ary = $p; }else{ if(!is_numeric(mb_substr($p ,0 ,1))){ $p = mb_substr($p ,1 ); } $ary = preg_split("/,|度|分|秒|°|’|”|'|\"/",$p); if(count($ary) < 3){ return null; } } $res = $ary[0] + $ary[1]/60 + $ary[2]/3600; return $res; }
検証
60進数表記 | 10進数表記 |
---|---|
26,40,32.73 | 26.675758333333 |
26度40分32.73秒 | 26.675758333333 |
26°40’32.73” | 26.675758333333 |
N26,40'32.73" | 26.675758333333 |
array (size=3) 0 => int 26 1 => int 40 2 => float 32.73 | 26.675758333333 |