Xlua加载Lua文件失败

    今天在使用Xlua修改加载lua文件方式的时候碰到了lua文件第一行报错的问题。后来发现是由于Xlua加载使用字节流的方式,而自己的lua文件编码方式选择的是UTF-8 BOM导致的。


什么是BOM?

BOM: Byte Order Mark

UTF-8 BOM又叫UTF-8 签名,其实UTF-8 的BOM对UFT-8没有作用,是为了支持UTF-16,UTF-32才加上的

BOM,BOM签名的意思就是告诉编辑器当前文件采用何种编码,方便编辑器识别,但是BOM虽然在编辑器中不显示,但是会产生输出,就像多了一个空行。

Byte Order Marks are special characters at the beginning of a Unicode file to indicate whether it is big or little endian, in other words does the high or low order byte come first. These codes also tell whether the encoding is 8, 16 or 32 bit. You can recognise Unicode files by their starting byte order marks, and by the way Unicode-16 files are half zeroes and Unicode-32 files are three-quarters zeros. Unicode Endian Markers

Byte-order mark Description

EF BB BF UTF-8

FF FE UTF-16 aka UCS-2, little endian

FE FF UTF-16 aka UCS-2, big endian

00 00 FF FE UTF-32 aka UCS-4, little endian.

00 00 FE FF UTF-32 aka UCS-4, big-endian.

UTF的字节序和BOM

UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。

原来BOM是在文件的开始加了几个字节作为标记。有了这个标记,一些协议和系统才能识别。

关于字节序可以,点击查看 理解字节序


    所以碰到的问题就是xlua在加载lua文件字节流的时候前三位是 EF BB BF 导致无法无法加载成功,所以在unity editor下写了个小工具在导入lua脚本时自动检测脚本编码方式是否是UTF-8 BOM,如果是的话则自动转换成UTF-8。

using UnityEditor;
using UnityEngine;
using System.IO;
using System;

public class Importer : AssetPostprocessor
{

        //高版本可以使用OnPreprocessAsset代替 
        private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
        {
            //lua文件 UTF-8约束,如果是UTF-BOM则强行转换
            foreach (var path in importedAssets)
            {
                if (path.EndsWith(".lua"))
                {
                   ProcessLuaFiles(path);
                }
            }
        }

        private static void ProcessLuaFiles(string filePath)
        {
              byte[] bytes =  File.ReadAllBytes(filePath);
              if (bytes.Length >= 3)
              {
                  byte[] bom = new byte[] { 0xef, 0xbb, 0xbf };
                  if (bytes[0] == bom[0] && bytes[1] == bom[1] && bytes[2] == bom[2])
                      {
                         byte[] bytesUTF8 = new byte[bytes.Length-3];
                         Debug.LogFormat("检查到lua文件编码格式含有Bom,移除Bom -> {0}", filePath);
                         Buffer.BlockCopy(bytes, 3, bytesUTF8, 0, bytesUTF8.Length);
                         File.WriteAllBytes(filePath,bytesUTF8);
                      }
              }
        }
}

猜你喜欢

转载自blog.csdn.net/Lc_Snow/article/details/86623645