適切な解決策は、ファイルを最初から目的の位置まで読み取ることです (@Chet Simpson による回答)。最適化が必要な場合 (たとえば、非常に大きなファイル、中間のどこかに配置、典型的な行がかなり短いなど)、ファイルを逆方向に読み取ることができます。ただし、これはバイナリ モードで開かれたファイルでのみ機能します (UNIX ライクなプラットフォームの任意のファイルios_base::binary
。Windows ではパラメーターを使用してファイルを開きます)。
アルゴリズムは次のようになります。
- ファイル内の数バイト戻る
- 数バイトを読み取る
- そこに行末があればあとは簡単
- そうでなければ繰り返す
コード (Windows でテスト済み):
std::string GetSurroundingLine(std::istream& f, std::istream::pos_type start_pos)
{
std::istream::pos_type prev_pos = start_pos;
std::istream::pos_type pos;
char buffer[40]; // typical line length, so typical iteration count is 1
std::istream::pos_type size = sizeof(buffer);
// Look for the beginning of the line that includes the given position
while (true)
{
// Move back 40 bytes from prev_pos
if (prev_pos < size)
pos = 0;
else
pos = prev_pos - size;
f.seekg(pos);
// Read 40 bytes
f.read(buffer, prev_pos - pos);
if (!f)
throw;
// Look for a newline byte, which terminates previous line
int eol_pos;
for (eol_pos = sizeof(buffer) - 1; eol_pos >= 0; --eol_pos)
if (buffer[eol_pos] == '\n')
break;
// If found newline or got to beginning of file - done looking
if (eol_pos >= 0 || pos == (std::istream::pos_type)0)
{
pos += eol_pos + 1;
break;
}
}
// Position the read pointer
f.seekg(pos);
// Read the line
std::string s;
std::getline(f, s, '\n');
return s;
}
編集: 行末が でマークされている Windows のようなプラットフォームでは、\r\n
バイナリ モードを使用する必要があるため、出力文字列には余分な文字が含まれます\r
(ファイルの終わりに行末がない場合を除きます)。 )、捨てることができます。