初心者必見!Qt QTextStream::seek()の基本から実践的な使い方まで
基本的な機能
seek(qint64 pos)
関数は、ストリームの現在位置をpos
で指定されたバイトオフセットに設定します。pos
はストリームの先頭からのバイト数で表されます。
QTextStreamとQFileの関連
QTextStream
は、通常、QFile
のようなQIODevice
を内部で利用して、実際のデータ読み書きを行います。QTextStream
がテキストのエンコーディング(UTF-8、Shift-JISなど)や改行コード(CRLF、LFなど)の変換を抽象化してくれるため、開発者は生のバイト列を気にすることなくテキストを扱えます。
しかし、seek()
を理解する上で重要なのは、QTextStream
が内部でバッファリングを行っている点です。seek()
は、バイトオフセットに基づいて位置を指定します。これは、文字数ではなく、実際のファイル内のバイト数で位置が決定されることを意味します。
注意点
-
バッファリング:
QTextStream
はパフォーマンス向上のために内部バッファを使用します。seek()
を呼び出すと、この内部バッファがクリアされ、新しい位置からデータが読み込まれます。 もしQTextStream
を使わずに基になるQFile
のread()
やreadLine()
などを使って直接ファイルを読み書きすると、QTextStream
の内部的な位置とQFile
のファイルポインタの位置がずれてしまう可能性があります。seek()
を使う場合は、一貫してQTextStream
のメソッドを使用することが推奨されます。 -
シーケンシャルデバイス:
QIODevice
には、ランダムアクセスデバイス(QFile
など、seek()
が可能なもの)とシーケンシャルデバイス(QTcpSocket
など、seek()
が不可能なもの)があります。QTextStream::seek()
は、基になるQIODevice
がランダムアクセスをサポートしている場合にのみ機能します。QFile
のような通常のファイルであれば問題なく使用できます。 -
QIODevice::Text
フラグとの関係:QFile::open()
時にQIODevice::Text
フラグを使用すると、改行コードの自動変換が行われます。QTextStream
を使用する場合、このフラグは指定しない方が良いとされています。QTextStream
自体がエンコーディングや改行コードの変換を処理するため、重複して変換が行われることで予期せぬ問題(特にseek()
で位置がずれるなど)が発生する可能性があります。
使用例
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile file("my_text_file.txt");
// ファイルを書き込みモードで開く
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
QTextStream out(&file);
out.setCodec("UTF-8"); // 日本語を扱うためUTF-8に設定
out << "最初の行です。\n";
out << "これが二行目です。\n";
out << "三行目のテキスト。\n";
out << "最後の行です。\n";
file.close();
qDebug() << "ファイルに書き込みました。";
} else {
qDebug() << "ファイルの書き込みに失敗しました。";
return -1;
}
// ファイルを読み込みモードで開く
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
in.setCodec("UTF-8"); // 読み込む際もUTF-8に設定
qDebug() << "現在の位置(初期値):" << in.pos(); // 通常は0
QString line1 = in.readLine();
qDebug() << "1行目:" << line1;
qDebug() << "1行目を読んだ後の位置:" << in.pos();
// 2行目の開始位置を記憶
qint64 pos_before_line2 = in.pos();
QString line2 = in.readLine();
qDebug() << "2行目:" << line2;
qDebug() << "2行目を読んだ後の位置:" << in.pos();
// 記憶した2行目の開始位置に戻る
if (in.seek(pos_before_line2)) {
qDebug() << "位置を戻しました。現在の位置:" << in.pos();
QString line2_re_read = in.readLine();
qDebug() << "再度2行目を読む:" << line2_re_read;
} else {
qDebug() << "seekに失敗しました。";
}
// ファイルの先頭に戻ってすべて読み込む
if (in.seek(0)) {
qDebug() << "\nファイルの先頭に戻って全て読み込みます:";
qDebug() << in.readAll();
}
file.close();
} else {
qDebug() << "ファイルの読み込みに失敗しました。";
return -1;
}
// 作成したファイルを削除 (オプション)
// QFile::remove("my_text_file.txt");
return a.exec();
}
QTextStream::seek()
は非常に便利な機能ですが、その内部的な動作(特にバッファリングとエンコーディング)を理解していないと、予期せぬ挙動に遭遇することがあります。
バッファリングによる位置のずれ
エラー/問題: QTextStream
を使って読み書きしている途中で、直接基となるQFile
のseek()
やread()
、readLine()
などのメソッドを呼び出すと、QTextStream
の内部的な位置(pos()
で取得できるもの)と実際のファイルポインタの位置が同期されなくなり、QTextStream::seek()
が正しく機能しない、または期待通りの位置に移動しない。
原因: QTextStream
はパフォーマンスのために内部バッファを使用しています。QTextStream
を通してデータを読み書きすると、そのバッファが更新されます。しかし、QFile
などの下位レベルのI/Oデバイスを直接操作すると、QTextStream
はその操作を認識しないため、内部バッファと実際のファイルポインタが矛盾します。
トラブルシューティング:
- ストリームの再初期化: どうしても
QFile
を直接操作する必要がある場合、または位置が完全に狂ってしまった場合は、一度QTextStream
を閉じるか、新しいQTextStream
オブジェクトを生成し、QFile
を再度開いて(またはsetDevice()
で再設定して)ストリームをリセットすることを検討します。これは最後の手段であり、できる限り避けるべきです。 flush()
とseek()
の組み合わせ: 書き込みモードでseek()
する前に、QTextStream::flush()
を呼び出して内部バッファをデバイスに書き出すことで、同期の問題を軽減できる場合があります。- 一貫性を保つ:
QTextStream
を使用する場合は、データの読み書きも必ずQTextStream
のメソッド(readLine()
,readAll()
,operator<<
,operator>>
など)を通して行うようにします。QFile
のメソッドを直接使用するのは避けるべきです。
エンコーディング(文字コード)とバイトオフセットの混同
トラブルシューティング:
- 文字単位の移動は非推奨:
QTextStream
を使って、厳密にN文字分だけseek()
で移動するという使い方は、エンコーディングによって複雑になり、バグの温床になりがちです。必要であれば、一度readAll()
で全てをQString
に読み込み、QString
の操作(mid()
,left()
,right()
など)で文字単位の処理を行う方が安全です。ただし、非常に大きなファイルではメモリ使用量に注意が必要です。 - 行単位の処理: 「N行目」に移動したい場合は、
seek()
で直接移動するのではなく、ファイルの先頭(seek(0)
)からreadLine()
をN回繰り返して読み飛ばす方が確実です。 pos()
との併用:seek()
は、以前にQTextStream::pos()
で取得したバイトオフセットに戻る際に最も信頼性が高いです。例えば、ファイルの特定の場所をブックマークしておき、後でその場所に戻りたい場合に適しています。qint64 bookmarkPos = stream.pos(); // ... 読み書き ... stream.seek(bookmarkPos); // ブックマークした位置に戻る
QIODevice::Textフラグの使用
エラー/問題: QFile::open()
時にQIODevice::Text
フラグを指定してファイルを開き、そのQFile
をQTextStream
に設定している場合、QTextStream
が改行コードの変換を二重に行ったり、seek()
の位置計算に影響を与えたりする可能性がある。
原因: QIODevice::Text
フラグは、改行コード(WindowsのCRLFとUnixのLF)の自動変換を有効にします。QTextStream
もまた、指定されたQTextCodec
に基づいて改行コードを含むテキスト変換を内部で行います。この二重変換がseek()
のバイトオフセットの計算を複雑にし、予期せぬ位置のずれを引き起こす可能性があります。
トラブルシューティング:
QIODevice::Text
フラグを避ける:QTextStream
を使用する場合は、QFile::open()
時にQIODevice::Text
フラグを使用しないことを強く推奨します。QTextStream
に適切なQTextCodec
を設定するだけで、テキストのエンコーディングと改行コードの変換を適切に処理できます。
シーケンシャルデバイスに対するseek()の呼び出し
エラー/問題: QTcpSocket
やQProcess
の標準入出力など、シーケンシャルデバイスに対してQTextStream::seek()
を呼び出そうとすると、seek()
がfalse
を返し、位置の移動に失敗する。
原因: QTextStream::seek()
は、基となるQIODevice
がランダムアクセスをサポートしている場合にのみ機能します。QFile
やQBuffer
はランダムアクセスデバイスですが、QTcpSocket
やQProcess
はデータが連続的に流れるシーケンシャルデバイスであり、任意の位置にジャンプする機能を持っていません。
トラブルシューティング:
- 代替手段: シーケンシャルデバイスで特定のデータをスキップしたい場合は、読み捨てていくしかありません。例えば、
read(N)
でNバイトを読み飛ばす、またはreadLine()
で不要な行を読み飛ばすなどです。 - デバイスの性質を理解する: 使用している
QIODevice
がisSequential()
をtrue
と返す場合、seek()
は使用できません。シーケンシャルデバイスでは、データの読み書きは常に現在の位置から順次行われる必要があります。
atEnd()とseek()の連携の誤解
エラー/問題: readAll()
などでストリームの終端に達した後、seek(0)
で先頭に戻っても、その後atEnd()
がすぐにtrue
を返してしまい、読み込みができない。
原因: QTextStream
がファイルの終端に達したと判断すると、内部の状態が「終端」になります。seek()
は位置を移動しますが、ストリームの内部状態(エラーや終端フラグなど)を必ずしも完全にリセットするわけではありません。特に、一度atEnd()
がtrue
になると、再度読み込みを行う前にストリームの状態をリセットする必要がある場合があります。
トラブルシューティング:
clear()
:QFile::open()
の後に、QTextStream
のコンストラクタでQFile
を渡す際に、QTextStream
の内部状態をリセットしたい場合は、stream.clear()
を呼ぶと良い場合もあります。ただし、主にエラー状態をクリアするために使用されます。QTextStream::resetStatus()
:QTextStream::resetStatus()
を呼び出して、ストリームの内部ステータス(エラーフラグや終端フラグなど)をリセットします。これは、seek()
が成功した後に再度読み込みを行いたい場合に有効です。- ファイルのリオープン: 最も確実な方法は、ファイルを一度閉じて(
file.close()
)、再度開く(file.open(...)
)ことです。これにより、QTextStream
も新しいファイルストリームとして初期化されます。
ファイルの先頭に戻って再度読み込む
最も一般的な使用例は、ファイルを一度読み終えた後、再び先頭から読み込みたい場合です。
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// テスト用のファイルを作成
QFile file("sample.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&file);
out.setCodec("UTF-8"); // 日本語も考慮
out << "最初の行です。\n";
out << "二行目の内容。\n";
out << "三行目、最終行。\n";
file.close();
qDebug() << "sample.txt を作成しました。";
} else {
qDebug() << "ファイルの作成に失敗しました。";
return -1;
}
// ファイルを読み込みモードで開く
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
in.setCodec("UTF-8");
qDebug() << "--- 1回目の読み込み ---";
while (!in.atEnd()) {
qDebug() << in.readLine();
}
// ファイルの先頭に戻る
if (in.seek(0)) {
qDebug() << "\n--- ファイルの先頭に戻って2回目の読み込み ---";
// seek()後もatEnd()がtrueのままの場合があるので、
// resetStatus()を呼ぶことでストリームの状態をクリアすることが推奨されます。
in.resetStatus();
while (!in.atEnd()) {
qDebug() << in.readLine();
}
} else {
qDebug() << "seek(0) に失敗しました。";
}
file.close();
} else {
qDebug() << "ファイルの読み込みに失敗しました。";
return -1;
}
// 作成したファイルを削除 (オプション)
// QFile::remove("sample.txt");
return a.exec();
}
解説:
- ファイルを読み込みモードで開き、
QTextStream
を使って内容をすべて読み込みます。 in.atEnd()
がtrue
になった後、in.seek(0)
を呼び出してストリームの位置をファイルの先頭(バイトオフセット0)に戻します。seek()
の後にin.resetStatus()
を呼び出すことで、ストリームの内部状態(特にatEnd()
フラグ)をリセットし、再度読み込みができるようにします。- 再びループでファイルを読み込み、先頭から読み込めていることを確認します。
ファイルの特定の位置から読み込みを開始したい場合や、以前に記録した位置に戻りたい場合にseek()
を使用します。
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// テスト用のファイルを作成
QFile file("data.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&file);
out.setCodec("UTF-8");
out << "データA: 値1, 値2\n"; // 最初の行
qint64 pos_data_b = out.pos(); // この時点のバイト位置を記録
out << "データB: 値3, 値4\n"; // 二行目
out << "データC: 値5, 値6\n"; // 三行目
file.close();
qDebug() << "data.txt を作成しました。データBの開始位置を記録しました。";
} else {
qDebug() << "ファイルの作成に失敗しました。";
return -1;
}
// ファイルを読み込みモードで開く
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
in.setCodec("UTF-8");
// 記録したデータBの開始位置に移動
qint64 recorded_pos = 18; // 例えば、"データB"の開始位置を事前に知っているか、pos()で取得した場合
// 実際のバイトオフセットはエンコーディングや改行コードに依存します。
// 上記の例では、"データA: 値1, 値2\n" (UTF-8, LF) が18バイトなので、手動で設定。
// 通常は out.pos() で正確な位置を記録します。
qDebug() << "現在の位置(初期値):" << in.pos();
if (in.seek(recorded_pos)) {
qDebug() << "データBの開始位置に移動しました (" << recorded_pos << "バイト)。";
in.resetStatus(); // 状態をリセット
while (!in.atEnd()) {
qDebug() << "読み込み中:" << in.readLine();
}
} else {
qDebug() << "指定した位置 (" << recorded_pos << ") への移動に失敗しました。";
}
file.close();
} else {
qDebug() << "ファイルの読み込みに失敗しました。";
return -1;
}
// 作成したファイルを削除 (オプション)
// QFile::remove("data.txt");
return a.exec();
}
解説:
- ファイルに書き込む際に、
QTextStream::pos()
を呼び出して、特定のデータの開始バイト位置を記録します。 - ファイルを読み込みモードで開き、
in.seek(recorded_pos)
を使って、記録した位置に移動します。 - そこから
readLine()
などで読み込みを再開します。
重要な注意点:
- 書き込みモードで
seek()
を使用する場合、QTextStream::flush()
を呼び出して内部バッファをデバイスに書き出してからseek()
を行うことで、予期せぬ動作を防ぐことができます。 seek()
がfalse
を返す場合、デバイスがシークをサポートしていないか、指定された位置が無効である可能性があります。- ファイルに書き込む際に
QTextStream::pos()
で得たオフセットは、その後のQTextStream::seek()
で正確にその位置に戻るために最も信頼できる方法です。 QTextStream
が使用するエンコーディング(UTF-8など)によっては、1文字が複数バイトになることがあります。そのため、例えば「ファイルの30文字目」に移動したい場合に、単純にseek(30)
とすることはできません。seek()
に渡すオフセットはバイト数です。文字数ではありません。
以下に、QTextStream::seek()
の代替となるプログラミング手法をいくつか紹介します。
行単位での読み飛ばし(行数指定の場合)
もし「N行目に移動したい」という要件がある場合、seek()
はバイトオフセットで動作するため、テキストファイルのエンコーディングや改行コードによってバイト数が変動し、正確な位置を特定するのが困難です。この場合、ファイルの先頭から行を読み飛ばしていくのが最も確実な方法です。
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
// N行目に移動して、そこから読み込みを開始する関数
QString readFromLine(QFile &file, int targetLineNumber) {
if (!file.isOpen()) {
qDebug() << "ファイルが開かれていません。";
return QString();
}
// ストリームの先頭に戻る
// QTextStream::seek(0) が可能であれば、ファイルポインタをリセットする
QTextStream in(&file);
in.setCodec("UTF-8"); // 適切なエンコーディングを設定
if (file.isReadable() && file.isSequential()) {
// シーケンシャルデバイス(例:QProcessからの入力など)ではseekできないので、
// 毎回ファイルをリオープンする必要がある。
// QFileであれば以下は不要だが、一般的なケースとして記載。
file.seek(0); // QIODevice::seek() を使用 (QTextStreamが設定済みでも影響しないはず)
in.resetStatus();
} else {
// ランダムアクセスデバイスの場合
in.seek(0);
in.resetStatus();
}
int currentLine = 0;
while (!in.atEnd()) {
QString line = in.readLine();
currentLine++;
if (currentLine == targetLineNumber) {
qDebug() << targetLineNumber << "行目から読み込みを開始します:";
return line; // 目的の行を返す(またはそこから読み込みを開始する)
}
}
qDebug() << targetLineNumber << "行目は見つかりませんでした。";
return QString(); // 見つからなかった場合
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// テスト用のファイルを作成
QFile file("large_text_data.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&file);
out.setCodec("UTF-8");
for (int i = 1; i <= 100; ++i) {
out << QString("これは %1 行目です。").arg(i) << "\n";
}
file.close();
qDebug() << "large_text_data.txt を作成しました。";
} else {
qDebug() << "ファイルの作成に失敗しました。";
return -1;
}
// ファイルを読み込みモードで開く
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString line50 = readFromLine(file, 50);
qDebug() << "取得した50行目:" << line50;
// 50行目からさらに読み進める場合
QTextStream currentStream(&file); // readFromLineでファイルポインタが移動しているので、新しいQTextStreamを作成するか、
// readFromLine内でストリームを保持して返す
currentStream.setCodec("UTF-8"); // 忘れずにコーデックを設定
qDebug() << "現在のストリーム位置から次の行を読み込み:";
qDebug() << currentStream.readLine(); // 51行目が読み込まれる
file.close();
} else {
qDebug() << "ファイルの読み込みに失敗しました。";
return -1;
}
// QFile::remove("large_text_data.txt"); // オプション
return a.exec();
}
利点:
- 理解しやすく、実装がシンプル。
- エンコーディングや改行コードに依存せず、正確な「N行目」に移動できる。
欠点:
- 目的の行がファイルの後半にある場合、大量の行を読み飛ばす必要があり、パフォーマンスが低下する可能性がある。特に巨大なファイルでは効率が悪い。
QFile の seek() を直接使用する(テキストファイルには非推奨だが、バイナリファイルでは有効)
QTextStream
はテキストのエンコーディングや改行コードの変換を抽象化しますが、その基盤となる QFile
(または他の QIODevice
)はバイト単位で動作します。厳密にバイトオフセットが分かっている場合は、QFile::seek()
を直接使用することも可能です。しかし、これはテキストファイルには非推奨です。
#include <QCoreApplication>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile file("binary_data.bin"); // バイナリファイルを想定
// バイナリデータを書き込み
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QByteArray data;
data.append("HEADER1234"); // 10バイト
data.append(QByteArray(100, 'A')); // 100バイトの'A'
data.append("FOOTER5678"); // 10バイト
file.write(data);
file.close();
qDebug() << "binary_data.bin を作成しました。";
} else {
qDebug() << "ファイルの作成に失敗しました。";
return -1;
}
// 特定のバイト位置から読み込み
if (file.open(QIODevice::ReadOnly)) {
// "AAAA..." の部分の開始位置に移動 (HEADER1234の10バイト後)
qint64 offset = 10;
if (file.seek(offset)) {
QByteArray chunk = file.read(5); // 5バイト読み込む
qDebug() << "オフセット" << offset << "から5バイト読み込み:" << chunk;
} else {
qDebug() << "seekに失敗しました。";
}
// FOOTER の部分の開始位置に移動 (HEADER1234 (10) + AAAA... (100) = 110バイト後)
offset = 110;
if (file.seek(offset)) {
QByteArray footer = file.read(file.bytesAvailable()); // 残りすべてを読み込む
qDebug() << "オフセット" << offset << "から読み込み:" << footer;
} else {
qDebug() << "seekに失敗しました。";
}
file.close();
} else {
qDebug() << "ファイルの読み込みに失敗しました。";
return -1;
}
// QFile::remove("binary_data.bin"); // オプション
return a.exec();
}
利点:
QTextStream
のバッファリングやエンコーディング変換による複雑さを回避できる。- バイナリデータの場合、正確なバイト単位での位置制御が可能。
欠点:
- テキストファイルには非推奨: テキストファイルに対して
QFile::seek()
とQFile::read()
を直接使うと、改行コードの自動変換が行われず、エンコーディングも手動で管理する必要があるため、テキストの読み書きが非常に複雑になります。テキストファイルを扱う場合は、QTextStream
の使用が推奨されます。
全体を読み込み、メモリ上で処理する
ファイルが比較的小さい場合や、一度ファイル全体をメモリに読み込んでしまえば、その後の処理が非常に効率的になります。QString
や QByteArray
のメソッドを使って、必要な部分を抽出したり、文字列検索を行ったりできます。
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// テスト用のファイルを作成
QFile file("small_data.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&file);
out.setCodec("UTF-8");
out << "Hello, world!\n";
out << "Qt programming is fun.\n";
out << "This is line number three.\n";
out << "The end.\n";
file.close();
qDebug() << "small_data.txt を作成しました。";
} else {
qDebug() << "ファイルの作成に失敗しました。";
return -1;
}
// ファイルを読み込みモードで開く
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
in.setCodec("UTF-8");
QString allContent = in.readAll(); // 全体を読み込む
qDebug() << "ファイル全体のコンテンツ:\n" << allContent;
// メモリ上で特定の行や文字列を抽出
QStringList lines = allContent.split('\n', Qt::SkipEmptyParts); // 行に分割
if (lines.size() >= 2) {
qDebug() << "2行目:" << lines.at(1);
}
// 文字列検索
int index = allContent.indexOf("programming");
if (index != -1) {
qDebug() << "'programming' はオフセット" << index << "から見つかりました。";
// その前後を抽出
qDebug() << "周辺の文字列:" << allContent.mid(qMax(0, index - 10), 30);
}
file.close();
} else {
qDebug() << "ファイルの読み込みに失敗しました。";
return -1;
}
// QFile::remove("small_data.txt"); // オプション
return a.exec();
}
利点:
- 一度読み込めば、何度でも異なる方法でデータを処理できる。
- メモリにロードされた後は、
QString
やQByteArray
の強力な文字列操作機能(indexOf()
,mid()
,split()
, 正規表現など)をフル活用できる。
欠点:
- 非常に大きなファイル(GB単位など)の場合、メモリを大量に消費し、アプリケーションのパフォーマンスや安定性に影響を与える可能性がある。
特定のフォーマット(CSV、XML、JSONなど)のファイルを扱う場合、それぞれのフォーマットに特化したQtのクラス(QCsvFile
, QXmlStreamReader
, QJsonDocument
など)や、外部の解析ライブラリを使用する方が効率的で堅牢な場合があります。これらのライブラリは、内部的に効率的な読み込み戦略を持っていることが多く、手動でseek()
や行読み込みを繰り返すよりも優れています。
例えば、CSVファイルであれば、自前でreadLine()
とsplit(',')
を繰り返すよりも、CSVパーサーライブラリを使った方が、クォーテーションや改行を含むフィールドの処理などを気にせずに済みます。
QTextStream::seek()
は特定のバイトオフセットに戻る場合に有効ですが、テキストファイルではエンコーディングや改行コードによってバイト数が変動するため、使いこなすには注意が必要です。
- 特定のデータ構造を持つファイル: そのフォーマットに特化したQtクラスや外部ライブラリを利用する。
- バイナリファイルをバイト単位で操作したい:
QFile::seek()
を直接使用する。 - ファイル全体が小さい:
readAll()
でメモリに読み込んでから、QString
やQByteArray
の強力な文字列操作機能を使う。 - 行単位で移動したい:
readLine()
を繰り返して読み飛ばすのが最もシンプルで確実。