我有一个数据文件“records.txt”,其格式如下:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
const string record1("records.txt");
// declaring a struct for each record
struct record
{
int number; // number of record
vector<int> content; // content of record
};
int main()
{
record batch_1; // stores integers from 1 - 64
record batch_2; // stores integers from 65 - 128
record temp;
string line;
// read the data file
ifstream read_record1(record1.c_str());
if (read_record1.fail())
{
cerr << "Cannot open " << record1 << endl;
exit(EXIT_FAILURE);
}
else
cout << "Reading data file: " << record1 << endl;
cout << "Starting Batch 1..." << endl;
read_record1.open(record1.c_str());
while(getline(read_record1, line))
{
stringstream S;
S << line; // store the line just read into the string stream
vector<int> thisLine; // save the numbers read into a vector
for (int c = 0; c < 33; c++) // WE KNOW THERE WILL BE 33 ENTRIES
{
S >> thisLine[c];
cout << thisLine[c] << " ";
}
for (int d = 0; d < thisLine.size(); d++)
{
if (d == 0)
temp.number = thisLine[d];
else
temp.content.push_back(thisLine[d]);
cout << temp.content[d] << " ";
}
if (temp.number == 1)
{
batch_1.content = temp.content;
temp.content.clear();
}
thisLine.clear();
}
// DUPLICATE ABOVE FOR BATCH TWO
return 0;
}
每行以一个或两个开头,表示它属于哪个批次。我试图使用字符串流来读取每一行并将结果存储在结构中,第一个数字对应于批号,后面的32个整数对应于内容,属于结构向量。我一直在努力与此斗争,我按照这里找到的解决方案:How to read line by line
结果程序如下:
Starting Batch 1...
程序编译并以返回值0运行,但循环中的cout语句不执行,因为唯一的控制台输出是:
{{1}}
此外,如果代码重复批次2,我会遇到分段错误。很明显,这是行不通的。我不太熟悉阅读字符串,所以任何帮助都会受到赞赏。另外,如果行没有等量的条目(例如,一行有33个条目,另一行有15个条目),我该怎么办?
答案 0 :(得分:1)
您的代码存在许多问题:
您正在打开输入文件两次。没什么大不了的,但也不可取。如果您将文件名传递给std::ifstream
构造函数,它会立即打开文件,因此之后无需再调用open()
。
在for
循环的第一个while
循环内,您尝试使用thisLine
直接将整数读取到本地operator>>
向量中,但这样做会因为你还没有为thisLine
的数组分配任何内存,所以无法正常工作。由于您需要33个整数,因此可以在读取之前预先分配数组:
vector<int> thisLine(33);
或者:
vector<int> thisLine;
thisLine.resize(33);
但是,既然你也问过单独行有不同整数的可能性,你根本不应该预先调整向量的大小,因为你还不知道整数的数量(虽然你可以预先分配如果你知道你可能期望的最大整数数,那么向量的容量。您可以使用while
循环而不是for
循环,这样您就可以读取整个std::stringstream
,无论它实际拥有多少整数:
thisLine.reserve(33); // optional
int c;
while (S >> c) {
thisLine.push_back(c);
}
在第二个for
循环中,您正在访问temp.content[d]
,但如果d
为0,那么temp.content
可能尚未填充,因此访问{ {1}}无效(如果您使用了temp.content[0]
,则会遇到temp.content.at(d)
例外)。你可能想做更像这样的事情:
std::out_of_range
但即使这样也可以通过完全删除for (int d = 0; d < thisLine.size(); d++)
{
if (d == 0)
temp.number = thisLine[d];
else {
temp.content.push_back(thisLine[d]);
cout << thisLine[d] << " ";
}
}
循环来简化:
push_back()
您循环遍历整个文件一次,读取所有记录但只处理批处理1记录。您说您有一组重复的循环来处理批次2记录。这意味着您将再次重新读取整个文件,重新读取所有记录但忽略批处理1记录。这是很多浪费的开销。您应该读取文件一次,根据需要分离批次,然后在读取循环结束时处理它们,例如:
if (thisLine.size() > 0)
{
temp.number = thisLine[0];
thisLine.erase(thisLine.begin());
}
temp.content = thisLine;
for (int d = 0; d < thisLine.size(); d++)
cout << thisLine[d] << " ";
因此,如上所述,更正后的代码应该更像这样:
vector<record> batch_1; // stores integers from 1 - 64
vector<record> batch_2; // stores integers from 65 - 128
record temp;
...
while(getline(read_record1, line))
{
...
if (temp.number == 1) {
batch_1.push_back(temp);
} else {
batch_2.push_back(temp);
}
}
// process batch_1 and batch_2 as needed...
然后你可以通过完全摆脱#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
const string records_file("records.txt");
// declaring a struct for each record
struct record
{
int number; // number of record
vector<int> content; // content of record
};
int main()
{
vector<record> batch_1; // stores integers from 1 - 64
vector<record> batch_2; // stores integers from 65 - 128
record temp;
string line;
// read the data file
ifstream read_records(records_file.c_str());
if (read_records.fail())
{
cerr << "Cannot open " << records_file << endl;
exit(EXIT_FAILURE);
}
cout << "Reading data file: " << records_file << endl;
cout << "Starting Batch 1..." << endl;
while (getline(read_records, line))
{
istringstream S(line); // store the line just read into the string stream
vector<int> thisLine; // save the numbers read into a vector
thisLine.reserve(33); // WE KNOW THERE WILL BE 33 ENTRIES
int c;
while (S >> c) {
thisLine.push_back(c);
cout << c << " ";
}
temp.number = 0;
temp.content.reserve(thisLine.size());
for (int d = 0; d < thisLine.size(); d++)
{
if (d == 0)
temp.number = thisLine[d];
else
temp.content.push_back(thisLine[d]);
}
/* alternatively:
if (thisLine.size() > 0) {
temp.number = thisLine[0];
thisLine.erase(thisLine.begin());
}
temp.content = thisLine;
*/
if (temp.number == 1) {
batch_1.push_back(temp);
}
temp.content.clear();
}
read_records.seekg(0);
cout << "Starting Batch 2..." << endl;
// DUPLICATE ABOVE FOR BATCH TWO
read_records.close();
// process batch_1 qand batch_2 as needed...
return 0;
}
向量来简化你的阅读循环:
thisLine
然后,如果您如此倾向,可以使用std::copy()
代替std::istream_iterator
和std::back_insertor
来进一步简化代码:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
const string records_file("records.txt");
// declaring a struct for each record
struct record
{
int number; // number of record
vector<int> content; // content of record
};
int main()
{
vector<record> batch_1; // stores integers from 1 - 64
vector<record> batch_2; // stores integers from 65 - 128
record temp;
string line;
// read the data file
ifstream read_records(records_file.c_str());
if (read_records.fail())
{
cerr << "Cannot open " << records_file << endl;
exit(EXIT_FAILURE);
}
cout << "Reading data file: " << records_file << endl;
cout << "Starting Batch 1..." << endl;
while (getline(read_records, line))
{
istringstream S(line); // store the line just read into the string stream
if (S >> temp.number)
{
cout << temp.number << " ";
temp.content.reserve(32); // WE KNOW THERE WILL BE 32 ENTRIES
int c;
while (S >> c) {
temp.content.push_back(c);
cout << c << " ";
}
if (temp.number == 1) {
batch_1.push_back(temp);
}
temp.content.clear();
}
}
read_records.seekg(0);
cout << "Starting Batch 2..." << endl;
// DUPLICATE ABOVE FOR BATCH TWO
read_records.close();
// process batch_1 qand batch_2 as needed...
return 0;
}
答案 1 :(得分:-4)
您是否查找了std::getline
的{{3}}?我不相信它会像您似乎假设的那样返回bool
。看起来它会返回std::istream&
。惊讶它编译,必须做一些奇怪的隐式转换。