目录

问题缘由

背后原理

C#代码示例

总结


问题缘由

由于公司需求,需要读取游戏Redis数据做内外网数据迁移,没有与游戏组过多的沟通。  使用的数据类型是Hash, key是string,value是byte[]。以前对于编码的理解是:计算机底层存储的永远是01的二进制数据,编码是一种对于计算机二进制数据的字符映射,也就是约定好哪个值对应哪个字符。是为了便于在显示器上展示。

那么基于这个理解,我就以为 不需要关心存储的数据类型,因为我不需要用到数据,我只是负责做数据的搬运。于是我用的是HGetAsync方法去读的字符串。然后HSetAsync把数据存到另一个Redis。结果发现数据发生了编码。基于我上边对于编码的理解,也就是按照不同的编码读取字符串,只是显示器上会乱码,但是底层的01二进制没有发生变化,这次问题打破了我的认知。

背后原理

当一个byte[]在计算机中存储时,它就是以二进制形式保存的。如果这个byte[]中的每一个字节代表的是ASCII码(一个字节表示一个字符),那么它在不同的编码下读取应该没有问题。但是,如果它代表的是Unicode字符集(UTF-8和UTF-16等),那么在不同的编码下读取就会发生问题。因为不同的编码方式对存储方式和字节长度都有不同的要求。

以UTF-8为例,它对不同字符分配的位数不同。对于ASCII字符,UTF-8使用一个字节表示,而对于其他字符,它需要两个字节、三个字节或四个字节来表示。因此,在按照UTF-8格式读取一个byte[]时,如果它的编码确实是UTF-8,那么就可以读取正确的字符。但是,如果重新以UTF-8的格式存储它时,就会按照UTF-8的编码方式重新把这个字符转换成二进制。如果这个字符之前的编码不是UTF-8,那么它在转换为UTF-8的二进制时,就会变成不同的值,因此数据也就变了。

C#代码示例

var data = Encoding.UTF32.GetBytes("爱");
var word = Encoding.UTF8.GetString(data);
var word1 = Encoding.UTF32.GetString(data); File.WriteAllText($@"{AppDomain.CurrentDomain.BaseDirectory}/code.txt", word);
File.WriteAllText($@"{AppDomain.CurrentDomain.BaseDirectory}/code1.txt", word1); foreach (var d in File.ReadAllBytes($@"{AppDomain.CurrentDomain.BaseDirectory}/code.txt"))
{
Console.WriteLine(d);
}
Console.WriteLine("------------"); foreach (var d in File.ReadAllBytes($@"{AppDomain.CurrentDomain.BaseDirectory}/code1.txt"))
{
Console.WriteLine(d);
}
 

例如,我们有一个Unicode字符“爱”,其二进制表示为:0000 0100 1110 0111。按照UTF-8编码的规则,在存储这个字符时,我们需要使用3个字节的二进制数据:1110XXXX 10XXXXXX 10XXXXXX(X表示对应字符的二进制数据的高位)

我们将其存储到一个byte[]中,再将其存储到文件中。然后按照UTF-8的格式读取,解析出Unicode字符“爱”,再将其按照UTF-8的格式存储回文件。这时,由于使用了UTF-8编码,我们需要将Unicode字符“爱”转换为UTF-8编码的二进制数据,即,使用3个字节的二进制数据:11100100 10101110 10011111。

通过运行代码,可以看到,由于存储使用了UTF-8编码,而读取和重新存储又使用了UTF-8编码,因此二进制数据发生了变化。

总结

当一个byte[]在计算机中存储时,它就是以二进制形式保存的。如果这个byte[]中的每一个字节代表的是ASCII码(一个字节表示一个字符),那么它在不同的编码下读取应该没有问题。但是,如果它代表的是Unicode字符集(UTF-8和UTF-16等),那么在不同的编码下读取就会发生问题。

