需要帮助用c ++加载简单的文本数据

时间:2011-11-27 10:58:40

标签: c++ file-io codeblocks

我需要帮助将自定义文件格式加载到我用c ++编写的程序中... 我知道有一种简单的方法可以做到这一点,但我想我正在使用它 错误的条款在线搜索...

我的3d对象自定义格式如下:

NumVerts 6
//verts (float)
-1
-1
0
1
-1
0
-1
1
0
1
-1
0
1
1
0
-1
1
0
//texture (float)
0
0
1
0
0
1
1
0
1
1
0
1
//index (int)
0
1
2
1
3
2

这是一个四核......(是的;我知道......可怕的格式......但它是我用于安卓游戏的东西)。

我想在c ++中为我的编辑器(SDL + OpenGL for windows)创建一个函数,将这些文件加载​​到数据中...不幸的是,虽然我知道如何用C ++导出这种格式,但我无法弄清楚如何导入它们...我希望使用fstream命令...

如果有人能够快速写出一个简单的版本,我会非常感激。

我只是做以下事情:

  • 从输入字符串中查找文本文件
  • 读取“NumVerts”并获取其后写的整数
  • 循环显示下一行(NumVerts * 3)并将每个数字作为一个浮点数
  • 循环播放下一行(NumVerts * 2)并将每个数字作为浮点数
  • 循环显示下一行(NumVerts * 1)并将每个数字作为Int
  • 获取
  • (跳过任何以“//”开头的行)
  • 关闭文件。

感谢您阅读,现在任何帮助都会非常好......或者是一个非常简单的重用链接,从文件中读取字符串并从中获取数字以放入内存...

我真的只想完成这个游戏,并且试图找到有用的教程时会非常紧张。

更新:更新了脚本......我意外地忘了分开1和0 ...

4 个答案:

答案 0 :(得分:2)

希望这会有所帮助。顺便提一下,你的顶点组件数量是错误的 - 你需要18个。

#include <algorithm>
#include <exception>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;

int load_3d_object(const std::string& filename,
                   std::vector<float>& vertComponents,
                   std::vector<float>& texComponents,
                   std::vector<int>& indices)
{
    std::ifstream fs(filename.c_str());
    std::string line;
    if(!std::getline(fs, line))
    {
        throw std::runtime_error("The input file is empty");
    }

    if(line.substr(0,8) != "NumVerts")
    {
        throw std::runtime_error("The first line must start with NumVerts");
    }

    // Extract the number of vertices.
    int numVerts = lexical_cast<int>(line.substr(line.find(' ') + 1));

    // Read in the vertex components, texture components and indices.
    while(std::getline(fs, line))
    {
        boost::trim(line);
        if(line.substr(0,2) == "//") continue;

        if((int)vertComponents.size() < numVerts * 3)       vertComponents.push_back(lexical_cast<float>(line));
        else if((int)texComponents.size() < numVerts * 2)   texComponents.push_back(lexical_cast<float>(line));
        else                                                indices.push_back(lexical_cast<int>(line));
    }

    return numVerts;
}

int main()
{
    std::vector<float> vertComponents;
    std::vector<float> texComponents;
    std::vector<int> indices;
    try
    {
        int numVerts = load_3d_object("input.txt", vertComponents, texComponents, indices);
    }
    catch(std::exception& e)
    {
        std::cout << e.what() << '\n';
    }
    return 0;
}

答案 1 :(得分:1)

希望这可能会有所帮助(最小的错误检查):

int _get_num_verts_value(std::ifstream& a_in)
{
    char buf[128];
    int result = -1;
    a_in.getline(buf, sizeof(buf));
    while (a_in.good())
    {
        if (a_in.gcount() > 9)
        {
            string s(buf);
            if (0 == s.find("NumVerts "))
            {
                result = atoi(s.substr(8).c_str());
                break;
            }
        }
        a_in.getline(buf, sizeof(buf));
    }
    return result;
}

template <typename T>
void _get_values(std::ifstream& a_in, std::vector<T>& a_values)
{
    char buf[128];
    a_in.getline(buf, sizeof(buf));
    int i = 0;
    while (a_in.good())
    {
        string line(buf);
        if (0 != line.find("//"))
        {
            a_values[i++] = boost::lexical_cast<T>(line);
            // All read ?
            if (i == a_values.capacity())
            {
                break;
            }
        }
        a_in.getline(buf, sizeof(buf));
    }
}

int main(int /*a_argc*/, char** /*a_argv*/)
{
    ifstream in("test.txt");
    const int num_verts_value = _get_num_verts_value(in);

    std::vector<float> verts(num_verts_value * 3);
    _get_values<float>(in, verts);

    std::vector<float> textures(num_verts_value * 2);
    _get_values<float>(in, textures);

    std::vector<int> indexes(num_verts_value);
    _get_values<int>(in, indexes);

    in.close();

    return 0;
}

答案 2 :(得分:0)

为此目的使用平面文件可能是一个坏主意。它非常脆弱。我更喜欢二进制文件或自描述文件(例如xml)。

std::ifstream in("in");
char buf[256];
std::string line;
int NumVerts;
in >> buf >> NumVerts;
std::vector<float> verts(NumVerts * 3);
std::getline(in, line);//read the rest of the line
std::getline(in, line);//skip the comment line
std::for_each(verts.begin(), verts.end(), [&in](float& par){
    in >> par;
});
std::vector<float> texture(NumVerts * 2);
std::getline(in, line);//read the rest of the line
std::getline(in, line);//skip the comment line
std::for_each(texture.begin(), texture.end(), [&in](float& par){
    in >> par;
});
std::vector<int> index(NumVerts);
std::getline(in, line);//read the rest of the line
std::getline(in, line);//skip the comment line
std::for_each(index.begin(), index.end(), [&in](int& par){
    in >> par;
}); 

答案 3 :(得分:0)

关于如何DIY的链接:

示例代码:

#include <string>
#include <iostream> // needed for printing stuff out
#include <fstream>  // Needed to read the file
#include <stdexcept>
#include <vector>

using namespace std;

struct Vertice {
    double x,y,z; // 3 part stuff to read
    double a,b;   // 2 part stuff to read
    int i;        // 1 int thing to read
};

/// Reads a number ignoring comment lines (and any other line that isn't a number)
template <typename T>
T readNumber(istream& data) {
    char lastChar;
    while (data.good()) {
        data >> lastChar; // Don't use peek as that won't skip whitespace
        data.putback(lastChar);
        if (( (lastChar >= '0') && (lastChar <= '9') ) || (lastChar == '-')) {
            // If we're looking at a number read and return it
            T result;
            data >> result;
            return result;
        } else {
            // If it's not part of a number .. assume it's a comment line and skip the whole line
            string commentLine;
            getline(data, commentLine);
            // TODO: Maybe just skip '//' lines and throw an exception for everything else..
        }
    }
    throw exception("Couldn't read file");
}

double readDouble(istream& data) { return readNumber<double>(data); }
int readInt(istream& data) { return readNumber<int>(data); }

int main(int argc, char** argv) {
    if (argc != 2) 
        cout << "Usage: " << argv[0] << " [DATA_FILE_NAME]" << endl;
    else {
        fstream data(argv[1], ios_base::in);
        data >> skipws; // Skip whitespace
        string lastString;
        long numVerts = -1;
        // Read in words ignoring everything until we hit a 'NumVerts'
        while (numVerts < 0) {
            data >> lastString;
            if (lastString == "NumVerts")
                data >> numVerts;
        }
        // We know how many to get now
        typedef vector<Vertice> Verts;
        Verts verts(numVerts);
        // Read in the triples
        for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) {
            i->x = readDouble(data);
            i->y = readDouble(data);
            i->z = readDouble(data);
        }
        // Read in the pairs (some other data)
        for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) {
            i->a = readDouble(data);
            i->b = readDouble(data);
        }
        // Read in the single integer value
        for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) {
            i->i = readInt(data);
        }
        // Print out all we found
        for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) {
            cout << "Vertice" << endl
                 << "  x: " << i->x << endl
                 << "  y: " << i->y << endl
                 << "  z: " << i->z << endl
                 << "  a: " << i->a << endl
                 << "  b: " << i->b << endl
                 << "  i: " << i->i << endl
                 << endl;
        }

    }

}

示例代码在提供的文件上引发错误,因为没有足够的数据来填写'NumVerts'。

相关问题