作为示例,请考虑以下文件的示例:
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;
}
答案 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
(或非零)用于异常情况。
除非你真的需要,否则不要使用\n
和endl
,我不认为这是一个案件。
考虑重新排序您的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&
。