cocos2d-x学习笔记——Csv文件读取工具

一个游戏中,通常会有很多怪物,以及怪物的生命值,魔法值等属性数据,这些数据不可能在代码里面写死,一般都会用配置文件来保存,使用时再加载到内存。

我们常用的配置文件是CSV文件,即逗号分隔值(Comma-Separated Values),如下图所示。

今天,我就来介绍一个来读取CSV文件的工具类——MyCsvUtil

在接受读取CSV文件工具类之前,先介绍一个读取字符串的工具类——StringUtil

//头文件StringUtil.h

#ifndef __StringUtil_H_
#define __StringUtil_H_
#include "cocos2d.h"

class StringUtil : public cocos2d::Ref
{
public:
    static StringUtil * getInstance();
    virtual bool init();

    //用分隔符分割字符窜,结果存放到一个列表中,列表中的对象为Value
    cocos2d::ValueVector split(const char * srcStr, const char * sSep);
private:
    static StringUtil * m_StringUtil;//Util 是工具的意思!
};

//函数实现文件
#include "StringUtil.h"
USING_NS_CC;

//初始化
StringUtil * StringUtil::m_StringUtil = nullptr;

StringUtil * StringUtil::getInstance()
{
    if (m_StringUtil == nullptr)
    {
        m_StringUtil = new StringUtil();
        if (m_StringUtil && m_StringUtil->init() )
        {
            m_StringUtil->autorelease();
            m_StringUtil->retain();
        }
        else
        {
            CC_SAFE_DELETE(m_StringUtil);
            m_StringUtil = nullptr;
        }
    }
    return m_StringUtil;
}

bool StringUtil::init()
{

    ////拆分字符串
    //auto strsList = StringUtil::getInstance()->split("zhaolong,want,to,work!",",");
    //for (auto str : strsList)
    //{
    //  log("str = %s",str.asString().c_str());
    //}

    return true;
}

//分离函数,srcStr是要进行分离的字符串,sSep是分隔符 separator
ValueVector StringUtil::split(const char * srcStr, const char * sSep)
{
    ValueVector stringList; //typedef std::vector<Value> ValueVector;
    int size = strlen(srcStr);
    //将数据转换为字符串对象
    Value str = Value(srcStr);
    int startIndex = 0;
    int endIndex = 0;
    endIndex = str.asString().find(sSep);

    std::string lineStr;
    //根据分隔符拆分字符串,并添加到列表中
    while (endIndex > 0)
    {
        //拆分的字符串
        //substr函数的作用是从给定的字符表达式或备注字段中返回一个子字符串。
        lineStr = str.asString().substr(startIndex,endIndex);
        //放入列表中
        stringList.push_back(Value(lineStr));

        //更新要分离的字符串
        str = Value(str.asString().substr(endIndex + 1,size));
        //更新索引号
        endIndex = str.asString().find(sSep);
    }
    //剩下的字符串也添加进入列表
    //将剩下的字符串与空字符串相比,若不为空
    if (str.asString().compare("") != 0)
    {
        //就把该字符串放入到列表中
        stringList.push_back(Value(str.asString()));
    }
    return stringList;
}
#endif

上面那个字符串工具类,最主要的就是一个split函数,因为已经写了足够多的注释了,这里就不再多做解释了。以后要进行字符串读取的话只需要将这个头文件包含进去,再调用split函数就行了。

下面开始讲解真正的Csv文件读取类

我们要想更好的处理和保存csv文件数据,我们应该把它当作对象来处理,新建一个CsvData类,他的类对象就代表一份Csv文件数据。

//头文件CsvData.h
#ifndef __CsvData_H_
#define __CsvData_H_
#include "cocos2d.h"

class CsvData : public  cocos2d::Ref
{
public:
    CREATE_FUNC(CsvData);
    virtual bool init();

    //添加一行数据
    void addLineData(cocos2d::ValueVector lineData);
    //获取某行的数据
    cocos2d::ValueVector getSingleLineData(int iLine);
    //获取行列大小
    cocos2d::Size getRowColNum();

private:
    //用来存放Csv文件所有行的数据
    cocos2d::ValueVector m_allLinesVec;
};

//函数实现文件
#include "CsvData.h"
USING_NS_CC;
bool CsvData::init()
{
    return true;
}

void CsvData::addLineData(ValueVector lineData)
{
    m_allLinesVec.push_back(Value(lineData));
}

ValueVector CsvData::getSingleLineData(int iLine)
{
    return m_allLinesVec.at(iLine).asValueVector();
}

Size CsvData::getRowColNum()
{
    Size size = Size();
    //获得Csv文件的行数,因为m_allLinesVec变量保存的就是每一行的数据,所以m_allLinesVec的大小就是行的数量
    size.width = m_allLinesVec.size();
    //如果Csv文件中的行数大于0
    if (size.width > 0)
    {
        //就求Csv文件第0行的数据的个数,得到列的数量
        size.height = m_allLinesVec.at(0).asValueVector().size();
    }

    return size;
}
#endif

