2012-07-13 78 views
1

我想爲Wavefront OBJ文件格式,純文本文件編寫解析器。 示例可以在這裏看到:people.sc.fsu.edu/~jburkardt/data/obj/diamond.obj。逐行解析緩衝數據

大多數人使用舊scanf函數解析一行此行的格式,但我寧願加載整個文件一次,以減少IO操作次數。有沒有辦法逐行解析這種緩衝數據?

void ObjModelConditioner::Import(Model& asset) 
{ 
    uint8_t* buffer = SyncReadFile(asset.source_file_info()); 

    delete [] buffer; 
} 

或者將整個文件加載到一個字符串並試圖解析它?

+0

什麼格式的輸入文字? CSV? XML? YAML? – 2012-07-13 14:15:55

+0

這是Wavefront OBJ文件,純文本文件。例如:http://people.sc.fsu.edu/~jburkardt/data/obj/diamond.obj – Martin 2012-07-13 14:21:51

回答

4

經過一段時間似乎我找到了足夠的(和簡單的)解決方案。由於我的目標是創建資產調節管道,因此代碼必須能夠高效地處理大量數據。數據可以一次讀入string,一旦加載,stringstream可以用這個字符串初始化。

std::string data; 
SyncReadFile(asset.source_file_info(), data); 

std::stringstream data_stream(data); 
std::string line; 

然後我只需撥打getline()

while(std::getline(data_stream, line)) 
{   
    std::stringstream line_stream(line); 
    std::string type_token; 

    line_stream >> type_token; 
    if (type_token == "v") { 
     // Vertex position 
     Vector3f position; 
     line_stream >> position.x >> position.y >> position.z; 
     // ... 
    } 
    else if (type_token == "vn") { 
     // Vertex normal 
    } 
    else if (type_token == "vt") { 
     // Texture coordinates 
    } 
    else if (type_token == "f") { 
     // Face 
    } 
} 
2

這裏的一個分割字符數組成字符串的向量的函數(假設每個新的字符串「\ N」符號開始):

#include <iostream> 
#include <vector> 

std::vector<std::string>split(char * arr) 
{ 
    std::string str = arr; 
    std::vector<std::string>result; 
    int beg=0, end=0;//begining and end of each line in the array 
    while(end = str.find('\n', beg + 1)) 
    { 
     if(end == -1) 
     { 
      result.push_back(str.substr(beg)); 
      break; 
     } 
     result.push_back(str.substr(beg, end - beg)); 
     beg = end; 
    } 
    return result; 
} 

這裏的用法:

int main() 
{ 
    char * a = "asdasdasdasdasd \n asdasdasd \n asdasd"; 
    std::vector<std::string>result = split(a); 
} 
1

如果你已經得到了一個char[](或一個unsigned char[])和 的原始數據,你知道它的長度,只寫入一個輸入是非常簡單的,沒有尋求 支持streambuf這將允許你創建一個n std::istream 並使用std::getline就可以了。請致電:

setg(start, start, start + length); 

在構造函數中。 (閒來無事是必要的。)

1

這真的取決於你如何去分析文本。一種方法是將數據讀入一個字符串向量中。我會假設你已經涵蓋如可擴展性/使用內存等

std::vector<std::string> lines; 
std::string line; 
ifstream file(filename.c_str(), ios_base::in); 
while (getline(file, line)) 
{ 
    lines.push_back(line); 
} 
file.close(); 

這將緩存文件中lines問題。接下來你需要通過線

for (std::vector<std::string>::const_iterator it = lines.begin(); 
     it != lines.end(); ++it) 
{ 
    const std::string& line = *it; 
    if (line.empty()) 
     continue; 

    switch (line[0]) 
    { 
     case 'g': 
      // Some stuff 
      break; 
     case 'v': 
      // Some stuff 
      break; 
     case 'f': 
      // Some stuff 
      break; 
     default: 
      // Default stuff including '#' (probably nothing) 
    } 
} 

當然,這是非常簡單化,很大程度上取決於你想要用你的文件做什麼。

你已經作爲例子給出的文件的大小是不大可能造成IO壓力(除非你使用一些非常輕便的設備),但如果你正在讀許多文件一次,我想這可能是一個問題。

我覺得這裏的問題是,以儘量減少IO,我不知道這解決方案將真正幫助那麼多,因爲你將要遍歷集合兩次。 如果您需要回去並保持在讀取相同的文件,一遍又一遍的話,那肯定會加快速度,在內存中緩存文件,但也有同樣簡單的方式來做到這一點,如內存映射文件和使用正常的文件訪問。如果你真的擔心,那麼嘗試分析這樣的解決方案,避免在從IO讀取時直接處理文件。