IO流
【摘要】IO流~
前言
IO流相关概念
IO能力是一门编程语言的标准能力,几乎所有的编程语言都有IO的能力,但是,java语言的IO能力还是很强的。
IO可以简单解释为 对文件的输入输出操作。
- 文件[File],它是一个宽泛的概念,包含:
普通文件
块文件
网络文件
文件夹
设备文件
… 
在OS中,比较重要一个概念是文件系统[FS], 比如:NTFS, FAT32, …
在java中,通过 java.io.File 类型来表示OS的文件,每一个OS的文件都可以使用一个路径来表示,而这个路径可以使用String类型来表达,并且我们可以很容易地把这个字符串所表示的路径转换成 File的实例。
如:
1  | String path = "E:\\JAVA实训\\note\\javase\\day01.txt"; //文件的路径  | 
- 路径[path]
- 绝对路径[absolute path]:以盘符开头的路径
 - 相对路径[relative path]:不以盘符开头的路径
每一个资源[文件]都有唯一的绝对路径。 
 
File类
- File类[没有能力操作文件的内容]。
 - 核心方法:
- length()
 - canRead()
 - canWrite()
 - getAbsolutePath()
 - getPath()
 - getName()
 - isFile()
 - isDirectory()
 - createNewFile(); //创建文件
 - mkdir(); //创建目录
 - mkdirs(); //创建目录结构,含父目录
 - delete(); //删除文件、空目录
 - deleteOnExit(); 在JVM进程退出之前再删除
 - listFiles
 - list
 - …
 
 
注:利用File类的delete方法删除文件时,需要注意
A.被其它进程占用的文件 删除会失败。
B.有内容的文件夹 删除会失败。
流 [stream]
流的源头
文件、网络、内存、扫描器,….
流的目的地
文件、网络、内存、终端,…
流的分类
- 根据数据的流向
以JVM为界,流可以分为:- 输入流:把外界的数据读入到JVM之中。
 - 输出流:把JVM之中的数据写出到外界。
 
 - 以功能来划分
- 字节流:以字节为单位的流。
 - 字符流:以字符为单位的流。[专门用来处理 文本类的文件]
 
 - 根据流数据的包装过程:
- 节点流:又称为低级流,特点是:数据源明确,真实负责读写数据的流。
 - 处理流:又称为高级流,特点是:不能单独存在(没意义),用来处理其他流,所有高级流都封装了某些特定功能的读写操作,目的是简化我们的读写操作具体的流。
 
 
综合以上前两种划分,共计可以分为:
字节流
字节输入流
1  | java.io.InputStream  | 
字节输出流
1  | java.io.OutputStream  | 
- 使用IO流的基本步骤:
1.把路径字符串转换成 File实例
2.有效性判断
3.创建流 [new ….]
4.循环读、写
5.释放资源 
作业:
- 写一个程序,完成文件的COPY
 - 写一个程序,完成文件夹的COPY。
 
节点流:
拥有真正的读写能力的流
1  | FileInputStream/FileOutputStream *[针对文件操作的字节流]  | 
过滤流 [FilterInputStream/FilterOutputStream]
本身没有读写能力,它必需架接在节点流的基础上,才能做读写操作,它可以在
节点流的基础上添加新的功能,如:
1  | BufferInputStream/BufferedOutputStream [添加缓存功能]  | 
IO流中API 的这种设计叫 装饰模式,它把类型分成两种:
A. 拥有核心基本能力的类
B. 装饰能力的类 [必需以 拥有基本能力的类 为构造]
基于这种模式,我们可以构建成功能强大的流:
1.构建一个带缓存功能的文件流
1  | BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));  | 
2.构建一个带缓存并且读基本数据类型的流
1  | DataInputStream dis = new DataInputStream(  | 
3.构建一个带缓存并且读对象类型的流
1  | ObjectInputStream dis =  | 
读写基本数据类型
1  | DataInputStream  | 
读写对象数据类型 – 对象序列化
要想持久化一个对象,要求这个对象必需要实现 java.io.Serializable接口,而且这个对象的属性类型也必需要实现 Serializable。
如:
1  | public class Student implements Serializable{  | 
之所以要把对象写入文件中,是为了保存此对象的状态[持久化它的数据]。
对于对象的集合 又该如何?
    直接持久化集合即可【要求集合中的元素必需实现 Serializable】
如:
1  | List<Student> stuList = ....;  | 
利用IO流的知识,完成如下业务
我们之前开发过银行帐户类:Account,
改写:要求它的no属性是自动生成的,起始值A1000,每创建一个帐户,no自动增1,
如:A1001, A1002, A1003, …
1  | //Code  | 
并且也开发过它的业务类:AccountService
现在,在之前的基础上,提供一个业务接口:IAccountService
然后,改写之前的AccountService类,使用实现IAccountService接口.
新要求:
开发一个银行类 Bank, 要求此类是一个单例,它提供如下属性:
1  | private static final String PATH = ""; // 存放帐户文件的路径  | 
字符流
以字符为处理的基本单位的流
字符输入流
1  | java.io.Reader  | 
字符输出流
1  | java.io.Writer  | 
InputStreamReader
    把字节流转换成字符流的桥梁,它的构造:
    public InputStreamReader(InputStream in); //默认字符集
    public InputStreamReader(InputStream in, String charSet);//指定字符集
如:
在d:\\temp\\hehe.txt 文本文件,则可以用如下方式来打开:
1  | //1.  | 
了解
System.in   => InputStream
    它被JVM默认指定为 标准输入设备,也就是键盘
System.out  => PrintStream [OutpuStream的子类]
    它被JVM默认指定为 标准输出设备,也就是终端[console]
JVM允许我们修改标准输出输出设备,也就是对流进行重定向。
    System.setIn() 和  System.setOut() 
利用System.in和桥接器,我们可以让用户从键盘输入任意字符。
如:
1  | BufferedReader br =  | 
随机存取流
java.io.RandomAccessFile这个流既可以读也可以写。而且支持基本数据类型、对象类型的读和写。更关键的是,这个流支持文件指针的定位【指定从哪个位置开始读】
1  | 构造方法:  | 
思考:如何读取一个巨大的日志文件的最后一行?
作业:
请把 文件夹“文本文档”下的8个文本文件全部读取出来进行分析:
要求:
统计出空行的数量
英文单词的数量
中文词的数量
进阶:
分析每一个英文单词出现的次数。
结束语
作业现在不写~


