使用C/ c++正确读取文件格式



如何使用C或c++读取一个简单的文件格式?

例如,以Wavefront .obj文件格式为例,示例:

# this is a box
o 1
v -0.5 -0.5 0.5
v -0.5 -0.5 -0.5
v -0.5 0.5 -0.5
v -0.5 0.5 0.5
v 0.5 -0.5 0.5
v 0.5 -0.5 -0.5
v 0.5 0.5 -0.5
v 0.5 0.5 0.5
usemtl Default
f 4 3 2 1
f 2 6 5 1
f 3 7 6 2
f 8 7 3 4
f 5 8 4 1
f 6 7 8 5

由于文件可能相当大,我创建了一个带有操作符[]的中间类(FileBuffer)。它在内存中只有4096字节的文件,并在需要时读取新的部分。文件格式非常简单,但我不喜欢使用flex/bison之类的格式。这只会使事情复杂化。

解释这个(类型)文件的合适方法是什么?目前我有很多嵌套的for/while循环和许多计数器跟踪。还有许多switch/elseif语句。如何使这些代码易于维护,并且总体上更加结构化?

谢谢。

如果是我,我会尽可能多地利用标准库:

struct Command { /* Abstract Base Class */ ... };
struct VCommand : Command { std::vector<double> dims; ... }
struct FCommand : Command { std::vector<int> vertexes; ... }
struct FootCommand : Command { enum {LEFT, RIGHT, IN, OUT} e; ... }
std::vector<Command*> commandList; // DANGER: raw pointers
void ParseInput(std::istream& in) {
    // untested code:
    std::string line;
    while(getline(in, line)) {
        std::stringstream lineStream(line);
        std::string command;
        lineStream >> command;
        if(command == "v") {
            std::istream_iterator<double>(lineStream) begin;
            std::istream_iterator<double> end;
            // Add the "v" command to the parse tree
            commandList.push_back(new VCommand(begin, end));
        } else if (command == "f") {
            std::istream_iterator<int>(lineStream) begin;
            std::istream_iterator<int> end;
            // Add the "v" command to the parse tree
            commandList.push_back(new FCommand(begin, end));
        } else if (command == "quit") {
            ...
        } else if (command == "put_your_left_foot_in") {
            ...
            commandList.push_back(new FootCommand(LEFT, IN));
        }
    }
}

如果我理解正确的话,每一行定义一种特定类型的数据,其类型由第一个确定词。我将首先定义一个抽象基类和类的具体实例,用于每行的类型;我在std::map<std::string, LineParser*>中注册这些实例。

为了读取文件,我可能会安装一个过滤流buf去掉上游的注释和空行。然后一个简单的循环就可以做到:

std::string line;
while ( std::getline( filteredInput, line ) ) {
    std::string keyword;
    std::istringstream toParse( line );
    toParse >> keyword;
    std::map<std::string, LineParser*>::const_iterator
        parser = registry.find( keyword );
    if ( parser == registry.end() ) {
        //  Syntax error: unknown keyword...
    } else {
        parser->parse( toParse );
    }
}

我将从定义(或获取)文件语法/结构开始。

然后根据该语法为输入流构建解析器。

相关内容

  • 没有找到相关文章