一文让你读懂JAVA.IO、字符编码 - 51CTO

文章推薦指數: 80 %
投票人數:10人

用ByteArrayOutputStream暂时缓存来自其他渠道的数据 ByteArrayOutputStream data = new ... 如“程”的utf-8编码格式,由[-25][-88][-117]组成。

内容精选视频话题技术期刊技术大会社区编辑申请我关注的话题我收藏的文章账号设置退出 注册/登录一文让你读懂JAVA.IO、字符编码作者:JAVA互联搬砖工人2020-11-1209:14:25开发后端本篇给大家介绍JAVA.IO、字符编码,希望对你有所帮助。

 1JAVA.IO字节流 inputstream.png LineNumberInputStream和StringBufferInputStream官方建议不再使用,推荐使用LineNumberReader和StringReader代替 ByteArrayInputStream和ByteArrayOutputStream字节数组处理流,在内存中建立一个缓冲区作为流使用,从缓存区读取数据比从存储介质(如磁盘)的速率快 //用ByteArrayOutputStream暂时缓存来自其他渠道的数据 ByteArrayOutputStream data = new ByteArrayOutputStream(1024); //1024字节大小的缓存区 data.write(System.in.read()); // 暂存用户输入数据  //将data转为ByteArrayInputStream ByteArrayInputStream in = new ByteArrayInputStream(data.toByteArray());  FileInputStream和FileOutputStream访问文件,把文件作为InputStream,实现对文件的读写操作 ObjectInputStream和ObjectOutputStream对象流,构造函数需要传入一个流,实现对JAVA对象的读写功能;可用于序列化,而对象需要实现Serializable接口 //java对象的写入 FileOutputStream fileStream = new FileOutputStream("example.txt"); ObjectOutputStream out = new ObjectOutputStream(fileStream); Example example = new Example(); out.writeObject(example);  //java对象的读取 FileInputStream fileStream = new FileInputStream("example.txt"); ObjectInputStream in = new ObjectInputStream(fileStream); Example = (Example) in.readObject();  PipedInputStream和PipedOutputStream管道流,适用在两个线程中传输数据,一个线程通过管道输出流发送数据,另一个线程通过管道输入流读取数据,实现两个线程间的数据通信 // 创建一个发送者对象 Sender sender = new Sender(); // 创建一个接收者对象 Receiver receiver = new Receiver(); // 获取输出管道流 // 获取输入输出管道流 PipedOutputStream outputStream = sender.getOutputStream();  PipedInputStream inputStream = receiver.getInputStream(); // 链接两个管道,这一步很重要,把输入流和输出流联通起来   outputStream.connect(inputStream); sender.start();// 启动发送者线程 receiver.start();// 启动接收者线程  SequenceInputStream把多个InputStream合并为一个InputStream,允许应用程序把几个输入流连续地合并起来 InputStream in1 = new FileInputStream("example1.txt"); InputStream in2 = new FileInputStream("example2.txt"); SequenceInputStream sequenceInputStream = new SequenceInputStream(in1, in2); //数据读取 int data = sequenceInputStream.read();  FilterInputStream和FilterOutputStream使用了装饰者模式来增加流的额外功能,子类构造参数需要一个InputStream/OutputStream ByteArrayOutputStream out = new ByteArrayOutputStream(2014); //数据写入,使用DataOutputStream装饰一个InputStream //使用InputStream具有对基本数据的处理能力 DataOutputStream dataOut = new DataOutputStream(out); dataOut.writeDouble(1.0); //数据读取 ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); DataInputStream dataIn = new DataInputStream(in); Double data = dataIn.readDouble();  DataInputStream和DataOutputStream(Filter流的子类)为其他流附加处理各种基本类型数据的能力,如byte、int、String BufferedInputStream和BufferedOutputStream(Filter流的子类)为其他流增加缓冲功能 PushBackInputStream(FilterInputStream子类)推回输入流,可以把读取进来的某些数据重新回退到输入流的缓冲区之中 PrintStream(FilterOutputStream子类)打印流,功能类似System.out.print  2JAVA.IO字符流 21.png  从字节流和字符流的导向图来,它们之间是相互对应的,比如CharArrayReader和ByteArrayInputStream 字节流和字符流的转化:InputStreamReader可以将InputStream转为Reader,OutputStreamReader可以将OutputStream转为Writer //InputStream转为Reader InputStream inputStream = new ByteArrayInputStream("程序".getBytes()); InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); //OutputStream转为Writer OutputStream out = new FileOutputStream("example.txt"); OutputStreamWriter writer = new OutputStreamWriter(out); //以字符为单位读写 writer.write(reader.read(new char[2]));  区别:字节流读取单位是字节,字符流读取单位是字符;一个字符由字节组成,如变字长编码UTF-8是由1~4个字节表示 3乱码问题和字符流 字符以不同的编码表示,它的字节长度(字长)是不一样的。

