Unity使用INIParser读写ini配置文件出现中文乱码问题的解决方法

👉一、前言

项目中常常会遇到读写配置文件的需求,考虑到轻量化的问题,采取了读写ini配置文件的方法。
在这里插入图片描述

为了方便,我找来了一个可以读写ini文件的第三方插件【Advanced INI Parser】,却发现读写的过程中出现了中文乱码的情况,一开始我也以为是插件库对中文不友好的原因。于是我把ini文件的编码改为UTF-16 LE(原来是ANSI),发现可以解决读写中文乱码的问题。但是后来考虑到项目里的这个ini配置文件多平台都有使用到,如果把它改了另外的编码,其他平台读写后又将它改为原来的ANSI编码,那Untiy端又会出现读写中文乱码的情况了。本来都要打算放弃这个插件库读写ini文件的方案了,后来经过阅读INIParser的源码后,才了解了它读写ini文件的原理和为什么会出现中文乱码的问题。说明阅读源码的还是能帮助我们找到解决方法的,那解决方法就得从插件本身下手了。

👉二、中文乱码问题出现、INIParser读写原理及解决方法

1、搭建demo还原读写ini出现中文乱码场景

The First.demo场景:

在这里插入图片描述
功能:点击读取按钮,读取指定路径下的配置文件,显示到Text组件上;在输入框里输入一组键值数据,写入到ini文件中。

The Second.配置文件内容:
在这里插入图片描述

The Third.写脚本实现以上的功能逻辑:

using UnityEngine;
using UnityEngine.UI;

public class ReadWriteINI : MonoBehaviour
{
    private string iniPath;//指定路径的ini文件
    public Text showText;//显示ini文件的信息文本
    public Button readBtn;
    public InputField writeInput;
    void Start()
    {
        iniPath = Application.dataPath + "/Data/Application.ini";
        readBtn.onClick.AddListener(OnReadINI);//读写ini文件
        writeInput.onEndEdit.AddListener(OnWriteINI);//结束编辑写入ini文件
    }
    /// <summary>
    /// 读取ini文件
    /// </summary>
    private void OnReadINI()
    {
        INIParser ini = new INIParser();//声明一个解析ini文件的iniparser对象
        ini.Open(iniPath);//打开ini文件
        showText.text = ini.ToString();//显示ini文件的内容
        ini.Close();//关闭文件读取
    }
    /// <summary>
    /// 写入ini文件
    /// </summary>
    /// <param name="value"></param>
    private void OnWriteINI(string value)
    {  
        if (!string.IsNullOrEmpty(value))
        {
            INIParser ini = new INIParser();
            ini.Open(iniPath);
            string[] strs = value.Split('=');//输入的字符串以=分割,缓存到字符串数组
            if (strs.Length>1)
            {
                ini.WriteValue("Unity", strs[0], strs[1]);//将数据写入到 Unity节点下
            }
            ini.Close();
        }
    }
}

The Fourth. 读取ini文件运行结果:
在这里插入图片描述
读取出现中文乱码,但源文件没有乱码;

The Fifth.写入ini文件运行结果:
在这里插入图片描述
写入那组中文数据没有乱码,但是源文件内容出现乱码。

刚开始觉得有点奇怪,不是只写入了一组键值而已吗,为什么原来的内容会出现乱码呢?
这是为什么呢?让我们阅读INIParser源码一探究竟。

2、INIParser读写ini文件原理及乱码问题说明

在这里插入图片描述

仔细阅读源码就不难发现:INIParser对象打开ini文件读取时使用了I/O数据流技术File.ReadAllText(). 一次性先将ini文件内容全部读取到内存中缓存到m_iniString中。File.ReadAllText()如果没有指定编码格式读取,就默认是UTF-8编码读取,我的ini文件是ANSI编码格式的,如果使用UTF-8读取肯定是会出现中文乱码的;同理INIParser对象写入ini文件时,其实是先修改了内存中的m_iniString字符串,然后再使用==File.WriteAllText(). 一次性将修改后的m_iniString内容写入到ini文件。由于它也没有指定编码格式,所以默认以UTF-8编码写入ini文件,并将ini文件改为UTF-8编码格式的文件,也就造成了原内容中文乱码,写入那部分内容正常显示中文。了解原理之后我就很快找到了解决方法。

3、解决方法

其实File.ReadAllText()和File.WriteAllText()还有另一个重载方法是可以指定编码格式进行读写文件的。所以我们只需要将INIParser脚本里读写ini文件的方法指定为所需编码格式进行读写,就不会出现中文乱码的问题了。
在这里插入图片描述
由于我的配置文件默认就是ANSI格式了,所以我需要将读写ini文件都改为ANSI格式。而Encoding.Default 就是我项目当前.NET平台默认的ANSI格式,所以将其作为形参传入到File.ReadAllText()和File.WriteAllText()方法里。

