当文件的数量少于预期时,正确处理输入

时间:2016-04-26 17:38:02

标签: c++ file io

我正在尝试读取每行3个浮点数的文件。现在,我将其实现为:

std::ifstream inFile(inName.c_str());
if (!inFile) {
    prterr("in ASCII file could not be opened!\n");
    return -1;
}

std::vector<double> xData, yData, zData;
xData.resize(nPoints);
yData.resize(nPoints);
zData.resize(nPoints);
inFile.precision(std::numeric_limits<double>::digits10+1);

for (int i = 0; i < nPoints; ++i) {
    inFile >> xData[i] >> yData[i] >> zData[i];
    inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

即使用户每行输入的数字超过3个,程序也会成功运行。但是,有时用户尝试以每行<3个数字运行程序。发生这种情况时,解析器显然会错误地存储数据。

我想(a)如果文件每行少于3个数字,则抛出错误,或(b)仅存储前N个数字如果文件中仅存在每行N个数字,则在它们各自的向量中行。诀窍是,我想尽快做到这一点,因为我的数据集可以是几GB。 我可以保证我的文件每行的数字数量完全相同。

是否有一种优雅而有效的方式来执行(b)?我知道我可以通过在for循环之前单独读取第一行作为字符串来实现(a),但这看起来非常难看。有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

我知道你不想在第一行读作std::string,但是你需要找到有多少空格分隔的列,不幸的是换行被视为空格。如果你可以这样做,那么你可以看到你的男人专栏

std::ifstream inFile(inName.c_str());
std::vector<int> columns_in_file;
std::string temp;
std::getline(inFile, temp);
std::stringstream ss(temp);
int number;
while (ss >> number)
    columns_in_file.push_back(number);

然后我们需要做的是设置一个具有正确列数和行数的二维矢量。

// get number of columns.  3 max
int columns = columns_in_file.size() <= 3 ? columns_in_file.size() : 3;
std::vector<std::vector<int>> data(nPoints, std::vector<int>(columns));
// now we add the data we already read
for (int i = 0; i < columns; i++)
    data[0][i] = columns_in_file[i];

现在我们有一个与文件大小相同的向量,除非该文件有超过3列并且其中包含第一行数据。现在我们有决定,因为你只需要打电话

inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

在阅读columns_in_file.size() > 3时,如果不需要,我们不想调用它。我们可以在两个不同的函数中使用读取代码,也可以在else if语句中使用两个不同的块。后者是我将展示的,但知道你可以将它重构为函数调用。所以要实际读取文件,我们会有像

这样的东西
if (columns <= 3)
{
    for (int i = 0; i < nPoints; i++)
    {
        for(int j = 0; j < columns; j++)
        {
            infile >> data[i][j];
        }
    }
}
else
{
    for (int i = 0; i < nPoints; i++)
    {
        for(int j = 0; j < columns; j++)
        {
            infile >> data[i][j];
            inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
    }
}

答案 1 :(得分:2)

您可以在读取第一组值时,首先获取文件中的列数,作为字符串,然后在第一个for循环中使用count和另一个循环:

[ EDIT ]根据给出的评论(并且学习再次继续),您可以根据可用列调整所有向量的大小,而不是最初调整所有向量。这样可以避免不必要的空间消耗。

std::vector<double> Data[3];//the x,y,z data set(Assuming the maximum number of columns can't be >3)
//you can decide which of the vectors(x,y,z) are used by looking at the column count

inFile.precision(std::numeric_limits<double>::digits10+1);

int count=0;//count the number of columns
string first_line;
double temp;

getline(inFile,first_line);
istringstream ss(first_line);

while(ss>>temp && count<3)
{
    Data[count].resize(nPoints);
    Data[count][0]=temp;
    count++;
}

for(int i=1; i<nPoints&& inFile.peek() != EOF ; i++)
{
    for(int j=0;j<count;j++)
    {
        inFile>>temp;
        Data[j][i]=temp;
    }

    inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}