第六部分 IO流
File类
目录与文件的一个统称,用于操纵目录与文件,并不能读取数据,只能创文件不能创目录
目的:防止因为对象的消失而产生的数据丢失
构造方法
常量
因为操作系统的不同所以获取获取文件对象时我们采用File f=new File("d:"+File.separator);
普通方法
单元测试
IO流:(流用完一定要close)
重点字节流和字符缓冲流和打印流
4个父类都是抽象类
输入输出是针对程序来说的
输入指的是将内容从文件(硬盘)中输入到程序,(通过system.out方法将内存读到控制台),读到程序中某个变量的内存空间中
输出流指的是从程序向文件(硬盘)中写入数据,输出流只要一创建,就默认写入一个空格
如果想向文件中写入汉字,空格,换行等只能使用字符流来实现
功能上分为:1.节点流 :直接插到数据源上 2.处理流:套在节点流上 :缓冲流、转换流、数据流
FileInputStream(文件字节输入流)
第一个read方法,对于文件的读取,相当与指针指在了第一个位置,每调用一次read方法指针就会移动到下一个位置,当读取int值为-1的时候证明数据读取完毕
第二个read方法,代表的不是一个数组,而代表的是字节数组元素的个数。把读出的元素存入到一个byte数组里
注意:1.read()返回值是int型,所以输出要转换为char
2.流用完一定要close
FileOutputStream
1.覆盖写
FileOutputStream(String name)创建一个向具有指定名称的文件中写入数据的输出文件流。
2.追加写
FileOutputStream(String name, boolean append)创建一个向具有指定name的文件中写入数据的输出文件流。
假如一个文件中有很多内容,想要把它输入到另一个文件中,这时程序其实只运行了一次,所以不会产生覆盖,也就是说当复制一个图片的时候,虽然一个图片的字节有很多,但是这些字节都是在程序一次运行内复制到另一个文件中的,所以不会产生覆盖
Append:如果值为false代表的是从头插入数据,如果为true则代表的是程序再次运行从尾部插入数据
注意:对于输出流向一个文件中写入数据的时候如果没有该文件则会自动创建一个文件,但是不能创建文件夹,每读取一个字节都会存放在byte类型数组当中,当数组满了之后会一次性的读取出来,所以这个数组在这里起到了一个缓冲的作用,目的是提高效率。
off-数据中的起始偏移量,len-要写入的字节数。
如何写入字符串? 字符串有一个方法 getBytes()可以把字符串转换为字节,然后存到字节数组然后写入
字符流
特点:每次操作的是一个字符
1.字符输入流Reader :能读取字符数组了! 字符流读到结尾等于null ,也就证明数据读取完毕
文件字符输入流FileReader
方法类似
2字符输出流Writer:能输入字符数组了!
文件字符输出流FileWriter
特有方法
FileInputStream in =new FileInputStream(“path”);
将一根管道插入文件准备操作,path是字符串(双引号!)
例题:1.读一文件字节(),将读出的字节写入到另一文件
2.读文件,将读出来的字节存到一个字节数组中,然后将数组中的字节写入到文件中
注:针对节点流,文件读到末尾都是等于 -1
对于字节流与字符流的使用场景
1字节流一般读写的都是.jpg.exe .zip这样单位是字节的文件
2字符流一般读写的都是文本文件.txt .doc.ppt以字符为单位的文件
缓冲流
其实内部也是封装了字节数组。没有指定缓冲区大小,默认的字节是8192
缓冲流好处:没有缓冲区就像逛超市没有推车一样,一次只能拿一样东西,缓冲却可以让你把东西装满后再去结账
BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream
提高效率,减少读写次数,当缓冲区数据充满的时候会自动的把数据一些性写入或者读出,保护硬盘,套在节点流上,参数是节点流
FileWriter fw=new FileWriter(“path”)
BufferedWriter bufw=new BufferedWriter(fw);
方法(字符流)
newLine()写入一个空行
readLine()读一行
flush()
因为有一些IO流用的是缓冲方式:它有个缓冲区,一般得等到缓冲区满才写入文件。动态调用flush则不管缓冲区满不满,立即写到文件。如果最后缓冲区没满而关闭流,则会导致数据丢失。其实大多数流的close()方法都自动调用了flush方法
当读入的文件到结尾readLine=null
转换流
从字节流----》转换为字符流
InputStreamReader输入转换流字符流处理流
OutputStreamWriter输出转换流字符流处理流
它们有转换作用,而本身又是字符流。所以在构造方法内的参数是字节流
控制台输入:
BufferedRead br=new BufferedRead(new InputStreamReader(System.in))
数据流
可以把基本类型直接写入文件和从文件中读出(专门用网络间的数据传递)
DataInputStream
DataOutputStream。
对象流
将一个对象整体输入到文件中
序列化:把对象存入到文件中
1.将节点流插到文件上,将处理流套到节点流上
FileOutputStream fileStream=new FileOutputStream("path");
ObjectOutputStream os=new ObjectOutputStream(fileStream);
2.写入对象
os.writeObject( );
3.关闭流
os.close() 关闭流的时候只关闭处理流就可以了
对象被序列化的过程究竟都发生了什么?
(1)在堆上创建对象
(2)对象被碾平也就是被序列化,进入到了对象流中
(3)经过字节流,值被抽出到流上和虚拟机所需要的信息一起被保存到文件中
当一个对象的实例变量是引用的时候,会自动将其引用也进行序列化,类似集合被序列化的时候,集合所包含的对象也会被序列化
如何实现序列化
实现Serializable,这个接口是一个标记接口,因为其中没有任何方法要实现,唯一目的是说明此类是可以被序列化的,若父类是可被序列化,那么它的子类也是可以被序列化的。如果想要哪个实例变量不能被序列化,那么就用transient修饰,静态变量也不会被初值化(或者实现externaliable是serializable的一个子接口,可以控制序列化的过程,而serializable是虚拟机自动控制了)
反序列化:把对象从文件中获取出来
1.将节点流插到文件上,将处理流套到节点流上
FileInputStream fileStream=new FileInputStream("path");
ObjectInputStream os=new ObjectInputStream(fileStream);
2.读取对象
Object one=os.readObject()
3.转换对象类型
Game g=(Game)one
4.关闭流
os.close()
在解序列化的过程中,所有类都必须能让Java虚拟机找到,就是类要写上
private static final long serialVersionUID = 1L;
对象序列化的时候所遇到的问题:
InvalidClassException
该类的序列版本号与从流中读取的类描述符的版本号不匹配,该类包含未知数据类型,该类没有可访问的无参数构造方法(类中未定义版本号)
EOFException
该异常针对于对象流,其它流的读到文件的末尾一般返回的是-1或者是null对象特殊返回的是一个异常
内存流(了解)
ByteArrayInputStream 写出
ByteArrayOutputStream 写入
ByteArrayInputStream主要完成将内容从内存读入程序之中,而ByteArrayOutputStream的功能主要是将数据写入到内存中。(与常规的输入输出流正好相反)。
我们从网上下载的资源例如音乐小文本一些小的文件不适合直接存储到本地磁盘当中,需要进行处理,这个时候会把这些数据存入到内存当中,内存流的本质其实就是一个动态数组
注:输入输出是针对程序来说的
字节数组中先写进什么,就要先输出什么,先进先出类似队列
打印流(了解)
PrintStream字节打印流
它的构造函数可以接收三种数据类型的值。
1,字符串路径。
2,File对象。
3,OutputStream。
print方法和write方法的区别在于,print提供自动刷新.
普通的write方法需要调用flush或者close方法才可以看到数据.
网络间传输要换行和flush不然无法读取
PrintWriter字符打印流
是一个字符打印流。构造函数可以接收四种类型的值。
1,字符串路径。
2,File对象。
对于1,2类型的数据,还可以指定编码表。也就是字符集。
3,OutputStream
4,Writer
FileWriter fw = new FileWriter("C:\\log.txt", true);
PrintWriter log = new PrintWriter(fw,true);
注意:PrintWriter的构造方法的第二个参数,只有true才会自动flush。
可以向文件中打印各种数据包括基本数据和引用类型
序列流,合并流
SequenceInputStream表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。