IO流
- 文件从硬盘输入到内存中产生输入流(InputStream)。读。
- 文件从内存输出到硬盘中产生输出流(OutputStream)。写。
- 有的流是按照字节的方式读取数据,一次读取一个字节,什么类型的文件都可以读取。
- 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的。连word文件都无法读取。
- java中所有的流都是在java.io包下。
- java.io.InputStream 字节输入流
- java.io.OutputStream 字节输出流
- java.io.Reader 字符输入流
- java.io.Writer 字符输出流
- 这四个首领都是抽象类。
- 所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。用完之后一定要关闭。
- 所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。输出流在最终输出之后,一定要记得flush()刷新一下,表示将通道当中剩余未输出的数据强行输出完(清空管道)。没有刷新的话可能会导致数据丢失。
文件专属:
- java.io.FileInputStream
- java.io.FileOutputStream
- java.io.FlieReader
- java.io.FlieWriter
转换流(将字节流转换成字符流)
- java.io.InputStreamReader
- java.io.OutputStreamWriter
缓冲流专属
- java.io.BufferedReader
- java.io.BufferedWriter
- java.io.BufferedInputStream
- java.io,BufferedOutputStream
数据流专属
- java.io.DataInputStream
- java.io.DataOutputStream
标准输出流
- java.io.PrintWriter
- java.io.PrintStream
对象专属流
- java.io.ObjectInputStream
- java.io.ObjectOutputStream
FlieInputStream流
- 这流是抛出异常的,所以要解决编译时异常。
- 关闭流的前提是流不是空(idea中输入ifn)。
- 它的一个方法read();返回的是一个int类型的字节也就是字节本身,比如说文件中的是a,那么返回的是97。文件读取的时候和指针差不多,刚开始针指向最前面,调用read就往后移一个字节,就返回那个数据。没东西的话就返回-1。一次只能读取一个字节。
- 还可以读取一个byte数组长度的字节。但是这个方法读取到的是字节的数量,而不是字节本身。而且注意,每次调用此意read(byte)后,这个里面的byte数组里面的元素是从前往后一次占用,而后面的元素如果没有被占用,则保持不变。当把byte数组变成String类型后,就可以输出byte数组中的元素,但是也会重复输出,具体看程序。所以应该转换成字符串的时候应该是读取多少个就转换多少个,因此调用String的另一个构造方法。String(byte数组,起始下标,读取数的元素)。
- int available();返回流中剩余没有读到的字节数量。可以一上来就调用这个方法,来知道总字节的数量。而且读的指定的byte数组里面的容量可以写成这个方法,这样就不用循环了。但是不适合太大的文件,因为byte数组不能太大。
- long skip(long n);跳过几个字节不读。
FileOutputStream流
- 文件try的最后一定要刷新。
- write(byte)方法是写入数据。write(byte,0,2);是吧byte数组的一部分写入。
- FileOutputStream有两个构造方法。第一:参数只是文件名的话,会把这个文件清空然后再写入。第二:参数是文件名,加一个true,这样写入的话是追加的文件后面,而不是清空文件。
- 如果想要写入字符串,可以吧字符串转换成byte数组。
- String s=“我是一个中国人”;
- byte[] ms=s.getBytes();
文件的复制
- D盘的文件到C盘,需要先到内存。首先先读(输入)到内存,然后再写(输出)到C盘,过程是一边读一边写。
FileReader流
- 文件字符输入流,只能读取文本。快捷方便。
- 只不过之前是byte数组,现在是char数组就可以了。
FileWrite流
- 和上面的FileOutputStream一样但是只支持普通文本。
BufferedReader缓冲区流
- 使用这个流的时候不需要自定义byte或char数组,自带缓冲。
- 它的构造方法里面的参数不是一个文件名,而是一个Reader类。但是Reader它是一个抽象类,不能实例化对象,但是可以靠它的子类,例如FileReader。而且这个参数只能传字符流,不能传字节流,但是可以用InputStreamReader和OutputStreamWriter转换成字符流。这两个流构造方法里面的参数是一个字节流。
- 当一个流的构造方法需要一个流的时候,这个被传进来的流叫做节点流。外部负责包装的这个流叫做包装流或处理流。关闭流的时候只需要关闭包装流就可以了。
- 里面有个方法ReadLine()方法,读一行但不包括最后的换行符,输出String字符串。直到变成null,就会停止输出。
File类
- File不能完成文件的读和写。
- 一个File对象对应的有可能是目录,也可能是文件。
- 创建file对象,参数是一个路径。
- file.exists()判断文件是否存在。
- file.createNewFile(),以文件的形式创建一个文件。
- file.mkdirs(),以目录的形式创建。如果想要创建多重目录,直接在File的参数后面跟加多重目录的名字,中间用\隔开。
- file.getParent(),获取文件的父路径,返回值是个字符串。
- file.getAbsoultePath(),获取这个文件的绝对路径。
- file.getName(),获取文件名。
- file.isFile(),是否是一个文件。
- file.isDirectory(),判断是否是一个目录。
- file.lastModified(),文件最后一次修改时间,返回的是long类型的毫秒。从1970年到现在的总毫秒数。
- file.length(),获取文件大小,单位是字节。
- file.listFiles(),方法获取当前目录下的所有子文件,返回的是一个文件类的数组。
对象的序列化和反序列化
- 序列化(Serialize):就是把一个java对象从内存拆分,一个一个传进硬盘文件的过程。反序列化(DeSerialize)就是反过来。
- ObjectOutputStream就是负责序列化的,ObjectInputStream就是负责反序列化的。
- 参与序列化和反序列化的对象,必须实现Serializable接口。
- 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。
- 对应的,如果我们想要在网络上进行文字传输,或者想要将程序内存中的对象写入到硬盘,可以用任何的虚拟机进行解析读取。也需要一个共同识别的方式,字节码!!!而我们的java序列化就是将java内存中对象属性的值进行字节码转换。
- Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在。即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在 将来重新读取 被保存的对象。Java对象序列化就能够帮助我们实现该功能。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。
- 除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。Java序列化API为处理对象序列化提供了一个标准机制。
- 简而言之:序列化的作用就是为了 不同jvm之间 共享实例对象 的一种解决方案.由java提供此机制,效率之高,是其他解决方案无法比拟的.
- 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
- 序列化也可以序列化多个对象,就是把对象放到集合当中。
- transient关键字,可以使某个属性游离,然后序列化的时候就不会把里面的值序列化进去,反序列化后输出的值是默认值0或null。
- 当一个类实现了Serializable接口后,相当于给这个类自动生成一个序列化版本号。即使两个类名字一样,JVM也会区分开。但是这种自动生成序列号也会有不好之处,十年前编译生成这个类,如今想要在这个类里面改点东西,再编译后就会生成新的序列号,导致原先的反序列号不能用了。所以这种方法就是不能修改源代码。所以建议把版本序列号手动的写出来。
- private static final long serialVersionUID=2912391391280912947L;
- java采用什么区分类的:第一,先根据类名区分。第二,后根据系列化版本号进行区分。
IO和Properties的联合使用
- 当某个信息需要经常变化,而且经常要提取出来,则这些信息可以写到文件当中。
- 等号左边做key,右边做value。
- 类似与这样的文件叫做配置文件。内容是:key=value的时候,这种配置文件叫做属性配置文件。而且这种文件名最好是以.properties结尾。
- 属性配置文件中#号是注释。