如“程”的utf-8编码格式,由[-25][-88][-117]组成。

而ISO_8859_1编码则是单个字节[63] 平时工作对资源的操作都是面向字节流的,然而数据资源根据不同的字节编码转为字节时,它们的内容是不一样,容易造成乱码问题 两种出现乱码场景encode和decode使用的字符编码不一致:资源使用UTF-8编码,而在代码里却使用GBK解码打开使用字节流读取字节数不符合字符规定字长:字符是由字节组成的,比如“程”的utf-8格式是三个字节;如果在InputStream里以每两个字节读取流,再转为String(java默认编码是utf-8),此时会出现乱码(半个中文,你猜是什么) ByteArrayInputStream in = new ByteArrayInputStream("程序大法好".getBytes()); byte[] buf = new byte[2]; //读取流的两个字节 in.read(buf); //读取数据 System.out.println(new String(buf)); //乱码 ---result----  �  //乱码  乱码场景1,知道资源的字符编码,就可以使用对应的字符编码来解码解决 乱码场景2,可以一次性读取所有字节,再一次性编码处理。

但是对于大文件流,这是不现实的,因此有了字符流的出现 字节流使用InputStreamReader、OutputStreamReader转化为字符流,其中可以指定字符编码,再以字符为单位来处理,可解决乱码 InputStreamReader reader =        new InputStreamReader(inputStream, StandardCharsets.UTF_8);  4字符集和字符编码的概念区分 字符集和字符编码的关系,字符集是规范,字符编码是规范的具体实现;字符集规定了符号和二进制代码值的唯一对应关系,但是没有指定具体的存储方式; unicode、ASCII、GB2312、GBK都是字符集;其中ASCII、GB2312、GBK既是字符集也是字符编码;注意不混淆这两者区别;而unicode的具体实现有UTF-8,UTF-16,UTF-32 最早出现的ASCII码是使用一个字节(8bit)来规定字符和二进制映射关系,标准ASCII编码规定了128个字符,在英文的世界,是够用的。

但是中文,日文等其他文字符号怎么映射呢?因此其他更大的字符集出现了 unicode(统一字符集),早期时它使用2个byte表示1个字符,整个字符集可以容纳65536个字符。

然而仍然不够用,于是扩展到4个byte表示一个字符,现支持范围是U+010000~U+10FFFF unicode是两个字节的说法是错误的;UTF-8是变字长的,需要用1~4个字节存储;UTF-16一般是两个字节(U+0000~U+FFFF范围),如果遇到两个字节存不下,则用4个字节;而UTF-32是固定四个字节 unicode表示的字符,会用“U+”开头,后面跟着十六进制的数字,如“字”的编码就是U+5B57 UTF-8编码和unicode字符集 范围Unicode(Binary)UTF-8编码(Binary)UTF-8编码byte长度U+0000~U+007F0000000000000000000000000XXXXXXX0XXXXXX1U+0080~U+07FF000000000000000000000YYYYYXXXXXX110YYYYY10XXXXXX2U+0800~U+FFFF0000000000000000ZZZZYYYYYYXXXXXX1110ZZZZ10YYYYYY10XXXXXX3U+010000~U+10FFFF00000000000AAAZZZZZZYYYYYYXXXXXX11110AAA10ZZZZZZ10YYYYYY10XXXXXX4 程序是分内码和外码,java的默认编码是UTF-8,其实指的是外码;内码倾向于使用定长码,和内存对齐一个原理,便于处理。

外码倾向于使用变长码,变长码将常用字符编为短编码,罕见字符编为长编码,节省存储空间与传输带宽 JDK8的字符串,是使用char[]来存储字符的,char是两个字节大小,其中使用的是UTF-16编码(内码)。

