java的内容好复杂_Java I/O 好复杂,傻傻分不清楚,别担心,我们有线索了……...
IO 类图
小帅最近在学Java的IO类库,这么多类看得小帅人头昏眼花,常常是学了这个类,忘了那个类,再过一阵子就全忘了。。。
每次用到的时候,小帅都要重新读文档,看代码,如此循环,身心疲惫。
小帅没办法只好向好朋友小会求助:IO类库太复杂了,我毫无头绪,能不能帮我梳理一下?
小会想了一下,说道:总体来说IO类库分为两大类:字节流和字符流,字节流是按字节读取数据,字符流是按字符读取数据。
小帅不解:所有的数据在计算机中都是二进制表示的,都用字节来读取不就行了吗?
为什么还要加个字符流,我用字节读出来,再转成字符不行吗?
小会说:Java中的字符都是用Unicode表示的,即对应一个数字,也就是码点。
如果我们用二进制的字节流读出来是无法看懂的,我们需要用对应的编码格式(比如:UTF-8,UFT-16等)转换成我们可读的字符。
字符流就是专门用来读写人们可读的字符的,这样会方便很多,一步到位,不用再手工转换成字符了。
我把IO类都放在一张图里,这样看上去就清爽了:
小帅:还是好多类啊。。。
小会:别急,我们往下看。
看个例子
我们看一下用字节流,把int数据1到9,写进txt文件的例子:
FileOutputStream outputStream=newFileOutputStream("text.txt");DataOutputStream dataOutputStream=newDataOutputStream(outputStream);
for(inti=;i
dataOutputStream.writeInt(i);
}
dataOutputStream.close();
text.txt文件内容:
里面保存的都是二进制数据,但是我们是用int的数据类型写进去的(dataOutputStream.writeInt(i);),而不是以二进制的格式写进去的。
小帅疑惑:为什么要用 DataOutputStream写入int数据呢?
我直接用 FileOutputStream 不能写吗?
DataOutputStream有什么作用呢?
小会微微一笑:如果不用DataOutputStream也可以,不过要自己拼成int数据类型的格式,一个int类型占四个字节。
比如1用二进制表示就是 0000 0000 0000 0000 0000 0000 0000 0001,用十六进制表示就是 00 00 00 01。
我们试一下用 FileOutputStream 写入int数字 0,1,2:
FileOutputStream outputStream=newFileOutputStream("text.txt");
// int 0
outputStream.write();
outputStream.write();
outputStream.write();
outputStream.write();
// int 1
outputStream.write();
outputStream.write();
outputStream.write();
outputStream.write(1);
// int 2
outputStream.write();
outputStream.write();
outputStream.write();
outputStream.write(2);
outputStream.close();
写入结果:
如果用DataOutputStream 写就是:dataOutputStream.writeInt(0),dataOutputStream.writeInt(1),dataOutputStream.writeInt(2),这样是不简单很多呢?
小帅似乎有点懂了:我知道了,DataOutputStream 是对 FileOutputStream 类功能的增强,让FileOutputStream 类更加强大,起到了装饰的作用。
小会开心道:你说到重点了,IO类看似凌乱,其实有一个精巧的设计模式,贯穿其中,把这么多类有序的组织起来了。
这个设计模式是理解IO类的钥匙,你知道是哪一个设计模式吗?
装饰者模式?小帅疑惑道。
装饰者模式
是的,就是装饰者模式,我以前写过一篇介绍装饰者模式的文章,可以点开看看:装饰模式--小美的生日蛋糕。
装饰者模式的类图:
OutputStream家族类:
这里的FilterOutputStream类就是装饰模式中的抽象装饰类。
它的子类BufferedOutputStream,DataOutputStream,PrintStream就是具体的装饰类,起到了功能增强的作用。
它们本身并没有实现写数据的功能。
看下FilterOutputStream的代码:
写数据的功能是靠被修饰的类实现的,这里的OutputStream out 是要从外面传进来的:
DataOutputStream的writeInt方法实现了功能的增强,可以直接写int类型的数据:
BufferedOutputStream类实现了缓存的功能增强:
也就是说装饰类是给主类锦上添花,主类是锦,装饰类是花,花不能代替锦,主要的功能还得靠“锦”实现的。
清晰起来了
同理我们来看看其他流:
InputStream家族类:
Writer家族类:
小帅一眼看出了问题:奇怪,FilterWriter装饰类怎么没有子类呢?是不是Writer家族没有用装饰模式呢?
小会微微一笑:不是的,其实还是用了装饰模式,只是实现的方式有点不一样,例如OutputStreamWriter类:
其实是对OutputStream类的装饰,换句话说字符流的底层其实是调用了字节流。
这也很容易理解,因为计算机只能处理二进制数据,本质上还是通过字节流实现的。
Reader家族类:
FilterReader充当了抽象装饰类,PushbackReader是具体的装饰类。
同样的InputStreamReader类其实也实现了装饰模式:
再看个例子
publicstaticvoidmain(String[]args)throwsIOException{
try(BufferedWriter writer=newBufferedWriter(newOutputStreamWriter(newFileOutputStream("把酒问月·故人贾淳令予问之.txt")))){
writer.write("青天有月来几时?我今停杯一问之。");
writer.newLine();
writer.write("人攀明月不可得,月行却与人相随。");
writer.newLine();
writer.write("皎如飞镜临丹阙,绿烟灭尽清辉发。");
writer.newLine();
writer.write("但见宵从海上来,宁知晓向云间没。");
writer.newLine();
writer.write("白兔捣药秋复春,嫦娥孤栖与谁邻。");
writer.newLine();
writer.write("今人不见古时月,今月曾经照古人。");
writer.newLine();
writer.write("古人今人若流水,共看明月皆如此。");
writer.newLine();
writer.write("唯愿当歌对酒时,月光长照金樽里。");
}
try(BufferedReader reader=newBufferedReader(newInputStreamReader(newFileInputStream("把酒问月·故人贾淳令予问之.txt")))){
String line;
while((line=reader.readLine())!=null){
System.out.println(line);
}
}}
输出:
青天有月来几时?我今停杯一问之。
人攀明月不可得,月行却与人相随。
皎如飞镜临丹阙,绿烟灭尽清辉发。
但见宵从海上来,宁知晓向云间没。
白兔捣药秋复春,嫦娥孤栖与谁邻。
今人不见古时月,今月曾经照古人。
古人今人若流水,共看明月皆如此。
唯愿当歌对酒时,月光长照金樽里。
OutputStreamWriter增强了FileOutputStream,让它拥有了直接写字符的能力,BufferedWriter增强了OutputStreamWriter,让它拥有了缓存的能力。
同样的,InputStreamReader增强了FileInputStream,让它拥有了直接读字符的能力,BufferedReader增强InputStreamReader,让它拥有了缓存的能力。
最后的话
Java的IO类库以前我也看得一脸懵逼,总是觉得太繁琐,太难记了。后来学了装饰者模式才知道,要搞懂Java的IO类库,其实重点是要搞懂装饰者模式。
如果不懂装饰者模式,看多少次也不会理解为什么要这么设计。
当一把锁被锁上的时候,你一直盯着锁看是没有用的,因为钥匙肯定不是插在锁上,一定要去别的地方找钥匙啊。
java的内容好复杂_Java I/O 好复杂,傻傻分不清楚,别担心,我们有线索了……...相关推荐
- java获取内容为空_Java使用POI读取Word文档时如果文档内容为空时出现异常
异常如下: org.apache.poi.EmptyFileException: The supplied file was empty (zero bytes long) at org.apache ...
- java调节音量代码_用Java调用VC音量控制程序_java
前言 本文通过java的Runtime接口来实现调用其他语言实现的应用程序,进而来实现对计算机硬件信息的监控和控制.本文是多媒体信息系统的一个部分,就是调整计算机音量. 使用VC编写音量控制程序 本控 ...
- JAVA秒杀mysql层实现_Java高并发秒杀API之web层
第1章 设计Restful接口 1.1前端交互流程设计 1.2 学习Restful接口设计 什么是Restful?它就是一种优雅的URI表述方式,用来设计我们资源的访问URL.通过这个URL的设计,我 ...
- java(x ) 3的值_java中,设x=2,则表达式 (x++)*3的值是多少 设x=2则表达式(x+
是6,如果是 ++x就是 9 原因 x++是先用原来的值运算 后赋值 ++x先给x自增,再运算 (x++)/3 x++的意思是先运算,后加1,也就是运算的时候x还是为2,运算过后x才会变成3. 而且 ...
- java 多线程的基本概念_java基本教程之多线程基本概念 java多线程教程
多线程是Java中不可避免的一个重要主体.下面我们将展开对多线程的学习.接下来的内容,是对"JDK中新增JUC包"之前的Java多线程内容的讲解,涉及到的内容包括,Object类中 ...
- java传统的项目有哪些内容_请问java全套内容都有什么呢?
我整理的Java全套内容学习路线,分为6个阶段(大阶段)第一阶段:java内功心法篇 第二阶段:Java武功秘籍(经典框架) 第三阶段:Java高级功法(主流框架) 第四阶段:Java成神之路 第五阶 ...
- java socket 传输压缩文件_java基于socket传输zip文件功能示例
本文实例讲述了java基于socket传输zip文件的方法.分享给大家供大家参考,具体如下: 服务器端程序: import java.io.*; import java.net.*; import j ...
- java中链式调用_Java及Android中常用链式调用写法简单示例
本文实例讲述了Java及Android中常用链式调用写法.分享给大家供大家参考,具体如下: 最近发现,目前大火的许多开源框架中,大多都使用了一种"(方法).(方法).(方法)"的形 ...
- java 在数组末尾添加元素_Java快问快答:用 ArrayList 还是 LinkedList?
问题: 通常我会这么定义列表: List<String> names = new ArrayList<>() names类型使用List接口,那么具体实现该如何选择. 什么时候 ...
最新文章
- 51nod 1179 最大的最大公约数 (打表计数法)
- 6月17 表单验证
- stdthread(7)并发unique_lock
- Acwing第 6 场周赛【未完结】
- AOM Summit:拥抱开源,引领新技术创新
- Script:List OBJECT DEPENDENT
- 函数不可以直接调用其他函数内部定义的变量_python的函数
- java界面ATM机取款后的余额_java_ATM机银行存取款系统的设计与实现本科毕业论文...
- matlab中关于统计的函数
- 前端安全: 如何防止 XSS 攻击?
- js刷新页面的几种方式与区别
- mysql 5.7修改密码
- php表格制作底纹怎么做,HTML表格标记教程(36):表头的背景色属性BGCOLOR
- php 格式化电话号码
- 压缩20M文件从30秒到1秒的优化过程
- Raspberry PI 编译WLan驱动模块, 并配置登录WIFI
- Trace32手册-Linux Debugging Reference Card
- android 仿微信联系人 首字母分组快速索引
- 功分器,双工器,耦合器,合路器,环形器
- Window XP 命令提示
热门文章
- java 鱼刺图_鱼骨图问题分析法
- 游戏数据分析 | 用户流失原因分析
- c语言里的加减乘除的英文单词怎么写,英语的加减乘除如何表达?
- No.03 色散补偿 FSM算法 频域离散采样算法 MATLAB Python 代码实现
- 详解:Flutter内存泄漏解决方案
- 我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=61c74kbnuf9n
- 如何学习symbian(转)
- AMBER分子动力学模拟之结果分析(构象分析)-- HIV蛋白酶-抑制剂复合物(6)
- 静态建模(类图和对象图)
- 电容感应触摸屏工作原理