Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】PharData::seek()メソッドの使い方

seekメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

seekメソッドは、PharDataアーカイブ内の現在選択されているエントリのファイルポインタを移動させるメソッドです。このメソッドは、PharDataクラスに属しており、圧縮されていないtarやzip形式などのアーカイブファイルを扱う際に、ファイル内の読み込み位置を細かく制御するために利用されます。

ファイルポインタとは、ファイル内で次にデータを読み込む、または書き込む位置を示すもので、seekメソッドを使うことで、このポインタを任意の位置に動かすことができます。具体的には、第一引数であるoffsetで移動させるバイト数を指定し、第二引数であるwhenceで移動の基準点を指定します。whenceには、ファイルの先頭からの相対位置(SEEK_SET)、現在のファイルポインタからの相対位置(SEEK_CUR)、またはファイルの末尾からの相対位置(SEEK_END)のいずれかを指定することが可能です。

この機能は、特に大きなアーカイブファイルから特定のデータを読み取る場合や、一度読み込んだデータの一部を再読み込みしたい場合などに非常に有効です。seekメソッドは、ファイルポインタの移動に成功するとtrueを返し、失敗した場合にはfalseを返します。これにより、開発者はアーカイブ内のデータを柔軟かつ効率的に操作することが可能になります。

構文(syntax)

1<?php
2
3class PharData
4{
5    public function seek(int $offset, int $whence = SEEK_SET): bool
6    {
7    }
8}

引数(parameters)

int $offset, int $whence = SEEK_SET

  • int $offset: 移動させたいバイト数を指定します。
  • int $whence = SEEK_SET: ファイルポインタの基準位置を指定します。SEEK_SET (0) はファイルの先頭、SEEK_CUR (1) は現在の位置、SEEK_END (2) はファイルの末尾を基準とします。

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PharData::seekでアーカイブ内を移動する

