使用std :: ifstream读取.obj文件时的c ++无限循环

时间:2018-01-17 12:47:53

标签: c++ while-loop infinite-loop ifstream .obj

我正在用C ++编写一个光线跟踪器程序。该程序的一部分应该能够从mesh.obj文件中读取3D模型。

我目前在使用std::ifstream阅读文件时遇到问题。

我编写了一个函数read_mesh,它接受​​一个字符串参数,该参数指定用户给出的.obj文件的路径。该函数返回一个三角形基元列表,用于渲染网格。

我正在使用LOG(INFO) << "specific info";,以便我能够查看我的计划中发生了什么。

这是我的功能:

std::vector<Primitive> read_mesh(const std::string& path) const
    {
        LOG(INFO) << "Reading mesh";

        LOG(INFO) << "Attempting to open file at " << path;

        std::ifstream obj;

        obj.exceptions(std::ifstream::failbit | std::ifstream::badbit);

        // Open the file from the given path
        try {
            obj.open(path, ios::in);
        }
        catch (std::ifstream::failure::exception e) {
            LOG(INFO) << "Exception when opening file \n" << e.what();
        }

        LOG(INFO) << "File opened";

        // Initialize list of vertices
        std::vector<Point3D> vertices;

        // Initialize list of triangles
        std::vector<Primitive> triangles;

        std::string line;

        // Read each line of the .obj file
        while (std::getline(obj, line))
        {
            LOG(INFO) << "New line";

            std::istringstream iss(line);
            std::string method;

            // Extract the type of data from the line
            iss >> method;

            // Checks if the data on the line represents a vertex
            if (method == "v")
            {
                double x, y, z;

                // Extract the x, y and z coordinates from the line
                iss >> x >> y >> z;

                LOG(INFO) << "New vertex (" << x << ", " << y << ", " << z << ")";

                // Create a Point3D from the coordinates
                Point3D p(x, y, z);

                // Add the point to the list of vertices
                vertices.push_back(p);
            }

            // Checks if the data on the line represents a set of triangles
            else if (method == "f")
            {
                int a, b, c;
                char s;

                // Read the set of triangles from the polygon line with the index of the vertices seperated by a '/'
                while ((iss >> a >> s >> b >> s >> c) && s == '/')
                {
                    LOG(INFO) << "New triangle (v" << a << ", v" << b << ", v" << c << ")";

                    // Create a triangle from the corresponding vertices (index -1 because they start at 1 in .obj files) and add it to the triangles list
                    triangles.push_back(triangle(vertices[a - 1], vertices[b - 1], vertices[b - 1]));
                }
            }
            else
            {
                LOG(INFO) << "Ignored this line";
            }
        }
        if (!std::getline(obj, line))
        {
            LOG(INFO) << "Reached end of file";
        }

        obj.close();

        LOG(INFO) << "Finished reading mesh, " << triangles.size() << " triangles found";

        // Return the list of triangles
        return triangles;
    }

我可以看到每一行都被正确读取,在最后一行之后,不再读取任何行。但不是打印&#34;达到文件结束&#34;和#34;完成阅读网格,找到290个三角形&#34;,程序停止执行。

所以我认为问题在于程序从未真正退出while循环,尽管它会停止打印&#34;新行&#34;和&#34;到达行尾&#34;。

任何人都可以帮我找到这个功能的问题吗?非常感谢任何帮助,谢谢!

编辑:

以下示例应用程序使用与上述函数相同的功能:

int main()
{

std::ifstream obj;

obj.exceptions(std::ifstream::failbit | std::ifstream::badbit);

try {
    // Enter the path to the example.obj file
    obj.open("C:/Users/Bram/Desktop/example-obj.txt", ios::in);
}
catch (std::ifstream::failure::exception e) {
    std::cout << "Failed to open file";
    return(1);
}

std::cout << "Reading file";

std::string line;

while (std::getline(obj, line))
{
    std::cout << "New line";

    std::istringstream iss(line);
    std::string method;

    iss >> method;

    if (method == "v")
    {
        double x, y, z;

        iss >> x >> y >> z;

        std::cout << "New vertex (" << x << ", " << y << ", " << z << ")";
    }

    else if (method == "f")
    {
        int a, b, c;
        char s;

        while ((iss >> a >> s >> b >> s >> c) && s == '/')
        {
            std::cout << "New triangle using vertices " << a << ", " << b << ", " << c;
        }
    }
    else
    {
        std::cout << "Ignored line";
    }
}

std::cout << "Finished reading file";

obj.close();

return(0);
}

它读取以下示例-obj.txt文件,该文件代表一个三角形:

# example.obj

v  -7.8541 121.3862 17.1093
v  7.1431 113.8654 23.1824
v  15.3955 112.2824 13.7628

f  1/2/3

程序打印正确的顶点和三角形,并在执行时给出以下错误消息:

Unhandled exception at 0x75EA08B2 in meshreader.exe: Microsoft C++ exception: std::ios_base::failure at memory location 0x008FF3F0.

1 个答案:

答案 0 :(得分:0)

obj.exceptions(std::ifstream::failbit | std::ifstream::badbit);

这将设置流对象的内部状态,以便在I / O操作尝试设置其中任何一个位时抛出异常。

while (std::getline(obj, line))

这表示要保持循环,直到对std::getline的调用失败。通常这样做是因为在读取完最后一行之后调用std::getline时对std::getline的调用将失败。

但是在这种情况下,当尝试输入失败时,流已设置为抛出异常。因此循环不会正常终止,因为对std::getline的最终调用会引发异常。

如果删除设置流的行以抛出异常,那么事情将按照您期望的方式运行。