如何使用行位置在std :: ifstream中导航?

时间:2018-02-06 18:42:17

标签: c++ fstream

如果“\ n”将.txt文件带到下一行,我们如何向后退几行?

我必须在控制台输入日期,然后(!myfile.eof())检查所有匹配输入日期的行并在屏幕上打印。但是,如果我需要在日期之前cout前两行?

这是我的代码的一部分,我需要获得前一行

void searchByDate(){
        system("cls");
        string line;
        string text;
        int counts = 0;
        string date;

            searching.open("info.txt", ios::app | ios::in | ios::out);

            cout << "Please enter a valid date (DD/MM/GG): ";
            cin >> date;

            if (searching.fail()){
                cerr << "ERROR! Cannot open file" << endl;
                exit(1);
            }

            while(!searching.eof()){
                getline(searching, line);
                if(line == date){
                    getline (searching, text);
                    cout << text << endl;
                    counts++;
                }
            }

            cout << counts << " flights were found in current date." << endl;
        searching.close();

}

此外,弹出的控制台消息是

Please enter a valid date (DD/MM/GG): 06/02/18
20:30:50
10:00:00
21:59:00
3 flights were found in current date.

2 个答案:

答案 0 :(得分:1)

我在my comment中提到的是,您可以将输入流编入索引,只记住行的起始偏移量。

std::istream::tellg()std::istream::seekg()功能可让您导航到现役std::istream中的任意位置。

这是working example code

涉及一小部分标准库头:

#include <sstream>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstddef>

here document 以建立std::istream

static const std::string theInput{R"inp(Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur.

06/02/18

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
)inp"};

索引行起始位置并在其中导航的主程序:

int main()
{
    std::vector<std::size_t> line_positions;
    std::istringstream input_stream(theInput);
    std::string current_line;
    std::size_t theDatePos = -1u;

    // Collect all line starting positions
    do {
        line_positions.push_back(input_stream.tellg());
        std::getline(input_stream,current_line);
        if(current_line == "06/02/18") {
            theDatePos = line_positions.back();
        }
    } while(input_stream);

    // At this point the istream's eof bit is set, so to work furter
    // with it we need to clear() and reset the state.
    input_stream.clear();

    int current_line_number = line_positions.size();

    std::cout << "current_line: " << current_line_number << ". '" 
              << current_line << "'" << std::endl;

    if(theDatePos != -1u) {
        int date_line_number = 1;
        std::find_if(std::begin(line_positions),std::end(line_positions),
         [&date_line_number,theDatePos](const size_t& pos) {
             if(pos != theDatePos) {
                 ++date_line_number;
                 return false;
             }
             return true;
         });
        std::cout << "The date '06/02/18' was found at line number " 
                  << date_line_number << std::endl;
    }

    // Jump to line 3 and read it to the current line
    input_stream.seekg(line_positions[2]);
    std::getline(input_stream,current_line);
    std::cout << "current_line:  3. '" << current_line << "'" << std::endl;

    // Jump to line 5 and read it to the current line
    input_stream.seekg(line_positions[4]);
    std::getline(input_stream,current_line);
    std::cout << "current_line:  5. '" << current_line << "'" << std::endl;   

    // Jump back to line 2 and read it to the current line
    input_stream.seekg(line_positions[1]);
    std::getline(input_stream,current_line);
    std::cout << "current_line:  2. '" << current_line << "'" << std::endl;   
}

输出:

current_line: 14. ''
The date '06/02/18' was found at line number 10
current_line:  3. 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
current_line:  5. 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut'
current_line:  2. 'consectetur adipiscing elit,'

上面提到的技术可能有助于在大输入流中快速导航,从而节省最少的信息 将所有行保留为std::string个实例可能有点矫枉过正。

一些不错的算法抽象作为基于该模型的练习而留下:

提供从行索引 std::istream中提取单行或一系列行的函数:

 // Extract a single line based on a given line number (position)
 std::string getLineAtPos 
     ( std::istream& is, const std::vector<std::size_t>& linePositions
     , std::size linePos
     );

 // Extract a contiguous range of lines based on a given pair of line numbers 
 // (.first == low, .second == high)
 std::vector<std::string> getLineRange
     ( std::istream& is
     , const std::vector<std::size_t>& linePositions
     , std::pair<std::size_t,std::size_t>& lineRange
     );

答案 1 :(得分:0)

你问我们错误的问题。您想要的是能够搜索您的数据集以获得匹配条件。您遇到的问题是,在您已经阅读过数据集的开头之前,您可能找不到匹配项。

针对此类问题的最简单的解决方案是为输入文件的数据集定义一个类,并使用它来封装您的数据,以便根据需要进行进一步处理。

您可以重载istream和ostream操作符并将I / O操作封装在类中。这是实现所需行为的一种非常干净的方法,但请注意,在从输入构建对象时,输入流上没有错误检查。添加错误检查和输入验证是读者的一项练习。

这里有一个名为Flights的类,它会重载输入和输出流操作符。

class Flights
{
    friend std::ostream& operator << (std::ostream& oss, const Flights& f)
    {
        oss << "Departs: " << f._depart << " - "
            << "Arrives: " << f._arrive << "  Time: "
            << f._time << std::endl;
        return oss;
    }

    friend std::istream& operator >> (std::istream& iss, Flights& f)
    {
        std::string line;
        std::getline(iss, line);
        f._depart = line;
        std::getline(iss, line);
        f._arrive = line;
        std::getline(iss, line);
        f._date = line;
        std::getline(iss, line);
        f._time = line;
        return iss;
    }

    public:

        const std::string & getDeparture() const { return _depart; }
        const std::string & getArrival() const { return _arrive; }
        const std::string & getDate() const { return _date; }
        const std::string & getTime() const { return _time; }

    private:

        std::string _depart;   ///< departure city
        std::string _arrive;   ///< arrival city
        std::string _date;     ///< date to match user input
        std::string _time;     ///< departure time for flight
};

现在,实现将解析输入文件并填充本地Flights对象的业务逻辑变得微不足道。如果用户输入日期与该对象的日期匹配,我们会将其添加到我们的匹配数据存储中。由于我们重载了输出流,只输出结果std::cout << object;增加了奖金!如果您需要按照其他条件(如抵达城市或出发城市)搜索您的数据集,您可以使用此Flights类轻松编写一个功能来完成该操作。

int main()
{
    std::string date;
    std::cout << "Please enter a valid date (DD/MM/GG): ";
    std::cin >> date;

    std::vector<Flights> flightList;
    std::ifstream infile("flights.txt");
    if (infile.is_open())
    {
        Flights flight;
        while (infile >> flight)
        {
            if (flight.getDate() == date)
            {
                flightList.push_back(flight);
            }
        }
        infile.close();
    }

    // print the flight data you found for that date
    std::cout << flightList.size() << " flights were found in current date." << std::endl;
    for (size_t i = 0; i < flightList.size(); ++i)
    {
        std::cout << flightList[i];
    }

    return 0;
}

上面的代码在输入文件上进行了测试,如下所示:

flights.txt

Abu Dhabi (UAE)
Moscow (RUS)
06/01/18
24:00
Cape Town (CPT)
Johannesburg (HLA)
06/02/18
18:05
Buenos Aires (AEP)
Rio de Janeiro (GIG)
06/03/18
15:07