1<?php
2
3/**
4 * PharData::seek メソッドの使用例
5 *
6 * このスクリプトは、PharDataアーカイブを作成し、その中のファイルエントリに対して
7 * seek メソッドを使用して読み取り位置を操作する方法を示します。
8 * システムエンジニアを目指す初心者が、アーカイブ内の特定の場所から
9 * データを読み出す「シーク可能なストリーム」の概念を理解するのに役立ちます。
10 */
11
12// 一時的なPharDataアーカイブファイル名と、アーカイブ内のファイル名
13$pharFileName = 'my_sample_archive.tar';
14$filePathInsideArchive = 'document.txt';
15$fileContent = "This is the first sentence.\nThis is the second sentence, which is quite a bit longer than the first one.\nFinally, this is the third sentence.";
16
17try {
18    // 1. 新しいPharDataアーカイブを作成し、ダミーファイルを追加する
19    // PharDataコンストラクタは、指定されたファイルが存在しない場合、新しいアーカイブを作成します。
20    // ここでは、新しいTarアーカイブとして初期化しています。
21    echo "PharDataアーカイブ: '{$pharFileName}' を作成中...\n";
22    $phar = new PharData($pharFileName, 0, null, Phar::TAR);
23    
24    // アーカイブ内にテキストファイルを追加
25    $phar->addFromString($filePathInsideArchive, $fileContent);
26    echo "'{$filePathInsideArchive}' をアーカイブに追加しました。\n\n";
27
28    // 2. 作成したPharDataアーカイブから特定のファイルエントリを取得する
29    // PharDataオブジェクトは配列のようにアクセスでき、ファイルエントリを返します。
30    // このファイルエントリは SplFileObject を継承しており、seek メソッドを持っています。
31    $fileEntry = $phar[$filePathInsideArchive];
32    echo "アーカイブからファイルエントリ '{$filePathInsideArchive}' を取得しました。\n";
33    echo "ファイルエントリの総バイト数: " . $fileEntry->getSize() . " バイト\n";
34
35    // 3. seek メソッドを使用して読み取り位置を変更し、内容を読み出す
36
37    // --- 例1: SEEK_SET (ファイルの先頭から指定したオフセットに移動) ---
38    $offsetSet = 10; // 先頭から10バイト目
39    echo "\n--- seek(\$offset = {$offsetSet}, SEEK_SET) の使用例 ---\n";
40    echo "ファイルポインタを先頭から {$offsetSet} バイトの位置に移動します。\n";
41    $fileEntry->seek($offsetSet, SEEK_SET);
42    // 現在の位置から20バイト読み込む
43    $readContentSet = $fileEntry->fread(20);
44    echo "読み取った20バイト: \"{$readContentSet}\"\n"; // "first sentence." の途中から始まる
45
46    // --- 例2: SEEK_CUR (現在の位置から指定したオフセットに移動) ---
47    $offsetCur = 5; // 現在の位置から5バイト進む
48    echo "\n--- seek(\$offset = {$offsetCur}, SEEK_CUR) の使用例 ---\n";
49    echo "ファイルポインタを現在の位置から {$offsetCur} バイト進めます。\n";
50    $fileEntry->seek($offsetCur, SEEK_CUR);
51    // 現在の位置から25バイト読み込む
52    $readContentCur = $fileEntry->fread(25);
53    echo "読み取った25バイト: \"{$readContentCur}\"\n"; // "second sentence, which "の途中から始まる
54
55    // --- 例3: SEEK_END (ファイルの末尾から指定したオフセットに移動) ---
56    $offsetEnd = -10; // 末尾から10バイト手前に移動 (負のオフセットを使用)
57    echo "\n--- seek(\$offset = {$offsetEnd}, SEEK_END) の使用例 ---\n";
58    echo "ファイルポインタを末尾から {$offsetEnd} バイト手前に移動します。\n";
59    $fileEntry->seek($offsetEnd, SEEK_END);
60    // 現在の位置から最後まで読み込む(例えば50バイト指定するが、残りすべてが読み込まれる)
61    $readContentEnd = $fileEntry->fread(50);
62    echo "読み取った残りバイト: \"{$readContentEnd}\"\n"; // "third sentence." の最後の方
63
64} catch (PharException $e) {
65    // Phar関連のエラーをキャッチ
66    echo "Phar関連のエラーが発生しました: " . $e->getMessage() . "\n";
67} catch (Exception $e) {
68    // その他の予期せぬエラーをキャッチ
69    echo "予期せぬエラーが発生しました: " . $e->getMessage() . "\n";
70} finally {
71    // 4. クリーンアップ: 作成した一時ファイルを削除する
72    if (file_exists($pharFileName)) {
73        unlink($pharFileName);
74        echo "\nクリーンアップ: 作成したアーカイブ '{$pharFileName}' を削除しました。\n";
75    }
76}

PHPのPharData::seekメソッドは、PharDataアーカイブ内に含まれる特定のファイルエントリの読み取り位置(ファイルポインタ)を操作するために使用されます。このメソッドは、SplFileObjectを継承したファイルオブジェクトに対して呼び出すことができます。

seekメソッドは主に二つの引数を取ります。第一引数$offsetは、ファイルポインタを移動させたいバイト数を整数で指定します。第二引数$whenceは、$offsetを適用する際の基準位置を定義し、デフォルト値はSEEK_SETです。SEEK_SETを選択すると、ファイルの先頭から$offsetバイトの位置に移動します。SEEK_CURを選択すると、現在のファイルポインタの位置から$offsetバイトだけ移動します。SEEK_ENDを選択すると、ファイルの末尾から$offsetバイト手前の位置に移動します(通常、負の$offsetを指定します)。

このメソッドは戻り値を持ちません。seekメソッドを呼び出すことで、次にファイルを読み込む際(例えばfreadメソッドを使用する際)の開始位置を自由に設定できます。これにより、アーカイブ内のファイル全体を最初から読み込むことなく、必要な部分だけを効率的に読み出す「シーク可能なストリーム」の概念を理解し、実際に操作することが可能になります。