【踩坑记录】字节流数据按照string的方式读取然后按照string的方案存储,编码导致二进制数据发生变化,原理记录的更多相关文章

  1. [19/05/07-星期二] JDBC(Java DataBase Connectivity)_CLOB(存储大量的文本数据)与BLOB(存储大量的二进制数据)

    一. CLOB(Character Large Object ) – 用于存储大量的文本数据 – 大字段有些特殊,不同数据库处理的方式不一样,大字段的操作常常是以流的方式来处理的.而非一般的字段,一次 ...

  2. BLOB存储图片文件二进制数据是非对错

    子在一天一天虚度,生活也在一天一天中茫然 做人做事哪能尽如人意,付出多少收获多少虽然存在偏颇,但是不劳而获的心态是万万不对的,更不能去怨天尤人,低调为人.做好自己就可以了 改进你的系统的最好的方法是先 ...

  3. vue+ vue-router + webpack 踩坑之旅

    说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案   老司机可以忽略下面的内容了 1)起因  考虑到数据分离的问题  因为server是express搭的   自然少 ...

  4. 背水一战 Windows 10 (89) - 文件系统: 读写文本数据, 读写二进制数据, 读写流数据

    [源码下载] 背水一战 Windows 10 (89) - 文件系统: 读写文本数据, 读写二进制数据, 读写流数据 作者:webabcd 介绍背水一战 Windows 10 之 文件系统 读写文本数 ...

  5. XML中二进制数据的处理方法

    原文链接:http://www.west263.com/www/info/22308-1.htm 在xml中,所有的数据都是以文本的形式来显示,但是二进制数据不能直接以文本格式来表示,那xml又是怎么 ...

  6. Android学习笔记(十二)——使用意图传递数据的几种方式

    使用意图传递数据的几种方式 点此获取完整代码 我们除了要从活动返回数据,也经常要传递数据给活动.对此我们能够使用Intent对象将这些数据传递给目标活动. 1.创建一个名为PassingData的项目 ...

  7. Erlang 位串和二进制数据

    http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=25876834&id=3300393 因为在本人工作中,服务端Erla ...

  8. 讨论贴:Sqlserver varbinary 是二进制数据,却是十六进制的表现形式

    首先创建一个数据表 CREATE TABLE [dbo].[log_info]( [id] [,) NOT NULL, [info] [varchar]() NULL, [info1] [varbin ...

  9. 认识Js中的二进制数据

    Blob 在项目中涉及到要对html原生的audio组件进行样式复写,因此需要重新实现audio的一些功能,比如下载.实现一个下载大致的思路是服务端返回一段音频的二进制数据,客户端将其存放在Blob中 ...

  10. 转载:【原译】Erlang构建和匹配二进制数据(Efficiency Guide)

    转自:http://www.cnblogs.com/futuredo/archive/2012/10/19/2727204.html Constructing and matching binarie ...

随机推荐

  1. Markdown 的常用语法

    声明(叠甲):鄙人水平有限,本文章仅供参考. 且本文章是一个不全的分享,只有我目前用的比较多的语法,如果有什么错误,欢迎大家指正.具体可以查看该网站 写博客我使用的是 Markdown,为熟悉 Mar ...

  2. BUU-RE-刮开有奖-WinMain

    WinMain函数参数介绍 int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrev ...

  3. 任意Exe转ShellCode?

    之前写过一个远控,但一直在琢磨如何生成shellcode,今天偶然看见一个项目:sRDI,github上就有 这个项目主要就是将dll转成shellcode,于是我就想到了"写一个输出文件的 ...

  4. 在react中使用wangEditorV5

    wangEditor是基于JavaScript和css的一款web富文本编辑器,是国内比较好用的一款轻量级富文本编辑器,上手简单,易用且开源免费. 官方文档:http://www.wangeditor ...

  5. 从k8s 的声明式API 到 GPT的 提示语

    命令式 命令式有时也称为指令式,命令式的场景下,计算机只会机械的完成指定的命令操作,执行的结果就取决于执行的命令是否正确.GPT 之前的人工智能就是这种典型的命令式,通过不断的炼丹,告诉计算机要怎么做 ...

  6. 正则表达式、datetime

    1.正则表达式就是用来匹配字符串的 2.常用\d表示一个数字,\w表示数字或者字母,'.'表示任意字符 3.如果要匹配边长的字符串,使用*表示任意个字符,+表示至少一个字符,?表示0个或者1个字符,{ ...

  7. 服务器实现端口转发的N种方式

    简介 在一些实际的场景里,我们需要通过利用一些端口转发工具,比如系统自带的命令行工具或第三方小软件,来绕过网络访问限制触及目标系统.下文为大家总结了linux系统和windows系统端口转发常用的一些 ...

  8. opengauss配置远程白名单

    DB_VERSION:openGauss 3.0.3 1.允许192.168网段用户使用jack用户登陆 --创建只读账号 CREATE USER jack WITH MONADMIN passwor ...

  9. Hyperledger Fabric 使用 CouchDB 和复杂智能合约开发

    前言 在上个实验中,我们已经实现了简单智能合约实现及客户端开发,但该实验中智能合约只有基础的增删改查功能,且其中的数据管理功能与传统 MySQL 比相差甚远.本文将在前面实验的基础上,将 Hyperl ...

  10. [操作系统] - 进程切换&进程控制

    2.1.6 进程切换 名称解析 进程的上下文(Context) 当一个进程在执行时,CPU的所有寄存器的值.进程的状态以及堆栈中的内容被称为进程的上下文Context 进程的切换(switch) 当内 ...