设置文件指针位置

时间:2015-09-02 09:42:41

标签: c++ file

  • 我有一个非常大的文本文件,其中包含许多以行排列的条目。
  • 每行的第一个单词就像一个" "为了我。该行的其他词是数字。
  • 一行中的第一个单词也可以存在于大量其他行中。

作为示例,请考虑以下文件的示例:

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

我的目标:

为所有" Associatives"," Disjunctives"进行一系列操作。和#34; Conjunctives"。该文件非常大,未进行排序。我可以使用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;

}       

2 个答案:

答案 0 :(得分:2)

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

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

另外,每次阅读后检查错误是个好主意:

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

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

答案 1 :(得分:1)

我还没有对您的代码进行过测试,但我建议您进行一些更改:

  • 我遇到的大多数操作系统都使用约定,对于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 ++ 11 seekg 即使在到达文件末尾之后运行正常,但在早期版本中您将需要清除流错误位使用fp.clear()

  • 如果您未使用C ++ 11进行编译,则auto关键字可能无法执行您认为的操作,请注意。您可能还想考虑const auto&