PharData::seekメソッドは、ファイル内の読み取り位置を移動させます。引数$whenceは、移動の基準となる位置(ファイルの先頭、現在位置、末尾)を指定します。特にSEEK_ENDを使用する際は、オフセットを負の値にして末尾から手前に移動させる点に注意が必要です。本メソッドはバイト単位で位置を操作するため、マルチバイト文字を含むテキストファイルでは、文字の途中でシークしないよう注意してください。エラー発生時も戻り値がないため、例外処理を適切に記述し、ファイル操作の安全性を確保することが重要です。また、サンプルコードのように一時的に作成したアーカイブファイルは、処理後に必ず削除するようにしてください。

PharDataエントリのSEEK_ENDでファイル位置を操作する

1<?php
2
3/**
4 * PharDataアーカイブ内のファイルエントリに対して、末尾からのシークを実演する関数。
5 * システムエンジニアを目指す初心者向けに、正確で簡潔なコードを提供します。
6 * 
7 * PHPの標準ライブラリPharDataクラス自体には'seek'メソッドは存在しません。
8 * アーカイブ内の個々のファイルエントリ(SplFileObjectとしてアクセス可能)に対して
9 * 'seek'メソッドを使用するのが一般的な方法です。
10 * ここでは、PharDataアーカイブ内のファイルに対してSEEK_ENDを用いたシーク操作を示します。
11 */
12function demonstratePharDataEntrySeekEnd(): void
13{
14    // 一時的なPharDataアーカイブファイル名
15    $archiveName = 'sample_archive_seek.tar';
16    $archivePath = __DIR__ . '/' . $archiveName;
17    $entryFileName = 'my_file_to_seek.txt';
18
19    // 既存のアーカイブファイルがあれば削除(PharDataは既存ファイルを上書きしないため)
20    if (file_exists($archivePath)) {
21        PharData::unlinkArchive($archiveName);
22    }
23
24    try {
25        // 新しいPharDataアーカイブを作成 (tar形式)
26        $pharData = new PharData($archivePath);
27
28        // アーカイブに追加するファイルの内容
29        $content = "Hello, System Engineers!\n"
30                 . "This is the content for our seek example.\n"
31                 . "We will use SEEK_END to demonstrate seeking from the end of this file.";
32
33        // アーカイブに新しいファイルエントリを追加
34        $pharData->addFromString($entryFileName, $content);
35
36        // アーカイブ内の特定のエントリをSplFileObjectとして開く
37        // PharData::offsetGet() は PharFileInfo オブジェクトを返します。
38        // そのオブジェクトの openFile() メソッドで、ファイルの内容にアクセスするための SplFileObject を取得します。
39        /** @var SplFileObject $fileObject */
40        $fileObject = $pharData[$entryFileName]->openFile('r');
41
42        echo "--- PharDataアーカイブ内のファイルエントリへのシーク開始 ---\n";
43        echo "ファイルエントリ名: '" . $entryFileName . "'\n";
44        echo "ファイル全体のサイズ: " . $fileObject->getSize() . " バイト\n";
45
46        // SEEK_END を使用して、ファイルの末尾からオフセットを指定してシークします。
47        // オフセットが負の数である場合、ファイルの末尾から逆方向にバイト数を数えます。
48        // 例: 末尾から5バイト手前にシークし、"file."という部分を読み込みます。
49        $offsetFromEnd = -5; 
50        $fileObject->seek($offsetFromEnd, SEEK_END);
51        
52        // 現在のファイルポインタの位置を表示
53        echo "SEEK_END (オフセット: " . $offsetFromEnd . ") でシーク後のポインタ位置: " . $fileObject->ftell() . " バイト\n";
54
55        // シークした位置からファイル終端までを読み込む
56        // ここでは、オフセットの絶対値分のバイト数を読み込みます。
57        $readContent = $fileObject->fread(abs($offsetFromEnd)); 
58        echo "シーク後、読み込んだ内容: '" . $readContent . "'\n"; // "file." が表示されるはず
59
60        echo "\n--- 別のシーク例: 末尾から最後の行を読み込む ---\n";
61        // ポインタをファイルの先頭に戻す
62        $fileObject->seek(0, SEEK_SET);
63
64        // すべての行を読み込み、最後の行のバイト長を取得
65        $allLines = [];
66        while (!$fileObject->eof()) {
67            $allLines[] = $fileObject->fgets();
68        }
69        $lastLine = array_pop($allLines); // 最後の行を取得
70        $lastLineLength = strlen($lastLine); // 最後の行のバイト長
71
72        // 最終行の開始位置までシーク (ファイル全体のサイズから最終行の長さを引く)
73        $fileObject->seek(-$lastLineLength, SEEK_END);
74        
75        echo "SEEK_END (オフセット: -" . $lastLineLength . ") でシーク後のポインタ位置: " . $fileObject->ftell() . " バイト\n";
76        $readLastLine = $fileObject->fgets(); // 最後の行を読み込む
77        echo "シーク後、読み込んだ最後の行: '" . trim($readLastLine) . "'\n"; // 改行コードを除去して表示
78        
79    } catch (Exception $e) {
80        // エラーハンドリング
81        echo "エラーが発生しました: " . $e->getMessage() . "\n";
82    } finally {
83        // 後処理: 一時的なアーカイブファイルを削除
84        // PharDataオブジェクトがアクティブな場合、直接 unlinkArchive を呼ぶとエラーになることがあるため、
85        // オブジェクトをnullにして参照を解放してから削除するのが安全です。
86        if (isset($pharData) && file_exists($archivePath)) {
87            unset($pharData);
88            PharData::unlinkArchive($archiveName);
89        } elseif (file_exists($archivePath)) {
90            // PharDataオブジェクトが作成されなかった場合でもファイルを削除
91            PharData::unlinkArchive($archiveName);
92        }
93        echo "\n--- クリーンアップ完了 ---\n";
94    }
95}
96
97// サンプルコードを実行
98demonstratePharDataEntrySeekEnd();
99