这个CsvData类比较简单,不必多说了,只需要注意的是getRowColNum这个函数。这个函数是获取Csv文件的规模,即行数和列数(行号和列号都是从0开始的)。

因为Csv文件保存的就是每一行的数据,所以Csv的size大小就是行的数量,要求列数的话,就求Csv文件第0行的数据的个数,得到列的数量。

然后,然后就是真正的编写Csv文件读取工具类啦!

//头文件MyCsvUtil.h
#ifndef __MyCsvUtil_H_
#define __MyCsvUtil_H_
#include "CsvData.h"

class MyCsvUtil : public cocos2d::Ref
{
public:
    static MyCsvUtil * getInstance();
    virtual bool init();

    //加载配置文件
    void loadFile(const char * sPath);
    //获取某行某列的值
    cocos2d::Value getValue(int iRow, int iCol, const char * csvFilePath);
    //获取值并转化为字符串
    const std::string getStr(int iRow, int iCol, const char * csvFilePath);
    //获取值并转换为整形
    const int getInt(int iRow, int iCol, const char * csvFilePath);
    //获取文件的行和列的数量
    const cocos2d::Size getFileSize(const char * csvFilePath);

private:
    static MyCsvUtil * ms_CsvUtil;
    cocos2d::Map<std::string, CsvData *> m_CsvMap;
};

#endif

//函数实现文件
#include "MyCsvUtil.h"
#include "StringUtil.h"
USING_NS_CC;

MyCsvUtil * MyCsvUtil::ms_CsvUtil = nullptr;

MyCsvUtil * MyCsvUtil::getInstance()
{
    if (ms_CsvUtil == nullptr)
    {
        ms_CsvUtil = new MyCsvUtil();
        if (ms_CsvUtil && ms_CsvUtil->init() )
        {
            ms_CsvUtil->autorelease();
            ms_CsvUtil->retain();
        }
        else
        {
            CC_SAFE_DELETE(ms_CsvUtil);
            ms_CsvUtil = nullptr;
        }
    }
    return ms_CsvUtil;
}

bool MyCsvUtil::init()
{
    if (!TBack::init())
    {
        return false;
    }
    return true;
}

//加载文件
void MyCsvUtil::loadFile(const char * sPath)
{
    //存放一个csv文件的对象
    CsvData * csvData = CsvData::create();
    //读取路径所在文件的数据,保存到列表中
    std::string str = FileUtils::getInstance()->getStringFromFile(sPath);
    //将得到的数据按换行符分开,放到列表中
    ValueVector linesList = StringUtil::getInstance()->split(str.c_str(),"\n");
    //把每一行的字符拆分开来(按都好分隔)
    for (auto value : linesList)
    {
        //将一行的字符串按逗号分隔,然后存放到列表中,最后将列表存放到CsvData对象里
        //换句话说,csvData将成为一个二维表格,记录了配置文件行和列的字符串
        ValueVector tArr = StringUtil::getInstance()->split(value.asString().c_str(),",");
        csvData->addLineData(tArr);
    }
    //将CsvData对象添加到字典里
    m_CsvMap.insert(sPath,csvData);
}

//获取文件规格
const Size MyCsvUtil::getFileSize(const char * csvFilePath)
{
    //取出配置文件的二维表格
    auto csvData = m_CsvMap.at(csvFilePath);
    //如果配置文件不存在,则加载配置文件
    if (csvData == nullptr)
    {
        loadFile(csvFilePath);
        csvData = m_CsvMap.at(csvFilePath);
    }
    //调用了csvData类的函数
    Size size = csvData->getRowColNum();
    return size;
}

//获取文件某行某列
Value MyCsvUtil::getValue(int iRow, int iCol, const char * csvFilePath)
{
    auto csvData = m_CsvMap.at(csvFilePath);
    if (csvData == nullptr)
    {
        loadFile(csvFilePath);
        csvData = m_CsvMap.at(csvFilePath);
    }
    //获取第iRow行数据
    ValueVector rowVector = csvData->getSingleLineData(iRow);
    //获取第iCol列数据
    Value colValue = rowVector.at(iCol);

    return colValue;
}

//获取文件某行某列并转换为字符串
const std::string MyCsvUtil::getStr(int iRow, int iCol, const char * csvFilePath)
{
    Value val = Value();
    val = getValue(iCol,iCol,csvFilePath);
    return val.asString();
}

//获取文件某行某列并转换为整型
const int MyCsvUtil::getInt(int iRow, int iCol, const char * csvFilePath)
{
    Value val = Value();
    val = getValue(iRow,iCol,csvFilePath);
    return val.asInt();
}

