1 JAVA.IO字节流

inputstream.png

  • LineNumberInputStream和StringBufferInputStream官方建议不再使用,推荐使用LineNumberReader和StringReader代替
  • ByteArrayInputStream和ByteArrayOutputStream 字节数组处理流,在内存中建立一个缓冲区作为流使用,从缓存区读取数据比从存储介质(如磁盘)的速率快
//用ByteArrayOutputStream暂时缓存来自其他渠道的数据ByteArrayOutputStream data = new ByteArrayOutputStream(1024); //1024字节大小的缓存区data.write(System.in.read()); // 暂存用户输入数据//将data转为ByteArrayInputStreamByteArrayInputStream 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

2 JAVA.IO字符流

21.png

  • 从字节流和字符流的导向图来,它们之间是相互对应的,比如CharArrayReader和ByteArrayInputStream
  • 字节流和字符流的转化:InputStreamReader可以将InputStream转为Reader,OutputStreamReader可以将OutputStream转为Writer
//InputStream转为ReaderInputStream inputStream = new ByteArrayInputStream("程序".getBytes());InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);//OutputStream转为WriterOutputStream 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+007F 00000000 00000000 00000000 0XXXXXXX 0XXXXXX 1 U+0080~U+07FF 00000000 00000000 00000YYY YYXXXXXX 110YYYYY 10XXXXXX 2 U+0800~U+FFFF 00000000 00000000 ZZZZYYYY YYXXXXXX 1110ZZZZ 10YYYYYY 10XXXXXX 3 U+010000~U+10FFFF 00000000 000AAAZZ ZZZZYYYY YYXXXXXX 11110AAA 10ZZZZZZ 10YYYYYY 10XXXXXX 4

  • 程序是分内码和外码,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。而它用来标识编码顺序是Big endian还是Little endian。以字符'中'为例,它的unicode十六进制是4E2D,存储时4E在前,2D在后,就是Big endian;2D在前,4E在后,就是Little endian。FEFF表示存储采用Big endian,FFFE表示使用Little endian
  • 为什么UTF-8没有字节序的问题呢?个人看法,因为UTF-8是变长的,由第一个字节的头部的0、110、1110、11110判断是否需后续几个字节组成字符,使用Big endian易读取处理,反过来不好处理,因此强制用Big endian
  • 其实感觉UTF-16可以强制规定用Big endian;但这其中历史问题。。。

java ascii码转字符_一文让你读懂JAVA.IO、字符编码、相关推荐

  1. java 整数变负数_一文帮你读懂Java整数的存储原理

    前言 大家应该都知道,整数包括负数,零,和正数.在Java中,基本类型中byte(8位).short(16位).int(32位).long(64位)属于整数,并且没有无符号数,均是有符号的.对于计算机 ...

  2. 简单一文带你读懂Java变量的作用和三要素

    Java变量的作用 不只是java,在其他的编程语言中变量的作用只有一个:存储值(数据) 在java中,变量本质上是一块内存区域,数据存储在java虚拟机(JVM)内存中 变量的三要素 变量的三要素分 ...

  3. java byte char io流_一文带你看懂JAVA IO流,史上最全面的IO教学

    原标题:一文带你看懂JAVA IO流,史上最全面的IO教学 一.IO流是什么 惯例引用百科的回答 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符 ...

  4. java io流详解_一文带你看懂JAVA IO流,史上最全面的IO教学啦

    一.IO流是什么 惯例引用百科的回答流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作 ...

  5. javaio流_一文带你看懂JAVA IO流,史上最全面的IO教学啦

    一.IO流是什么 惯例引用百科的回答 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操 ...

  6. java ascii码大小写转换_使用「ASCII」转换大小写

    笔记背景 今天在看同事写的代码的时候突然看到一个有趣的东西,刚好自己又不怎么熟悉,经过我几番研究和分析终于得到了答案和知道了原理.接下来介绍一下这个代码(本人弱鸡,大牛勿喷): code1.png 相 ...

  7. 一文带你读懂Java字节码

    文章目录 前言 准备事宜 1 下载UltraEdit 下载Java虚拟机规范(Java SE 8版) 一.生成字节码 二.字节码阅读 class文件总览 魔数与副主版本号 常量池 字段 方法 统一讲解 ...

  8. au加载默认的输入和输出设备失败_一文带你读懂 C/C++ 语言输入输出流与缓存区...

    (给CPP开发者加星标,提升C/C++技能) 作者:技术让梦想更伟大 / 李肖遥 (本文来自作者投稿) 前言 有没有发现,基本上所有的C语言入门书籍,或者是我们的教程里面,第一个C语言程序实体,都是& ...

  9. java ascii码从小到大排序_待签名参数按照字段名的ascii码从小到大排序 怎么理解...

    展开全部 private String getSign(Map params) { Map sortMap = new TreeMap(); sortMap.putAll(params); // 以k ...

最新文章

  1. Centos下源码安装golang
  2. -32767转化为二进制_程序员需要了解的硬核知识之二进制
  3. RMAN 不完全恢复
  4. 7-50 畅通工程之局部最小花费问题 (35 分)(思路加详解)来呀兄弟们冲呀呀呀呀呀呀呀
  5. 不写程序,整体就泡 土豆网电视剧
  6. java 打印16进制数组_如何在Java中将字节数组转换为十六进制字符串?
  7. 【ACDU】国产数据库有奖征文活动开始啦!发原创奖京东卡,最高可领1000元!...
  8. 《SQL高级应用和数据仓库基础(MySQL版)》学习笔记 ·005【表的CRUD操作(DML语句)】
  9. 用Windows Live Writer写51cto博客
  10. arcgis_spatialjoin
  11. python实现二分搜索binary_search
  12. 驱动程序解析及其对硬件和系统发挥效能的重大作用和注意事宜
  13. Java 遍历JsonNode
  14. python_基础部分(1)
  15. keychron的机械键盘
  16. 查看Windows系统的开机、关机时间
  17. Django框架中No installed app with label问题
  18. MyEclipse 8.5 6.x 最新注册码(有效期至2016年)
  19. 什么是5G LAN 5G LAN商用爆发推动5G创新应用 提速数字转型新引擎
  20. 【python】取txt文件中的单词存到SQLite数据库,并且从bing词典爬取单词详情

热门文章

  1. 大数据分析体系由哪些层级构成
  2. 《Python cookbook》笔记一
  3. oracle hang analyze,Oracle hanganalyze工具的使用
  4. AcWing 891. Nim游戏(nim博弈)
  5. mysql 交叉表 存储过程_用于生成交叉表的存储过程的存储过程
  6. oracle表还原truncate,Oracle数据库执行truncate table操作后如何逆向恢复之前的状态...
  7. 梦醒了,一切都结束了
  8. 机器学习︱非平衡数据处理方式与评估
  9. eviews 9.5新版本——平均预测、面板效应检验
  10. 两列自适应布局方案整理