PHP 8のPharDataクラスは、tarやzipなどのアーカイブファイルを操作する際に利用されます。このリファレンスで示されているseekメソッドは、PharDataクラス自体には直接存在せず、アーカイブ内の個々のファイルエントリをSplFileObjectとして開いた際に利用できるSplFileObject::seekメソッドを指しています。このメソッドは、ファイルポインタを指定した位置に移動させるために使用されます。

seekメソッドは2つの引数を取ります。1つ目の$offsetは、ポインタを移動させるバイト数を整数で指定します。2つ目の$whenceは、オフセットをどの位置から計算するかを指定する定数で、デフォルトはファイルの先頭を基準とするSEEK_SETです。他に、現在のポインタ位置を基準とするSEEK_CUR、そしてファイルの末尾を基準とするSEEK_ENDがあります。特にSEEK_ENDを使用する場合、ファイルの末尾から逆方向にポインタを移動させるには、$offsetに負の整数を指定します。このメソッドは戻り値を持ちません。

提供されたサンプルコードでは、まずPharDataアーカイブ内にテキストファイルを追加し、そのファイルエントリをSplFileObjectとして開いています。その後、$fileObject->seek($offsetFromEnd, SEEK_END)のようにSEEK_ENDを用いてファイルの末尾から5バイト手前にポインタを移動させ、そこからファイルを読み込むことで「file.」という文字列を取得しています。これにより、ファイルの特定の部分に効率的にアクセスできることが理解できます。また、ファイルの最後の行を読み込む応用例も示されています。

PHPのPharData::seekリファレンスは、実際にはPharDataアーカイブ内の個々のファイルエントリをSplFileObjectとして開いた際に、そのSplFileObjectに対してseekメソッドを使用することを示しています。PharDataクラス自体にseekメソッドは直接存在しませんのでご注意ください。

seekメソッドでSEEK_ENDを指定する場合、オフセットはファイルの末尾からの相対位置となり、通常は負の値を指定して末尾から手前に移動します。現在のファイルポインタの位置はftell()メソッドで確認できます。サンプルコードのように、一時的なPharDataアーカイブの操作後は、作成したファイルを確実に削除し、リソースを適切に解放することが重要です。