使用lua-cmsgpack序列化和反序列化lua对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用lua-cmsgpack序列化和反序列化lua对象相关的知识,希望对你有一定的参考价值。

参考技术A lua-cmsgpack是一个开源的MessagePack实现方式、纯C的库,没有任何其它依赖,编译后可以直接被lua调用,目前主要支持Lua 5.1/5.2/5.3 版本。
1、什么是MessagePack?

官方的解释是:

跟JSON及其类似,但是比JSON更快并且占用空间更小,举个官方给出的例子,直接截官方图:

翻译官方的解释:
MessagePack是一种高效的二进制序列化格式, 它允许在多种语言(如JSON)之间交换数据,但它越来越小, 小整数被编码为单个字节,典型的短字符串除了字符串本身之外还需要一个额外的字节。

目前市面上流行的开发语言MessagePack几乎支持,官方的地址为: http://msgpack.org/Lua MessagePack也提供了一套开源库,地址在: https://github.com/fperrad/lua-MessagePack/ 。

但是,作者使用的是lua-cmsgpack,至于哪个比较优异,作者还没有去比较,主要是先发现了lua-cmsgpack,后面看了下README文件,使用方法应该是差不多的,大家可以拿来参考。

lua-cmsgpack包括官方提供的lua-MessagePack都需要自行编译,因为可能平台太多,所以官方没有为每一个平台提供编译好的版本。lua-cmsgpack的github地址为: https://github.com/antirez/lua-cmsgpack
git clone下来之后需要安装cmake工具,mac平台直接在项目目录:

即可,当然需要预先安装lua,并且是5.1版本以上的。

主要说下CentOS平台下cmake可能会出现的问题,如果cmake的过程出现以下错误:

出现以上错误的话,需要自行安装lua的一些依赖库,一般:

就可以了,如果还不行,再试试下面的命令:

编译完成之后会生成cmsgpack.so文件,使用的时候直接require进去即可

运行效果:

cmsgpack.pack()可以把多个lua对象序列化成一个二进制msgpack,执行反序化的时候会返回对应数量的lua对象,非常的方便。

有趣的是redis也支持MessagePack,因此结合lua和lua-cmsgpack可以产生不错的化学反应,下面是一个简单的例子(结合OpenResty):

测试返回结果:

在某些场合还是有不错应用场景的。

使用和反序列化 FileStreamResult Blazor

【中文标题】使用和反序列化 FileStreamResult Blazor【英文标题】:Consume and Deserialize FileStreamResult Blazor 【发布时间】:2020-10-31 06:38:04 【问题描述】:

我有一个控制器端点,它提供如下文件;

    [HttpGet]
    [ProducesResponseType(typeof(FileStreamResult), 200)]
    [Route("documentId")]
    public IActionResult GetDocumentImage(int documentId)
    
        var response = _service.Get(documentId);

        HttpAssert.Success(response);
        HttpAssert.IsNotNull(response);

        Stream stream = new MemoryStream(response.Result.Data);

        if (stream == null)
            return NotFound();

        return File(stream, response.Result.MimeType); 
    

当在img 标签上设置为src 时效果很好,并且可以确认文件正在成功发送。

我想在 blazor razor 页面中使用结果。我使用

反序列化调用
var responseContent = await response.Content.ReadAsStringAsync();

if (response.IsSuccessStatusCode)

 var result = JsonConvert.DeserializeObject<T>(responseContent);
 return new ServiceResponse<T>  Result = result, HasError = false, HttpErrorCode = -1, Error = null ;

但是,当我反序列化为object(使用JsonConvert.DeserializeObject&lt;T&gt;(responseContent))时

当我调试并尝试在我得到的监视窗口中进行评估时,抛出没有 ex.Message 的错误

'解析值时遇到意外字符:%。路径'',第 0 行,位置 0。'

这种情况下的返回是一个 PDF 文件。谁能指导我哪里出错了?

【问题讨论】:

【参考方案1】:

正如 TomTom 所说,您不能将 PDF 转换为 json,PDF 不像文本或 json 文件。

所以在 Blazor 中,您必须按照以下方式进行操作。

当您从端点取回结果时,它将是一个流。因此,您可以执行以下操作来获取stream from the endpoint:

var fileStream = new FileStream()

    Stream = await httpResponseMessage.Content.ReadAsStreamAsync(),
    Filename = $"someFile.pdf"
;

获取文件流后,你必须convert it to byte:

byte[] bytes;
using (var memoryStream = new System.IO.MemoryStream())

    fileStream.Stream.CopyTo(memoryStream);
    bytes = memoryStream.ToArray();

一旦你将它保存在字节数组中,它现在是数组格式,我们现在可以通过用户浏览器使用和下载它。您必须创建以下 js 以触发 Blazor 中的浏览器下载

这里我们基本上是在 HTML DOM 中创建一个锚点并触发一个点击事件(source):

var saveAsFile = function (filename, bytesBase64) 
    var link = document.createElement('a');
    link.download = filename;
    link.href = "data:application/octet-stream;base64," + bytesBase64;
    document.body.appendChild(link); // Needed for Firefox
    link.click();
    document.body.removeChild(link);

我们可以在 Blazor c# 代码中调用下面的代码并通过JSInterop 触发它

await JsRunTime.InvokeAsync<object>("saveAsFile", fileStream.Filename,
    Convert.ToBase64String(bytes));

【讨论】:

【参考方案2】:

啊,指出了明显的问题,但你已经告诉我们错了:

这种情况下的返回是一个PDF文件。

看,PDF 文件不是 JSON。

您尝试使用 JSON 转换器反序列化 PDF 文件:

var 结果 = JsonConvert.DeserializeObject(responseContent);

我不确定你从哪里得到这应该起作用的想法。 PDF 不是 JSON。哎呀,甚至“ReadAsStringAsync()”可能没有任何意义——我什至不确定 PDF 是否完全异步。它绝对不是 JSON。

【讨论】:

谢谢你,令人担忧的是我从来没有想过。那么我将如何将FileStreamResult 反序列化为对象甚至byte[] 从文档开始。我的意思是,您找到了 ReadAsString - 通过所有扩展方法找到将流作为字节数组读取的方法应该很简单。内容是一个流。流到字节数组 - 你基本上要求我为你阅读文档。永远不要那样做。【参考方案3】:

类似于Umair's answer,您可以这样做,而不是创建一个新的 FileStream 和一个新的 MemoryStream:

using var streamReader = new StreamReader(await httpResponseMessage.Content.ReadAsStreamAsync());
var fileString = await streamReader.ReadToEndAsync();
var bytes = Encoding.ASCII.GetBytes(fileString);

然后还是按照 Umair 的示例 JS Blazor 触发代码调用 saveFileAs 和 InvokeAsync。

【讨论】:

以上是关于使用lua-cmsgpack序列化和反序列化lua对象的主要内容,如果未能解决你的问题,请参考以下文章

使用循环序列化和反序列化图形

使用 Gson 序列化和反序列化枚举 [重复]

Dubbo中Map类型默认的序列化和反序列化

关于使用XmlSerializer 序列化和反序列化的问题?

39.使用序列化和反序列化

认识k_BackingField,微软自己的序列化和反序列化