正在设置文件指针位置

Setting file pointer position

本文关键字:指针 位置 文件 设置      更新时间:2023-10-16
  • 我有一个很大的文本文件,里面有很多按行排列的条目
  • 每行的第一个单词对我来说就像一个">"。这行的其他单词都是数字
  • 一行的第一个字也可以存在于大量其他行中

作为一个例子,考虑如下文件的示例:

Associative 19 78 45 23 
Disjunctive 23 45 02 200
Associative 23 546 32 56
Conjunctive 22 22 00 3478
Disjunctive 11 934 88 34

我的目标:

对所有"联想词"、"虚拟词"answers"连接词"做一组特定的运算。该文件很大,未进行排序。我可以使用bash进行额外的排序操作,但只考虑我想避免它的情况

我的方法

Step 1 : Open the file using **std::ifstream**
Step 2 : Create an unordered set to store the unique first words.
Step 3 : Create a multimap of type multimap<std::string,streampos>
Step 4 : Traverse the file using std::ifstream::ignore, and keep adding the first word to the unordered set, and stream position to the multimap alongwith the first word.
Step 5 : The thought is that in this way a primary index of stream position and line numbers is being created.
Step 6 : Now go through each element of the unordered set and use multimap::equal_range to look for stream positions for that key.
Step 7 : Traverse through those stream positions and do your operation

Q1.使用C++从文件中读取特定行的方法正确吗?

Q2.下面是我为测试这个想法而编写的C++程序的一个基本片段。然而,我觉得这个想法不会成功。程序已完成。您可以简单地复制和粘贴代码,并使用上面的文本文件示例来查看输出。具体问题如下:当我使用seekg设置流位置,然后尝试读取一行时,似乎什么都没发生(即流位置没有改变(。代码片段如下:

#include<iostream>
#include<fstream>
#include<limits>
#include<unordered_set>
#include<map>
using namespace std;
int main(int argc,char* argv[])
{
        if (argc<2)
        {
                cout<<"Usage: get_negatives <Full Path of Annotation File> n"<<endl;
                return 0;
        }
        ifstream fileGT; 
        fileGT.open(argv[1]);//Open the file containing groundtruth annotations
        string filename;
        unordered_set<string> unique_files; //Open this unordered set to uniquely store the file names
        multimap<string,streampos> file_lines; //Open this multimap to store the file names as keys and corresponding line numbers as the values
        streampos filepos = fileGT.tellg();
        fileGT>>filename; 
        unique_files.insert(filename);
        file_lines.insert(pair<string,streampos>(filename,filepos));
        while(!fileGT.eof())
        {
                fileGT.ignore(numeric_limits<streamsize>::max(),'n');
                filepos = fileGT.tellg();       
                fileGT>>filename;
                unique_files.insert(filename);
                file_lines.insert(pair<string,streampos >(filename,filepos));
        }
        for(auto it=unique_files.begin(); it!=unique_files.end(); ++it)
        {
                pair<multimap<string,streampos>::iterator, multimap<string,streampos>::iterator>range_vals;
                range_vals = file_lines.equal_range(*it);
                for(auto it2=range_vals.first; it2!=range_vals.second; ++it2)
                {
                        fileGT.seekg(it2->second,ios_base::beg);
                        getline(fileGT,filename);       
                        cout<<filename<<endl;
                }
        }

        return -1;
}       

问题是,如果设置了一些错误位,seekg()有时无法正常工作。

您必须始终在每次fileGT.seekg()之前调用fileGT.clear()。我认为这应该是C++11中的默认模式,但我不会打赌。

此外,在每次读取后检查错误也是一个好主意:

if (!getline(fileGT, filename))
    //error handling

而且,正如我在评论中所说,如果你要四处寻找,你必须用std::ios::binary打开文件。

我还没有测试你的代码,但我建议你做一些更改:

  • 我遇到的大多数操作系统都使用约定,用于main的返回值,return 0用于典型/正确输出,return 1(或非零(用于异常情况。

  • 除非你真的需要,否则不要使用nendl,我认为这不是千种情况之一。

  • 考虑重新排序while循环,使ignore位于末尾,考虑以下内容:

std::string buf;
std::ifstream fp("input");
while (fp)
{
  if (fp >> buf) { /* do something with buf */ }
  fp.ignore(streamsize::max(), 'n');
}
  • 无论何时从流中读取,都不要认为输出良好或流仍然有效。检查错误标志(使用bool重载或fp.good()(。仅仅检查fp.eof()可能并不总是足够的。

  • 如果您使用的是C++11seekg,即使在到达文件末尾后也应该运行良好,但在早期的变体中,您需要使用fp.clear()清除流错误位。

  • 如果你没有用C++11进行编译,auto关键字可能不会起到你认为的作用,请小心。您可能还需要考虑const auto&