【踩坑记录】字节流数据按照string的方式读取然后按照string的方案存储,编码导致二进制数据发生变化,原理记录
目录
问题缘由
由于公司需求,需要读取游戏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的方案存储,编码导致二进制数据发生变化,原理记录的更多相关文章
- [19/05/07-星期二] JDBC(Java DataBase Connectivity)_CLOB(存储大量的文本数据)与BLOB(存储大量的二进制数据)
一. CLOB(Character Large Object ) – 用于存储大量的文本数据 – 大字段有些特殊,不同数据库处理的方式不一样,大字段的操作常常是以流的方式来处理的.而非一般的字段,一次 ...
- BLOB存储图片文件二进制数据是非对错
子在一天一天虚度,生活也在一天一天中茫然 做人做事哪能尽如人意,付出多少收获多少虽然存在偏颇,但是不劳而获的心态是万万不对的,更不能去怨天尤人,低调为人.做好自己就可以了 改进你的系统的最好的方法是先 ...
- vue+ vue-router + webpack 踩坑之旅
说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案 老司机可以忽略下面的内容了 1)起因 考虑到数据分离的问题 因为server是express搭的 自然少 ...
- 背水一战 Windows 10 (89) - 文件系统: 读写文本数据, 读写二进制数据, 读写流数据
[源码下载] 背水一战 Windows 10 (89) - 文件系统: 读写文本数据, 读写二进制数据, 读写流数据 作者:webabcd 介绍背水一战 Windows 10 之 文件系统 读写文本数 ...
- XML中二进制数据的处理方法
原文链接:http://www.west263.com/www/info/22308-1.htm 在xml中,所有的数据都是以文本的形式来显示,但是二进制数据不能直接以文本格式来表示,那xml又是怎么 ...
- Android学习笔记(十二)——使用意图传递数据的几种方式
使用意图传递数据的几种方式 点此获取完整代码 我们除了要从活动返回数据,也经常要传递数据给活动.对此我们能够使用Intent对象将这些数据传递给目标活动. 1.创建一个名为PassingData的项目 ...
- Erlang 位串和二进制数据
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=25876834&id=3300393 因为在本人工作中,服务端Erla ...
- 讨论贴:Sqlserver varbinary 是二进制数据,却是十六进制的表现形式
首先创建一个数据表 CREATE TABLE [dbo].[log_info]( [id] [,) NOT NULL, [info] [varchar]() NULL, [info1] [varbin ...
- 认识Js中的二进制数据
Blob 在项目中涉及到要对html原生的audio组件进行样式复写,因此需要重新实现audio的一些功能,比如下载.实现一个下载大致的思路是服务端返回一段音频的二进制数据,客户端将其存放在Blob中 ...
- 转载:【原译】Erlang构建和匹配二进制数据(Efficiency Guide)
转自:http://www.cnblogs.com/futuredo/archive/2012/10/19/2727204.html Constructing and matching binarie ...
随机推荐
- ZIP64压缩扩展的兼容性问题
一.ZIP压缩的两种规范 zip64 格式是标准 zip 格式的扩展,实际上消除了 zip 存档中文件大小和数量的限制. 每种格式允许的最大值总结如下: Standard Format Zip64 F ...
- Java面试——Nginx
一. 二.Nginx 的优点 [1]速度更快:这表现在两个方面:一方面,在正常情况下,单次请求会得到更快的响应:另一方面,在高峰期(如有数以万计的并发请求),Nginx 可以比其他 Web服务器更快地 ...
- JetBrains 2022全家桶-激活
## JetBrains 全家桶 激活教程 https://tech.souyunku.com/?page_id=50199
- PyQt5学习 (2)--QWidget(上)
描述: 1.所有可视控件的基类 2.是一个最简单的空白控件 3.控件时用户界面的最小元素:接收各种事件.绘制在桌面上,展示给用户看 4.每个控件都是矩形的,它们按Z轴顺序排序 5. ...
- 搭建私有YUM仓库_及_内网镜像站
搭建私有YUM仓库_及_内网镜像站 搭建私有YUM仓库(自己定制的rpm包)私有yum仓库环境系统版本:centos7.4 IP:192.168.1.47 #最好能上公网 私有yum仓库服务端配置 第 ...
- 快速部署Ceph分布式高可用集群
快速部署Ceph分布式高可用集群 Ceph简介 Ceph是一个PB,EB级别的分布式存储系统,可以提供文件存储,对象存储.和块存储,它可靠性高,易扩展,管理简便,其中对象存储和块存储可以和其他云平台集 ...
- pandas之sql操作
我们知道,使用 SQL 语句能够完成对 table 的增删改查操作,Pandas 同样也可以实现 SQL 语句的基本功能.本节主要讲解 Pandas 如何执行 SQL 操作.首先加载一个某连锁咖啡厅地 ...
- [云计算]杂谈:SaaS与PaaS的产品经理,做产品设计时有什么区别?[摘]
本文摘自: 郝雨彤@碧岸久 于 2022-09-20在社交平台中所表达的观点. 产品性质/类型 服务领域 服务对象(受众) 核心能力 SaaS 面向具体业务 (所属行业的)业务用户 很看重对业务的理解 ...
- 【LeetCode动态规划#06】分割等和子集(01背包问题一维写法实战)
分割等和子集 分割等和子集 给你一个 只包含正整数 的 非空 数组 nums .请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等. 示例 1: 输入:nums = [1,5,11,5 ...
- Mybatis 框架下 SQL 注入攻击的方式
前言 SQL注入漏洞作为WEB安全的最常见的漏洞之一,在java中随着预编译与各种ORM框架的使用,注入问题也越来越少. 新手代码审计者往往对Java Web应用的多个框架组合而心生畏惧,不知如何下手 ...