目录

问题缘由

背后原理

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. golang中关于死锁的思考与学习

    1.Golang中死锁的触发条件 1.1 书上关于死锁的四个必要条件的讲解 发生死锁时,线程永远不能完成,系统资源被阻碍使用,以致于阻止了其他作业开始执行.在讨论处理死锁问题的各种方法之前,我们首先深 ...

  2. MyBatisPlus--入门

    入门案例 MyBatisPlus(MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发.提高效率. 1.新建springboot项目(版本2.5.0),仅保留JDBC 添加mybatis ...

  3. 一篇文章带你了解Java中的运算符

    前言 在前一篇文章中,壹哥给大家讲解了Java数据类型之间的转换,包括自动类型转换.强制类型转换.隐含的强制类型转换等问题.且在上一篇文章中,我还简单地给大家提到了Java的类型提升.在类型提升的案例 ...

  4. Spring事务的底层原理

    1. 划分处理单元--IOC 由于spring解决的问题是对单个数据库进行局部事务处理的,具体的实现首相用spring 中的IOC划分了事务处理单元.并且将对事务的各种配置放到了ioc容器中(设置事务 ...

  5. Solr 入门配置

    大多数搜索引擎应用都必须具有某种搜索功能,问题是搜索功能往往是巨大的资源消耗,并且它们由于沉重的数据库加载而拖垮你的应用的性能.这就是为什么转移负载到一个外部的搜索服务器是一个不错的注意,Apache ...

  6. Quicker快速开发,简单的网页数据爬取(示例,获取天眼查指定公司基础工商数据)

    前言 有某个线上项目,没有接入工商接口,每次录入公司的时候,都要去天眼查.企查查或者其他公开数据平台,然后手动录入,一两个还好说,数量多了的重复操作就很烦,而且,部分数据是包含超链接,一不注意就点进去 ...

  7. JSON 与 Java 对象之间的转化

    前言 在现在的日常开发中,不管前端还是后端,JSON 格式的数据是用得比较多的,甚至可以说无处不在. 接触最多的就是 POST 请求中传递的数据一般以 JSON 的格式放在请求体中,而且服务端各种 A ...

  8. 深入理解 python 虚拟机:令人拍案叫绝的字节码设计

    深入理解 python 虚拟机:令人拍案叫绝的字节码设计 在本篇文章当中主要给大家介绍 cpython 虚拟机对于字节码的设计以及在调试过程当中一个比较重要的字段 co_lnotab 的设计原理! p ...

  9. flutter系列之:在flutter中使用相机拍摄照片

    目录 简介 使用相机前的准备工作 在flutter中使用camera 总结 简介 在app中使用相机肯定是再平常不过的一项事情了,相机肯定涉及到了底层原生代码的调用,那么在flutter中如何快速简单 ...

  10. Django之时区修改

    修改时区方法 环境:windows10 修改settings.py文件,修改TIME_ZONE和USE_TZ参数 TIME_ZONE = 'Asia/Shanghai' USE_TZ = False