分割されたファイルは次のようになります。
addressbooktokyo000.xml
addressbooktokyo001.xml
addressbooktokyo002.xml
addressbooktokyo003.xml
・・・
addressbooktokyo050.xml
初回のファイルのみにヘッダ(開始から</header>まで)があります。末尾のファイルのみにフッタ(</body></myaddress>)があります。
作業の流れ
1. 000ファイルを開いて、ヘッダをどこかに保存する
2. 001ファイルを開いて、開始から最初の</person>までを削除しつつ、変数に読み込んで、000の末尾に追加する
3. 000の末尾にフッタ(</body></myaddress>)を追加して、保存して閉じる
4. 001の開始部分にヘッダを挿入する
5. 002ファイルを開いて、開始から最初の</person>までを削除しつつ、変数に読み込んで、001の末尾に追加する
3. 001の末尾にフッタ(</body></myaddress>)を追加して、保存して閉じる
以下ループ
最後. 最後のファイルのみ、フッタはつけずに保存して閉じる
以上です。
以前に、次のURLで質問をしたのですが、対象のXMLファイルがあまりにも大きすぎたので、ファイル分割ツールで指定したサイズにぶった切ってから、あとで整合性をとるやり方に切り替えたいと思います(分割ツールは速いんです)。
http://q.hatena.ne.jp/1355133738
いろいろ考えてみましたが、なかなか納得できる結果ではなかったので参考出品です。
100M のファイルを 10M に分割するのは数十秒でしたが 数Gのファイルを処理する時間は未確認ですので、前回のスクリプトと大差ないようでしたら(&ほかに回答なければ)、質問をキャンセルください。
PHP は使用可能ということなので、PHP での実装です。
なお、分割したファイルを処理するのではなく、直接分割する例です。
下記を適当な名前(divFile.php)等で処理するファイルがあるフォルダに保存し、
コマンドラインで php.exe のフルパスに引数でスクリプトを指定し実行してみてください。
下記はCドライブの Program Files 下に PHPがインストールされている実行例です。
C:\>"C:\Program Files\PHP\php.exe" divFile.php
<?php // 引数は処理するファイル名 DivideFile( 'sample.xml' ); //--------------------------------------------------------------------- function DivideFile( $filePath ) //--------------------------------------------------------------------- { // 処理用データ //------------------------ $headerKeyword = "<body>"; // ヘッダ部分の最終キーワード $footerKeyword = "</body>"; // フッダ部分の先頭キーワード $recordKeyword = "</person>"; // 分割内の最終キーワード $fileSize = 10 * 1024 * 1024; // 分割サイズ ex) 10MB // 読込ファイルのオープン //------------------------ $rfp = fopen( $filePath, "rb" ); // ヘッダの切り出し //------------------------ $readData = fread( $rfp, $fileSize ); $spos = strpos( $readData, $headerKeyword ); if( $spos === false ) { echo "分割サイズ内に".$headerKeyword."がありません。"; return; } while( ord($readData[$spos]) != 13 ) { $spos++; } if( ord($readData[$spos+1]) == 10 ) { $spos++; } $header = substr($readData, 0, $spos + 1); // フッダの切り出し //------------------------ fseek( $rfp, $fileSize * (-1), SEEK_END ); $readData = fread( $rfp, $fileSize ); $epos = strrpos( $readData, $footerKeyword ); if( $epos === false ) { echo "分割サイズ内に".$footerKeyword."がありません。"; return; } while( ord($readData[$epos]) != 13 && ord($readData[$epos]) != 10 ) { $epos--; } $footer = substr($readData, $epos + 1 ); // サイズの整合 //------------------------ $fileSize -= strlen( $header ); $fileSize -= strlen( $footer ); // 分割処理 //------------------------ fseek( $rfp, $spos + 2, SEEK_SET ); $restBuffer = ""; $fileIndex = 1; while( !feof( $rfp ) ){ $readBuffer = fread( $rfp, $fileSize ); if ( $readBuffer === false ) { echo "ファイルの読み込みに失敗しました。\n"; return; } $readBuffer = $restBuffer.$readBuffer; if( ( $pos = strrpos( $readBuffer, $recordKeyword ) ) === false ) { echo "検索文字が見つかりませんでした。\n"; return; } if ( strpos( $readBuffer, "\n", $pos ) === false ){ $pos = strrpos( $readBuffer, $recordKeyword, $pos - strlen($readBuffer) - 1 ); } while( ord($readBuffer[$pos]) != 13 && $pos < strlen($readBuffer) ) { $pos++; } if( ord($readBuffer[$pos+1]) == 10 ) { $pos++; } // 出力ファイル名 echo "--->". $fileIndex." 番目のファイルを書き出しています\n"; $wFile = sprintf( 'sample_%03d.xml',$fileIndex ); $wfp = fopen( $wFile, "wb" ); fwrite( $wfp, $header ); fwrite( $wfp, substr($readBuffer, 0, $pos + 1) ); fwrite( $wfp, $footer ); fclose( $wfp ); $restBuffer = substr( $readBuffer, $pos ); $fileIndex++; } } ?>