而unicode规定的中文字符在U+0000~U+FFFF内,因此使用char(UTF-16编码)存储中文是不会出现乱码的 JDK9后,字符串则使用byte[]数组来存储,因为有一些字符一个char已经存不了,如emoji表情字符,使用字节存储字符串更容易拓展 JDK9,如果字符串的内容都是ISO-8859-1/Latin-1字符(1个字符1字节),则使用ISO-8859-1/Latin-1编码存储字符串,否则使用UTF-16编码存储数组(2或4个字节) System.out.println(Charset.defaultCharset()); //输出java默认编码 for (byte item : "程序".getBytes(StandardCharsets.UTF_16)) {     System.out.print("[" + item + "]"); } System.out.println(""); for (byte item : "程序".getBytes(StandardCharsets.UTF_8)) {     System.out.print("[" + item + "]"); } ----result---- UTF-8       //java默认编码UTF-8 [-2][-1][122][11][94][-113] //UTF_16:6个字节? [-25][-88][-117][-27][-70][-113] //UTF_8:6个字节 正常  “程序”的UTF-16编码竟是输出6个字节,多出了两个字节,这是什么情况?再试试一个字符的输 for (byte item : "程".getBytes(StandardCharsets.UTF_16)) {     System.out.print("[" + item + "]"); } ---result-- [-2][-1][122][11]  可以看出UTF-16编码的字节是多了[-2][-1]两个字节,十六进制是0xFEFF。

而它用来标识编码顺序是Bigendian还是Littleendian。

以字符'中'为例,它的unicode十六进制是4E2D,存储时4E在前,2D在后,就是Bigendian;2D在前,4E在后,就是Littleendian。

FEFF表示存储采用Bigendian,FFFE表示使用Littleendian 为什么UTF-8没有字节序的问题呢?个人看法,因为UTF-8是变长的,由第一个字节的头部的0、110、1110、11110判断是否需后续几个字节组成字符,使用Bigendian易读取处理,反过来不好处理,因此强制用Bigendian 其实感觉UTF-16可以强制规定用Bigendian;但这其中历史问题。





 【编辑推荐】 Python虽好,但请不要盲目将它用于每一个项目! 红帽开放混合云助力企业成为数字原生企业 分析鸿蒙系统helloworld程序是如何被调用,SYS_RUN做什么事情 5G为何突然间就“不火”了? 新方向、新功能:Python3.9完整版面世了  责任编辑:姜华 来源: 今日头条JAVA.IO、字符编码分享到微信微信扫码分享分享到微博相关推荐一文带你读懂Base64编码相信很多同学在工作中,经常会用到Base64编码,那大家知道为什么会有Base64编码吗我们为什么要使用它呢,它又是怎么实现的呢下面就让我们来一起深入探究一下Base64编码吧。

2021-03-0509:10:19base64编码一文读懂DataOps大部分企业的数据平台建设要想顺利过渡到第三阶段,则离不开一个关键方法论—DataOps(数据运维)的帮助。

2021-08-0416:06:45DataOps智领云一文让你理清PrimaryScrollController对苹果用户来说,大家基本都知道,iOS手机应用有一个比较常见的功能:点击状态栏,列表就会滚动到顶部。

在iOS原生代码中,我们可以通过原生框架的已有特性或者自己添加监听来实现这个功能。

2022-09-2910:26:59iOSScaffoldflutter一文读懂云网络云网络统一云网资源和服务能力,逐渐突破云网物理边界,向网络、计算和存储一体化融合的技术架构演进。

算力网络将成为云网络演进的下一个阶段。

2022-07-0506:30:54云网络网络云原生一文读懂无损网络RDMA的高效运行依赖于无损网络,通过无损网络的建设,算力、网络、存储才能相互匹配,协同发挥更大的作用。

2021-12-2918:00:19无损网络网络通信网络一文读懂“语言模型”语言模型的历史可以追溯到100多年前,马尔科夫、香农和其他人没有预见到他们所研究的模型和理论会在以后产生如此巨大的影响,甚至可能是意想不到的。

未来100年中语言模型将如何发展?它们仍将是人工智能技术的重要组成部分吗?2022-07-2600:00:03语言模型人工智能一文读懂前端缓存在国外IT圈和大部分国外视频中,cache的发音是k&230;&643;(同cash),这也是一个广泛认可的发音。

但我发现在中国的IT圈还有相当一部分程序员(比如我自己……)读作k&230;t&643;(同catch)。

