转自知乎javaIO理解

初学者觉得复杂是很正常的,归根结底是因为没有理解框架的设计思想:可以沿着这条路想一想:
1,学IO流之前,我们写的程序,都是在内存里自己跟自己玩 。比如,你声明个变量,创建个数组,创建个集合,写一个排序算法,模拟一个链表,使用一些常用API,现在回想一下,是不是在只是自己在内存里玩一玩?计算机组成包括运算器,控制器,存储器,输入设备,输出设备 。那么你前面的工作,仅仅够你的程序和内存以及CPU打打交道,如果你需要操作外部设备呢?比如键盘,显示器,再比如,最常见的外设:硬盘?甚至未来世界里的每家每户都有的机器人,“如何让你的程序和机器人进行交互呢?”
2,所以程序设计语言必须要提供程序与外部设备交互的方式,这就是IO框架的由来 。我们需要和外部设备进行数据的交互 。那么,计算机是通过什么和外部进行交互的呢?很简单就能想到:数据线 。数据线里传播的是什么呢?一个词:比特流 。比特就是bit的谐音,计算机中“位”的意思,代表0或1 。1位或者1bit,就是一个0或一个1 。但是,毕竟0或1不能表示什么,所以计算机更常见的基本单位是字节,也就是用8位0或1组成的一段数据 。以上是对比特流的由来做一个简单地解释 。(比特流一词来自于计算机网络原理中,对物理层传输内容的描述:物理层(网线)中传输的是“比特流”,在这里借用这个名词代指数据的表示形式,帮助理解)上面两段话的意思,其实是为了下文做铺垫,帮助理解输入输出最重要的概念:方向性 。输入还是输出,是相对于程序或者说相对于内存而言的 。数据从外流到内存,就是输入(读),数据从内存出去,就是输出(写) 。
3,既然计算机和外界进行信息的输入和输出交互,用的是比特流,那么很容易就能想到IO流名字的由来了 。就是比喻输入输出的数据像流一样 。我们可以这么认为,任何外部设备与内存之间输入输出的操作,都是需要输入输出流(IO流)来完成的,这里的IO流,指的就是比特流(或者称字节流) 。这些外部设备,包括,键盘(标准输入设备),显示器(标准输出设备),音响,网络上另一台主机,甚至你玩游戏用的游戏手柄,以及各种各样的信号传感器,都可以叫做外部设备,和这些设备之间进行数据交互,显然不可能靠之前学习的那些数组,集合,常用类,等等来完成 。而是要靠和外界数据交换的类来完成 。靠什么来进行数据交换,就是前面说的,比特流,或者说IO流类 。
4,那么,既然要学习IO流,就得针对某一个输入输出设备来学习 。哪种输入输出设备最重要同时也最常见?当然是硬盘 。硬盘在这里的含义也可以理解为文件系统 。(Java程序是运行在某操作系统平台上的应用软件JVM上的,实际上Java程序可见的并不是硬盘,而是操作系统提供的文件系统,因此此处可直接理解为文件系统) 。因此,我们学习IO流的时候,基本上是学习的Java如何操作文件系统,除了文件系统,我们还能够了解Java操作标准输入输出设备,如和.out 。
5,知道了学习的方向,是要使用Java操作文件系统,那么首先要学习的就是文件的表示,即File类 。然后,我们要操作做文件,虽然我们大部分操作都是操作文件系统,但是要明白IO流的概念不仅仅局限在操作文件上,前面我已经提到了,我们的编程语言是要能操作所有的输入输出,因此,API提供了两个顶层抽象类,用来表示操作所有的输出输出:,。并且,这两个类表示字节的输入输出,因为输入输出的本质是字节流 。这里注意体会一句话“字节流是最最基本的流”,这句话的由来就是因为计算机底层传递的就是字节 。那么,当我们要操作文件的时候,就需要具体的对文件系统操作的IO实现类,于是我们需要学习和,它们是文件输入输出字节流 。这里之所以/作为子类出现,按照面向对象思想理解就是,将来还有别的字节流来操作别的设备(比如将来需要通过操作网络设备获取网络数据,再比如需要操作机器人,那么或许就会再来个和,这些新的需求也就都可以继承这个体系)(这里顺便提一句架构设计思想,其中有一种设计原则叫“开闭原则”,其核心是:一个对象对扩展开放,对修改关闭 。就是说,一旦写好了某个类,就不要去轻易改动他,而是要保证它一直能运行下去,而面对新的功能需求时,只要在原有代码上增加即可,而不是修改原有代码 。要做到开闭原则,就需要分清需求中未来哪些部分是稳定的,哪些是很可能变化的,而往往抽象的部分是最稳定的,把稳定的内容分离出来,就能满足开闭原则 。这就是为什么Java的类设计的如此之琐碎,为什么我们要从继承关系角度去理解流的设计)