我这些学习笔记,记录的都是我自己认为的知识点,可能以后再看的时候还要翻书,但是可以用来定位到准确的书中示例的位置,减少翻书重找的时间,利于自身知识体系的搭建。 self-transcendence
第15章 I/O
15.1 流概述
流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流。I/O(Input/Putput)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。虽然I/O流通常与磁盘文件存取有关,但是程序的源和目的地也可以是键盘、鼠标、内存或显示器窗口等。
Java由数据流处理输入/输出模式,程序从指向源的输入流中读取源中的数据,源可以使文件、网络、压缩包或其他数据源。
输出流的指向是数据要到达的目的地,程序通过向输入流中写入数据把信息传递到目的地,输出流的目标可以使文件、网络、压缩包、控制台和其他数据输出目标
---------------------------------------------------------------------
15.2 输入/输出流
Java定义了许多专门负责各种方式的输入/输出,这些类都放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流)或抽象类Reader(字符输出流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或者抽象类Writer(字符输出流)的子类。
15.2.1 输入流
InputStream类是字节输入流的抽象类,是所有字节输入流的父类。
该类中所有方法遇到错误时都会引发IOException异常。
A. read():从输入流中读取数据的下一个字节。返回0-255范围内的int字节值。如果因为已经达到流末尾而没有可用的字节,则返回-1
B. read(byte[] b):从输入流中读入一定长度的字节,并以整数的形式返回字节数。
C. mark(int i):在输入流当前位置放置一个标记,i参数告知此输入流在标记位置失效之前允许读取的字节数。
D. reset():将输入指针返回到当前所做的标记处。
E. skip(long n):跳过输入流上的n个字节并返回实际跳过的字节数。
F. markSupported():如果当前流支持mark()/reset()操作就返回true。
G. Close():关闭此输入流并释放与该流关联的所有系统资源。
并不是所有的子类都支持inputStream定义的所有方法,如skip()、mark()、reset()等只对某些生效。
Java中的字符是Unicode编码,是双字节的。inputStream是用来处理字节的,并不适合处理字符文本。Java为字符文本的输入专门提供了一套单独的类Reader,但Reader类并不是Inputstream类的替换者,只是在处理字符串时简化了编程。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。
15.2.2 输出流
OutputStream类是字节输出流的抽象类,是所有输出字节流的父类。
该类所有的方法均返回void,错误会引发IOException异常。
A. write(int b):将指定的字节写入输出流
B. write(byte[] b):将b个字节从指定的b写入输出流
C. write(byte[] b,int off,int len):指定b数组中从偏移量off开始的len个字节写入输出流
D. flush():彻底完成输出并清空缓存区
E. Close():关闭输出流
Writer类是字符输出流的抽象类,所有字符输出类的实现都是他的子类。
----------------------------------------------------------------------
15.3 File类
File类是唯一代表磁盘文件本身的对象。File类定义了一些与平台无关的方法来操作文件,可以通过调用file类中的方法, 实现创建、删除、重命名文件等操作。File类的对象主要用来获取文件本身的一些信息,如文件所在的目录、文件的长度、文件读写权限等。数据流可以将数据写入到文件中,文件也是数据流最常用的数据媒体。
15.3.1 文件的创建与删除
可以使用file类创建一个文件对象。通常用以下3钟构造方法来创建文件对象:
A. File(String pathName):通过给定字符串,转换为抽象路径来创建一个File实例。
File file=new File(“d:/1.txt”);
B. File(String parent,String child):根据定义的父路径和子路径字符串创建一个新的file对象
File file=new File(“d:/doc/”,”1.txt”);
C. File(File f,String child):根据parent抽象路径名和child路径名字符串创建一个新的File
File file=new File(“d:/doc”,”1.txt”);
当通过实例化file创建一个文件对象时,如果该路径上没有就创建一个文件,如果有就会先删除后创建。
15.3.2 获取文件信息
File类提供了很多方法用于获取一些文件本身信息:
方法 | 返回值 | 说明 |
getName() | String | 获取文件的名称 |
canRead() | Boolean | 判断文件是否为可读的 |
canWrite() | Boolean | 判断文件是否可被写入 |
exits() | Boolean | 判断文件是否存在 |
length() | Long | 获取文件的长度(以字节为单位) |
getAbsolutePath() | String | 获取文件的绝对路径 |
getParent() | String | 获取文件的父路径 |
isFile() | Boolean | 判断文件是否存在 |
isDirectory() | Boolean | 判断文件是否为一个目录 |
isHidden() | Boolean | 判断文件是否为隐藏文件 |
lastModified() | long | 获取文件最后修改时间 |
-------------------------------------------------------------------
15.4 文件输入/输出流
程序运行时,大部分数据都在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存到文件中。
15.4.1 FileInputStream与FileOutputStream类
FileInputStream类和FileOutputStream类都用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream类,该类继承自InputStream类。FileOutputStream提供基本的文件写入能力,是OutputStream的子类。两个类的构造方法如下:
a. FileInputStream(String name) FileOutputStream(String name)
b. FileInputStream(File file) FileOutputStream(File file)
15.4.2 FileReader和FileWriter类
FileInputStream与FileOutputStream是对字节或字节数组进行读取,但是汉字占用两个字节,使用字节流可能会出现乱码现象,而FileReader和FileWriter就是用来操作字符流的。
------------------------------------------------------------
15.5 带缓存的输入/输出流
缓存是I/O的一种性能优化。缓存流为I/O流增加了内存缓存区。有了缓存区才使得skip mark reset方法可以实现。
15.5.1 BufferedInputStream与BufferedOutputStream类
BufferedInputStream类对所有InputStream类进行带缓存区的包装以达到性能的优化。
A. BufferedInputStream(InputStream in)
B. BufferedInputStream(InputStream in,int size)
一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。
字节数据读取文件的过程:文件---->InputStream---->BufferedInputStream---->目的地
BufferedOutputStream输出信息跟OutputStream输出信息完全一样,只不过前者有一个flush()方法将缓存区的数据强制输出完。
A. BufferedOutputStream(InputStream in)
B. BufferedOutputStream(InputStream in,int size)
Flush()方法用于缓存区没有满,也将缓存区内容强制写到外设,习惯上叫这个过程为刷新。
Flush()方法只对使用缓存区的OutputStream类的子类有效。
调用close()时,系统在关闭流之前,也会将缓存区中的信息刷新到磁盘文件中。
两个A构造方法都是创建一个有32个字节的缓存区,两个B构造方法都是以指定的大小来创建缓存区
15.5.2 BufferedReader与BufferedWriter类
BufferedReader与BufferedWriter类分别继承Reader和Writer类。具有内部缓存机制,并可以以单位进行输入/输出。字符数据读取文件的过程:
字符数据--->BufferedWriter--->OutputStreamWriter--->OutputStream--->文件
BufferedReader常用方法:
A. Read()方法:读取单个字符串
B. readLine()方法:读取一个文本行,并将其返回为字符串。若无数据则返回null
BufferedWriter类中都返回void,常用方法如下:
A. Write(String s,int off,int len)方法:写入字符串的某一部分
B. Flush()方法:刷新该流的缓存
C. newLine()方法:写入一个行分隔符
使用BufferedWriter类的write方法时,数据并没有立刻被写入输入流,而是先进入缓存区中。如果想立刻将缓存区的数据写入输出流,一定要调用flush()方法。
----------------------------------------------------------------------
15.6 数据输入/输出流
DataInputStream类与DataOutputStream类允许应用程序以与机器无关的方式从底层输入流中读取基本java数据类型。即读取数据时,不必关心这个数值是那种字节。构造方法如下:
A. DataInputStream(InputStream in):使用指定的基础InputStream 创建一个DataInputStream
B. DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。
DataOutputStream类提供了如下3种写入字符串的方法。
A. writeBytes(String s)
B. writeChars(String s)
C. writeUTF(String s)
Java中的字符是Unicode编码,是双字节的,writeBytes只是将字符串中的每一个字符的低字节内容写入目标设备中;而writeChars将字符串中的每一个字符的两个字节的内容都写到目标设备中;writeUTF将字符串按照UTF编码后的字节长度写入目标设备,然后才是每一个字节的UTF编码。
DataInputStream类提供了一个readUTF()方法返回字符串。这是因为要再一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream类中只有writeUTF()方法向目标设备中写入字符串的长度,所以也能准确地读回写入字符串。
-------------------------------------------------------------
15.7 zip压缩输入/输出流
如果要从zip压缩管理文件内读取某个文件,要先找到对应该文件的“目录进入点”,才能读取这个文件的内容,写文件也是一样。
Java实现了I/O数据流与网络数据流的单一接口,因此数据的压缩、网络传输和解压缩的实现比较容易。ZipEntry类产生的对象,是用来代表一个zip压缩文件内的进入点。
15.7.1 压缩文件
利用ZipOutputStream类对象,可以将文件压缩为zip文件
ZipOutputStream(OutputStream out)
方法 | 返回值 | 说明 |
putNextEntry(ZipEntry e) | void | 开始写一个新的ZipEntry,并将流内的位置移至此entry所指数据的开头 |
Write(byte[] b,int off,int len) | void | 将字节数组写入当前zip条目数据 |
Finish() | void | 完成写入zip输出流的内容,无须关闭它所配合的OutputStream |
setComment(String comment) | void | 可设置此Zip文件的注释文件 |
每一个zip文件中可能包含多个文件。写入目标zip文件时,必须先使用putNextEntry方法,写入个别文件的entry,将流内目前指到的位置移到该entry所指的开头位置。
15.7.2 解压缩zip文件
利用ZipInputStream类读取zip压缩文件,包括已压缩和未压缩的条目(entry)。
ZipInputStream(InputStream in)
方法 | 返回值 | 说明 |
Read(byte[] b,int off,int len) | int | 读取b数组内off偏移量的位置,长度是len字节 |
Available() | int | 判断是否已读完目前entry所指定的数据。是0否1 |
closeEntry() | void | 关闭当前ZIP条目并定位流以读取下一条目 |
Skip(long n) | long | 跳过当前ZIP条目中指定的字节数 |
getNextEntry() | ZipEntry | 读取下一个ZipEntry,将将流内的位置移至该entry所指数据的开头 |
createZipEntry(String name) | ZipEntry | 以指定的name参数新建一个ZipEntry对象 |
使用ZipInputStream类来解压文件,必须先使用ZipInputStream类的getNextEntry()方法来取得其内的第一个ZipEntry