修改后运行的读写ini结果:
在这里插入图片描述
可以看到读取时使用ANSI编码不会出现乱码,写入后ini文件还是原来的ANSI编码,所以也不会出现中文乱码的情况了,至此Unity使用INIParser读写ini配置文件出现中文乱码问题得以解决。

4、友情提示:谨慎使用Encoding.Default !!!

可能大家看到我这里使用Encoding.Default用来处理ANSI编码的文件,就以为Encoding.Default就是表示ANSI的,其实不是的。是因为我知道我当前项目的.net平台默认代码页的编码是ANSI,所以使用Encoding.Default来指定读写ini文件。在你不了解你当前.net平台默认编码时,为了避免使用Encoding.Default出现乱码,尽量谨慎使用Encoding.Default!!!因为这与你当前Unity版本选择的脚本运行.NET平台有关:(可以在PlayerSetting/OhterSetting查看,不同的计算机可以使用不同的编码作为默认编码)
在这里插入图片描述

本人实践发现:.net2.0和.net3.5平台下Encoding.Default均表示ANSI编码,.net4.x表示UTF-8编码
所以建议大家在读写文件时使用指定编码格式的方法。

比如指定ANSI编码可以这么写:

            Encoding winLatinCodePage = Encoding.GetEncoding("gb2312");//传入字符串GBK也可以
            m_iniString = File.ReadAllText(m_FileName, winLatinCodePage);//winLatinCodePage就表示ANSI编码

大家可以去了解一点C#中Encoding类编码的知识

👉三、学点额外的知识点

1、INIParser插件的简单使用说明

使用流程:

        INIParser ini = new INIParser();//1.声明INIParser对象
        ini.Open(iniPath);//2.打开指定路径的ini文件,进行读取操作,如果没有会创建新文件
        ini.ReadValue(...);ini.WriteValue(...);//3.调用ini读写的api,进行读写操作。
        ini.Close();//4.读写完成之后关闭文件读写操作,保存文件

常用API:
public string ReadValue(string SectionName, string Key, string DefaultValue)
从本地缓存读取值,读取SectionName(指定节点)下的key(指定键)的值,如果没有则返回DefaultValue(默认值)。

public void WriteValue(string SectionName, string Key, string Value)
在本地缓存中插入或修改一个值,写入SectionName(指定节点)下的key(指定键)和value(指定值),如果存在该节点和键值,则修改;否则是添加该节点和键值到文件中。

其实这个插件就一个脚本,如果有读写ini文件的话推荐大家使用,源码看上去也比较容易理解,插件也带有使用文档,大家可以去研究学习一下。

2、Unity中使用Encoding类的学习

1.Encoding类位于System.Text命名空间中,下面两个表格是Encoding类的常用属性和方法:

属性说明
Default获取当前代码页.NET 平台实现的默认编码。
Unicode表示使用Little-Endian字节顺序的UTF-16格式的编码
UTF-8表示UTF-8格式的编码
UTF-7表示UTF-7格式的编码
ASCII表示ASCII(7位)字符集的编码
UTF32表示使用 Little-Endian 字节顺序的 UTF-32 格式的编码
BigEndianUnicode表示使用 Big Endian 字节顺序的 UTF-16 格式的编码。
方法说明
Convert将字节数组从一种编码转换为另一种编码
GetBytes将一组字符编码为一个字节数组
GetString将一个字节数组解码为一个字符串
GetEncoder获取一个编码器,该编码器将Unicode字符序列转为已编码的字节序列
GetDecoder获取一个解码器,该解码器将已编码的字节序列转为字符序列
GetEncoding返回指定格式的编码

2.利用Encoding类的Convert方法可将字节数组从一种编码转换为另一种编码。方法原型为:
Public static byte[]Convert(Encoding srcEncoding,Encoding dstEncoding,byte[]bytes)
各参数含义如下。
srcEncoding:表示源编码格式。
dstEncoding:表示目标编码格式。
Bytes:待转换的字节数组。
返回值为包含转换结果的Byte类型的数组。

3.调用以下方法可以指定编码字符串转为目标字符串


        /// <summary>
        /// 将返回指定编码的字符串转为目标编码的字符串
        /// </summary>
        /// <param name="src">源编码</param>
        /// <param name="dst">目标编码</param>
        /// <param name="text">传入的字符串</param>
        /// <returns></returns>
        public static string EncodingConvert(Encoding src, Encoding dst, string text)
        {
            var bytes = src.GetBytes(text);//获取指定编码的字符串转换的字节数组
            bytes = Encoding.Convert(src, dst, bytes);//将源编码字节数组转为目标编码字节数组
            return dst.GetString(bytes);//返回目标编码字节数组转换的字符串
        }

👉四、插件的获取方法

1.直接打开 Window/Asset Store 搜【INIParser】,插件是开源免费的,直接下载导入即可。
在这里插入图片描述

2.iniparser插件下载

3.可以留言或私信我发给你😀

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周周的Unity小屋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值