从文件C++中的特定位置读取

Read from a specific spot in a file C++

本文关键字:定位 位置 读取 文件 C++      更新时间:2023-10-16

我在C++中有一个程序,需要返回特定单词出现的行。例如,如果我的文件看起来像这样:

the cow jumped over
the moon with the
green cheese in his mouth

我需要打印带有"with"的行。程序得到的只是文件开头的偏移量(在本例中为 24,因为"with"是文件开头的 24 个字符)。

如何打印整行"月亮与",仅偏移量?

多谢!

您可以通过单独读取每一行并记录读取前后的文件位置来执行此操作。然后,只需检查单词的偏移量是否在该行的范围内即可。

#include <iostream>
#include <fstream>
#include <string>
std::string LineFromOffset(
    const std::string &filename,
    std::istream::pos_type targetIndex)
{
    std::ifstream input(filename);
    //  Save the start position of the first line. Should be zero of course.
    std::istream::pos_type  lineStartIndex = input.tellg();
    while(false == input.eof())
    {
        std::string   line;
        std::getline(input, line);
        //  Get the end position of the line
        std::istream::pos_type  lineEndIndex = input.tellg();
        //  If the index of the word we're looking for in the bounds of the
        //  line, return it
        if(targetIndex >= lineStartIndex && targetIndex < lineEndIndex)
        {
            return line;
        }
        // The end of this line is the start of the next one. Set it
        lineStartIndex = lineEndIndex;
    }
    //  Need a better way to indicate failure
    return "";
}
void PrintLineTest()
{
    std::string str = LineFromOffset("test.txt", 24);
    std::cout << str;
}

一个好的解决方案是从头到所需位置读取文件(由@Chet辛普森回答)。如果你想要优化(例如,非常大的文件,位于中间的某个地方,典型的行相当短),你可以向后读取文件。但是,这仅适用于以二进制模式打开的文件(类 Unix 平台上的任何文件;在 Windows 上使用 ios_base::binary 参数打开文件)。

算法如下:

  • 在文件中返回几个字节
  • 读取几个字节
  • 如果那里有生产线末端,其余的都很容易
  • 否则,请重复

代码(在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的平台上,行尾用rn标记,由于您必须使用二进制模式,因此输出字符串将包含额外的字符r(除非文件末尾没有行尾),您可以将其丢弃。

每个操作都有函数

fopen - 打开文件

fseek - 将文件查找到所需的偏移量

fread - 读取所需的字节数

fclose - 关闭文件