虽然不太正确,但并不妨碍互相交流。

2018-09-2814:06:25前端缓存后端一文读懂CSS单位CSS中单位的形式有很多种,下面就来学习一下CSS中单位!2022-09-2209:00:46CSS单位一文读懂自动编码器的前世今生变分自动编码器(VAE)可以说是最实用的自动编码器,但是在讨论VAE之前,还必须了解一下用于数据压缩或去噪的传统自动编码器。

2019-05-2217:34:16代码开发工具一文带你读懂物联网物联网是“新基建”的核心要素,数字化转型,物联网是必经之路。

2021-09-1322:34:56区块链新基建数字化转型一文读懂https底层原理既然https协议本质只是http上加了安全层,本文就主要将安全层是怎么实现的。

当然要靠加密。

加密又分成对称加密和非对称加密。

2021-12-1614:45:09https架构服务端一文读懂MQ消息队列MQ(消息队列)在软件架构中是经常被使用的,特别是在分布式系统中也是使用频率很高的组件。

2019-08-2312:12:49MQ消息队列一文读懂Python装饰器很多初学者一直不理解装饰器及其工作原理,在这篇文章中,我们将介绍装饰器的来龙去脉。

2022-09-2109:04:07Python装饰器一文读懂加密网格交易新冠病毒疫情之后,以比特币为主的加密货币市场出现了一段时间的单边上涨态势,但当下的加密货币市场似乎开始进入盘整期,尤其是最近一个多月更是出现了多次震荡。

2021-04-0611:03:12一文读懂Kubernetes与Docker容器是惊人的!它们使我们能够以全新的数字化方式思考服务和系统。

Docker和Kubernetes都将继续存在。

2022-05-1208:01:18KubernetesDocker容器一文读懂零信任架构零信任不是一种技术,而是一种安全框架和理念,这意味着企业可以将其构建到现有的体系结构中,而无需完全拆除现有的基础设施。

2022-04-2606:04:11零信任网络安全一文带你读懂CNCFLandscapeRuntime这一层可以理解为容器的整个运行环境,是云原生中最核心的部分,它包括了计算、存储、网络三大块:2019-06-1321:31:19AI一文读懂电子数据取证在网络安全大环境中,信息安全可以看作是解决事前防御问题,电子取证则是解决事后究责问题。

2022-08-2710:37:48电子取证信息安全一文读懂Logback的配置为啥想着写这个呢是这样,小六六每次搭建系统的时候,都会涉及到这块的配置嘛,然后我发现我搭建了这么多次的系统,大部分的情况下,竟然是copy来完成的,然后这次搭建的过程中,又对这些配置又了点理解,所以打算给大家分享分享一些关键的点,让大家多Java项目的日志有一些更加深入的理解吧!2021-09-0419:04:14配置LogbackJava一文读懂零拷贝技术本文主要介绍了splice​的原理与实现,splice​是零拷贝技术​的一种实现。

希望通过本文,能够让读者对零拷贝技术有更深入的理解。

2022-09-2713:34:49splice零拷贝原理相似话题前端17849内容开发工具6345内容测试356内容游戏开发536内容全部话题同话题下的热门内容十个Python脚本来自动化你的日常任务三个Python小工具,Linux服务器性能直线飞起!!!功能强大的开源Python绘图库这五个实用但鲜为人知的Python模块,你知道么?Julia和Python,哪一个更快?面向嵌入式开发的八个Java框架,你知道几个?提升Python程序性能的七个习惯非常哇塞的SpringBoot性能优化长文编辑推荐VScode搭建C和C++环境的完整图文教程!超全!Python图形界面框架PyQt5使用指南!用Python画如此漂亮的专业插图?简直Soeasy!太强了!Python开发桌面小工具,让代码替我们干重复的工作!浅谈Python+requests+pytest接口自动化测试框架的搭建相关专题更多IBM助力企业全面转型Commvault:探寻企业数据管理的最佳实践2022-09-2816:16:10Cortex赋能自动化安全运营2022-09-2910:56:57我收藏的内容微博QQ微信复制链接微信扫码分享51CTO技术栈公众号51CTO技术栈公众号 业务 速览 在线客服媒体51CTOCIOAgeHC3i社区51CTO博客开源基础软件社区教育51CTO学堂精培企业培训CTO训练营



請為這篇文章評分?