PHP女程序猿学习Java的Day-12
IO流
什么是IO
输入(Input)指的是:可以让程序从外部系统获得数据(核心含义是“读”,读取外部数据)。
输出(Output)指的是:程序输出数据给外部系统从而可以操作外部系统(核心含义是“写”,将数据写出到外部系统)。
java.io包为我们提供了相关的API,实现了对所有外部系统的输入输出操作;
什么是数据源
数据源data source,提供数据的原始媒介。常见的数据源有:数据库、文件、其他程序、内存、网络连接、IO设备
数据源分为:源设备、目标设备。
-
源设备:为程序提供数据,一般对应输入流。
-
目标设备:程序数据的目的地,一般对应输出流
流的概念
流是一个抽象、动态的概念,是一连串连续动态的数据集合。
对于输入流而言,数据源就像水箱,流(stream)就像水管中流动着的水流,程序就是我们最终的用户。我们通过流(A Stream)将数据源(Source)中的数据(information)输送到程序(Program)中。
对于输出流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目的数据源(dest)中。
流与源数据源和目标数据源之间的关系:
当程序需要读取数据源的数据时,就会通过IO流对象开启一个通向数据源的流,通过这个IO流对象的相关方法可以顺序读取数据源中的数据。
//创建输入流
FileInputStream fis = new FileInputStream("e:/abc.txt");
- 开发中通常我们根本不知道文件的内容,因此我们在读取的时候需要配合while循环使用。
- 为了保证出现异常后流的正常关闭,通常要将流的关闭语句要放到finally语句块中,并且要判断流是不是null。
try {files = new FileInputStream("e:/abc.txt"); // 内容是:abcStringBuilder sb = new StringBuilder();int temp = 0;//当temp等于-1时,表示已经到了文件结尾,停止读取while ((temp = files.read()) != -1) {sb.append((char) temp);}System.out.println(sb);} catch (Exception e) {e.printStackTrace();} finally {try {//这种写法,保证了即使遇到异常情况,也会关闭流对象。if (files != null) {files.close();}} catch (IOException e) {e.printStackTrace();}}
IO流新语法经典写法
在JDK7以及以后的版本中可以使用try-with-resource语法更优雅的关闭资源。
java.lang.AutoCloseable接口:
在java.lang.AutoCloseable接口中包含了一个close方法,该方法用于关闭资源。
只要是实现了java.lang.AutoCloseable接口的对象,都可以使用try-with-resource关闭资源。
使用最新的try-with-resource简化
//使用try-with-resource方式关闭资源。//在try中打开资源,不需要在代码中添加finally块关闭资源。try(FileInputStream fis = new FileInputStream("d:/a.txt");){StringBuilder sb = new StringBuilder();int temp=0;while((temp = fis.read()) != -1){sb.append((char) temp);}System.out.println(sb);}catch(Exception e){e.printStackTrace();}
java中流的概念细分:
按流的方向分类:
- 输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。
- 输出流:数据流向是程序到目的地(以OutPutStream、Writer结尾的流)。
按处理的数据单元分类:
- 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。
- 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。
按处理对象不同分类:
- 节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等。
- 处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。
节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。
-
nputStream/OutputStream
字节流的抽象类。
-
Reader/Writer
字符流的抽象类。
-
FileInputStream/FileOutputStream
节点流:以字节为单位直接操作“文件”。
-
ByteArrayInputStream/ByteArrayOutputStream
节点流:以字节为单位直接操作“字节数组对象”。
-
ObjectInputStream/ObjectOutputStream
处理流:以字节为单位直接操作“对象”。
-
DataInputStream/DataOutputStream
处理流:以字节为单位直接操作“基本数据类型与字符串类型”。
-
FileReader/FileWriter
节点流:以字符为单位直接操作“文本文件”(注意:只能读写文本文件)。
-
BufferedReader/BufferedWriter
处理流:将Reader/Writer对象进行包装,增加缓存功能,提高读写效率。
-
BufferedInputStream/BufferedOutputStream
处理流:将InputStream/OutputStream对象进行包装,增加缓存功能,提高读写效率
-
InputStreamReader/OutputStreamWriter
处理流:将字节流对象转化成字符流对象。
-
PrintStream
处理流:将OutputStream进行包装,可以方便地输出字符
Java中IO的四大抽象类
nputStream/OutputStream和Reader/writer类是所有IO流类的抽象父类,我们有必要简单了解一下这个四个抽象类的作用。然后,通过它们具体的子类熟悉相关的用法。
InputStream
此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。 数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类 。
继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit)。
常用方法:
方法名 | 使用说明 |
---|---|
int read() | 读取一个字节的数据,并将字节的值作为int类型返回(0-255之间的一个值)。如果未读出字节则返回-1(返回值为-1表示读取结束) |
void close() | 关闭输入流对象,释放相关系统资源 |
OutputStream
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
常用方法:
方法名 | 使用说明 |
---|---|
void write(int n) | 向目的地中写入一个字节 |
void close() | 关闭输出流对象,释放相关系统资源 |
Reader
Reader用于读取的字符流抽象类,数据单位为字符。
方法名 | 使用说明 |
---|---|
int read() | 读取一个字符的数据,并将字符的值作为int类型返回(0-65535之间的一个值,即Unicode值)。如果未读出字符则返回-1(返回值为-1表示读取结束) |
void close() | 关闭流对象,释放相关系统资源 |
Writer
Writer用于输出的字符流抽象类,数据单位为字符。
方法名 | 使用说明 |
---|---|
void write(int n) | 向输出流中写入一个字符 |
void close() | 关闭输出流对象,释放相关系统资源 |
常用流详解
文件字节流
FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件(图像、视频、文本文件等)。
FileInputStream文件输入字节流
通过字节缓冲区提高读写效率
通过创建一个指定长度的字节数组作为缓冲区,以此来提高IO流的读写效率。该方式适用于读取较大文件时的缓冲区定义。注意:缓冲区的长度一定是2的整数幂。一般情况下1024长度较为合适
注意 在使用字节缓冲区时,我们需要注意:
- 为了减少对硬盘的读写次数,提高效率,通常设置缓存数组。相应地,读取时使用的方法为:read(byte[] b);写入时的方法为:write(byte[ ] b, int off, int length)
- 程序中如果遇到多个流,每个流都要单独关闭,防止其中一个流出现异常后导致其他流无法关闭的情况
//“后开的先关闭!”按照他们被创建顺序的逆序来关闭try(FileInputStream fis = new FileInputStream(src);FileOutputStream fos = new FileOutputStream(desc)){//创建一个缓冲区,提高读写效率byte[] buffer = new byte[1024];int temp = 0;while ((temp = fis.read(buffer)) != -1){//将缓存数组中的数据写入文件中,注意:写入的是读取的真实长度;fos.write(buffer,0,temp);}//将数据从内存中写入到磁盘中。fos.flush();}catch (IOException e) {e.printStackTrace();}
- 在关闭流时,应该先关闭最外层的包装流,即“后开的先关闭”。
- 缓存区的大小默认是8192字节,也可以使用其它的构造方法自己指定大小。
缓冲字符流
字符输入缓冲流
BufferedReader是针对字符输入流的缓冲流对象,提供了更方便的按行读取的方法:readLine(); 在使用字符流读取文本文件时,我们可以使用该方法以行为单位进行读取。
字符输出缓冲流
BufferedWriter是针对字符输出流的缓冲流对象,在字符输出缓冲流中可以使用newLine();方法实现换行处理。
转换流
InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流。
通过转换流解决乱码
ANSI(American National Standards Institute)美国国家标准协会
try(FileInputStream fis = new FileInputStream("d:/sxt.txt");//创建转换流(字节到字符的转换)流对象,并在该对象中指定编码。InputStreamReader isr = new InputStreamReader(fis,"gbk")){StringBuilder sb = new StringBuilder();//操作流对象int temp = 0;while((temp = isr.read()) != -1){sb.append((char) temp);}System.out.println(sb);}catch(IOException e){e.printStackTrace();}
Apache commons-io工具包的使用
Apache基金会介绍
Apache软件基金会(也就是Apache Software Foundation,简称为ASF),是专门为支持开源软件项目而办的一个非盈利性组织。在它所支持的Apache项目与子项目中,所发行的软件产品都遵循Apache许可证(Apache License)。 官方网址为:www.apache.org 。
很多著名的Java开源项目都来源于这个组织。比如:commons、kafka、lucene、maven、shiro、struts等技术,以及大数据技术中的:hadoop(大数据第一技术)、hbase、spark、storm、mahout等。
commons-io工具包
Apache的commons-io工具包中提供了IOUtils/FileUtils,为我们提供了更加简单、功能更加强大的文件操作和IO流操作功能。非常值得大家学习和使用。
下载与添加commons-io包
下载地址
https://commons.apache.org/proper/commons-io/download_io.cgi
添加jar包