只有你足够强,别人才会和你讲道理。
文章: 280
浏览: 2,994,482
  • 博主:笨木头
  • 关注:Unity、Net Core、Blazor
  • 邮箱:musicvs@163.com
笨木头  2017-06-11 11:08     Unity3D     阅读(4202)     评论(2)
转载请注明,原文地址: http://www.benmutou.com/archives/2337
文章来源:笨木头与游戏开发
转载请注明,原文地址:http://www.benmutou.com/archives/2337
文章来源:笨木头与游戏开发
 
CSV文件的读取是非常简单的,本篇木头就给CSV新手简单又详细地吹吹水,阿不是,详细地聊聊如何读取CSV文件。
 

1. 创建CSV文件

首先,用Ron's Editor创建一个新的CSV文件,不要问我怎么创建,这个常识大家应该有。
 
或者用记事本新建一个文本文件,然后把后缀改为.CSV,不改也行,这个不影响。
然后点击【文件】->【另存为】,编码选择UTF-8。(Ron's Editor不需要这么做)


然后给CSV文件随便输点内容,比如:


文件内容是这样的:
ID,Name
1,笨木头与游戏开发
2,www.benmutou.com
3,转载请注明出处
你也可以直接下载木头的CSV文件: CSVDemo
 
最后将CSV文件放到Unity项目的Assets\StreamingAssets目录下,千万记住,这一步不能忘记,否则无法读取文件。
 

2. 读取文件,保存成一行行的字符串

 我的读取方式是, 把文件按行读取,然后再解析每一行的内容,最终以行为单位,保存CSV文件。
 
先来解决读取文件的问题,如下代码:
[cce_cs]
/* CSV文件路径 */
string filePath = Application.streamingAssetsPath + "/CSVDemo.csv";

/* 读取CSV文件,一行行读取 */ string[] fileData = File.ReadAllLines(filePath); [/cce_cs]
CSV文件需要放在StreamingAssets目录下(可以有子目录)才能被成功读取,为什么要这么做?
有兴趣的可以看看我这篇文章:http://www.benmutou.com/archives/2094
言归正传,Application.streamingAssetsPath会自动帮我们组合正确的路径(自动根据PC、手机平台组合路径),让我们可以正确地找到StreamingAssets目录下的文件。
而File.ReadAllLines自然不用解释了,用于读取文件,并且按行读取,保存为string字符串数组。
CSV文件刚好又是按行保存的,这样解析起来会方便很多。

3. Key字段行和数据行

我们再来回忆一下CSV文件的内容:
ID,Name
1,笨木头与游戏开发
2,www.benmutou.com
3,转载请注明出处
文件的第一行是什么?是每一列数据的字段名,当然,文件内容是我们自己定义的,只是一般情况下第一行都是字段行。
Ron's Editor默认也是这么做的。
从第二行开始就真正的数据行了,我们来试试读取字段,并输出内容:
[cce_cs]
        /* CSV文件路径 */
        string filePath = Application.streamingAssetsPath + "/CSVDemo.csv";

  /* 读取CSV文件,一行行读取 */   string[] fileData = File.ReadAllLines(filePath);

  /* CSV文件的第一行为Key字段,先读取key字段 */   string[] keys = fileData[0].Split(',');

  /* 第二行开始是数据 */   for (int i = 1; i < fileData.Length; i++)   {   /* 每一行的内容都是逗号分隔,读取每一列的值 */   string[] lineData = fileData[i].Split(',');   for (int j = 0; j < lineData.Length; j++)   {   Debug.Log("key:" + keys[j] + ",value:" + lineData[j] + "\n");   }   } [/cce_cs]
代码解释如下:
a. 文件第一行是key字段,每个字段都是由逗号分割,所以string[] keys = fileData[0].Split(',');就能读取所有的key字段,后续需要根据key字段获取每列的数据内容;
b. 从第二行开始是数据内容,我们再次用逗号分割,这样就能获取到某一行的每一列的内容:string[] lineData = fileData[i].Split(',');
c. keys数组和lineData数据的长度一定相同的,所以,第二个for循环就能把某一行的数据内容和key字段对应起来;
输出的日志如下:
可能解释得有点混乱,这段代码总的作用就是,把key字段,和每一行的数据对应起来。
这有什么作用?等会就知道了。
 

4. 与CSV文件对应的类

为了把CSV文件保存起来,我们需要有一个类,这个类的结构与CSVDemo.csv文件要完全对应。
如下代码所示:
[cce_cs]
public class CSVDemo
{
    public int ID { get; set; }
    public string Name { get; set; }
}
[/cce_cs]
接下来就要用到这个类了,以后每次修改CSVDemo.csv文件的结构时(比如再加几个字段),那么,CSVDemo类也要做相应的修改。
确实有点麻烦,这也是木头这套CSV读取工具唯一麻烦的地方。

5. 保存CSV文件为对象

既然key字段和value字段的关系已经能确定了,那要保存起来就很简单了,如下代码:
[cce_cs]
        /* CSV文件路径 */
        string filePath = Application.streamingAssetsPath + "/CSVDemo.csv";

  /* 读取CSV文件,一行行读取 */   string[] fileData = File.ReadAllLines(filePath);

  /* 把CSV文件按行存放,每一行的ID作为key值,内容作为value值 */   Dictionary<int, CSVDemo> csvDataDic = new Dictionary<int, CSVDemo>();

  /* CSV文件的第一行为Key字段,先读取key字段 */   string[] keys = fileData[0].Split(',');

  /* 第二行开始是数据 */   for (int i = 1; i < fileData.Length; i++)   {   /* 每一行的内容都是逗号分隔,读取每一列的值 */   string[] lineData = fileData[i].Split(',');

  /* CSVDemo类与CSVDemo.csv文件的key字段一一对应,用于保存每一行的数据内容 */   CSVDemo csvDemo = new CSVDemo();   for (int j = 0; j < lineData.Length; j++)   {   if(keys[j] == "ID")   {   csvDemo.ID = Convert.ToInt32(lineData[j]);   }   else if(keys[j] == "Name")   {   csvDemo.Name = lineData[j];   }   }

  /* 保存每一行ID和数据对象的关系 */   csvDataDic[csvDemo.ID] = csvDemo;   } [/cce_cs]
大部分代码是和之前一样的,主要做了以下修改:
a. 创建了一个Dictionary<int, CSVDemo> csvDataDic变量,这个变量是为了把CSV文件保存起来,以便随时获取;
b. 在第二个for循环中,给每一行都创建了一个CSVDemo对象,然后根据key值来给该对象赋值;
c. 最后把每一行 CSVDemo对象都保存到csvDataDic变量中,以ID作为key值。
最后来测试一下:
[cce_cs]
        /* 测试读取ID为1的数据 */
        CSVDemo csvDemo1 = csvDataDic[1];
        Debug.Log("ID=" + csvDemo1.ID + ",Name=" + csvDemo1.Name);
[/cce_cs]
尝试获取ID为1的那一行数据,输出日志如下:
成功了,非常完美,啦啦啦。(旁白:突然这么不严肃,真的好么?)

6. 结束

对于新手而言,到目前为止已经足够了,我也不建议新手继续往下看。
先这么用着,等你觉得烦了,不想再这么用if条件一个个key值判断了,想要把代码变得更美丽一些,扩展性更好一些。
那么,这个时候的你,就应该往下看了。
木头会用神奇的方式把那些烦人的步骤去掉,让你再也想不起来。
 
2 条评论
  • xx 2020-09-17 17:03:20

    请问为什么csv要放在streamingAssets下不放在resources下来读取呢?
    0回复
    • 博主 笨木头 2020-09-18 08:29:47

      这个,我在这篇文章有解释:http://www.benmutou.com/archives/2094
      0回复
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发