最后,我们就可以在其他的程序里面包含这个Csv文件读取工具类的头文件,就可以使用它了。

这是我在调试模式下测试的结果:

#include "MyCsvUtil.h"

/*------测试代码段-------*/

const char * sPath = "monster.csv";//文件路径
MyCsvUtil::getInstance()->loadFile(sPath);//加载文件
//获得第1行第1列数据
Value firstMonsterName = MyCsvUtil::getInstance()->getValue(1,1,sPath);
//获得第2行第1列数据
Value secMonsterName = MyCsvUtil::getInstance()->getValue(2,1,sPath);
//打印结果
log("%s",firstMonsterName.asString().c_str());
log("%s",secMonsterName.asString().c_str());

输出结果:

时间: 2024-10-20 19:26:20

cocos2d-x学习笔记——Csv文件读取工具的相关文章

CSVFileUtil 读取写入CSV文件简单工具类

参考github大神源码 总结一下最简单的工具类记录一下 /** * @description CSV文件读取和输出 工具类.<br/> * @author michael * @date 2019/05/16 * @version Copyright (c) 2019, [email protected] All Rights Reserved. */ public class CSVFileUtil { private static final Logger LOGGER = Logger

Linux 程序设计学习笔记----POSIX 文件及目录管理

转载请注明:http://blog.csdn.net/suool/article/details/38141047 问题引入 文件流和文件描述符的区别 上节讲到ANSI C 库函数的实现在用户态,流的相应资源也在用户空间,但无论如何实现最终都需要通过内核实现对文件的读写控制.因此fopen函数必然调用了对OS的系统调用.这一调用在LINUX下即为open, close, read, write等函数.这些都遵循POSIX标准. so,在linux系统中是如何通过POSIX标准实现对文件的操作和目

python学习笔记九——文件与目录

1.python进行文件读写的函数是open或file类 mode:r  只读 r+   读写 w  写入,先删除原文件,再重新写入,如果文件没有则创建 w+  读写,先删除原文件,再重新写入,如果文件没有则创建(可写入和输出) a  写入,在文件末尾追加新的内容,文件不存在则创建 a+  读写,在文件末尾追加新的内容,文件不存在则创建 b  打开二进制文件,可与r,w,a,+结合使用 U  支持所有的换行符号,"\r","\n","\r\n"

树莓派学习笔记——使用文件IO操作GPIO SysFs方式

0 前言 本文描述如果通过文件IO sysfs方式控制树莓派 GPIO端口.通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction和value等,direction控制GPIO方向,而value可控制GPIO输出或获得GPIO输入. Linux学习可从应用出发,先不纠结Linux驱动编写,先把Linux给玩起来. [相同与不同] 本文和[EasyARM

CSV文件读取,解决汉字乱码

public String getDeptOuId(String openId) throws IOException { String deptId = ""; // 存储信息的文件的绝对路径  String csvPath = FileUtil.getWorkingPath()  .resolve(ConfigUtil.getConfig().get("idmappings")).toString(); System.out.print(csvPath); //

Linux System Programming 学习笔记(八) 文件和目录管理

1. 文件和元数据 每个文件都是通过inode引用,每个inode索引节点都具有文件系统中唯一的inode number 一个inode索引节点是存储在Linux文件系统的磁盘介质上的物理对象,也是LInux内核通过数据结构表示的实体 inode存储相关联文件的元数据 ls -i 命令获取文件的inode number /* obtaining the metadata of a file */ #include <sys/types.h> #include <sys/stat.h>

CSV文件读取类

最近项目中,经常需要读取Csv文件.基本步骤是: (1)按行读取 (2)然后将一行数据按逗号,分割为字符串数组 (3)将各列字符串转换成相应类型的数据 ,如int double类型 写了一个简单的Csv文件读取类,方便使用,可以按列名或列索引读取数据.将字符串转换成数字变量使用的是stringstream类. 如下: #ifndef CSV_READER_H_ #define CSV_READER_H_ #include <vector> #include <map> #inclu

APUE 学习笔记(二) 文件I/O

1. 文件I/O 对于内核而言,所有打开的文件都通过文件描述符引用,内核不区分文本文件和二进制文件 open函数:O_RDONLY  O_WRONLY  O_RDWR create函数: close函数:关闭一个文件时还会释放该进程加在该文件上的所有记录锁 lseek函数:显式地为一个打开的文件设置其偏移量 每个打开的文件都有一个与其相关联的 "当前文件偏移量",用以度量从文件开始处计算的字节数,通常,读.写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数 文件偏移量可以大于

学习笔记_springmvc文件上传和拦截器

文件上传 用到这两个包 配置视图解析器:springmvc配置文件配置 <!-- id必须要是"multipartResolver" --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- maxUploadSize文件上传的最大值,单位是byte