黑马程序员-Java基础总结11——IO流(二)
------- android培训、java培训、期待与您交流! ----------
内容:
打印流(PrintStream与PrintWriter)、序列流(合并流/SequenceInputStream)、
对象流(ObjectInputStream与ObjectOutputStream)、
管道流(PipedInputStream与PipedOutputStream)、
RandomAccessFile(直接操作文件类)、数据流与字符编码
———————————————IO流中的其他流——————————————
十、IO流中的其他流:
1、打印流: 该流提供了打印方法,可以将各种数据类型的数据都原样打印。
打印流PrintStream、PrintWriter,可使用print类的打印方法(print、printf、println等),这两个流都是能直接操作文件的IO流。(它们属于装饰类,可为其他流提供这些打印功能)。
PrintStream : 可直接写入字符串,然后将这些数据以字节流形式输出流或存储到文件中;
PrintWriter : 直接写入字符串数据,将数据以字符流形式输出。
PS: printf : 打印带格式的语句
2、序列流(合并流): SequenceInputStream ;
将多个流合并成一个流(即提取多个流中数据合并到一个流);
序列流构造函数使用参数:
InputStream : 直接传入输入流,不过只能传入两个。
Enumeration extends InputStream> : 枚举(List集合中Vector的特有功能)
(如果要合并两个以上的流就需要使用 带枚举的构造函数)
注意: 由于Vector效率较低,而SequenceInputStream接收的也只是实现枚举的实例化对象,因此可通过(带名字的)匿名内部类(实现Enumeration接口),并结合ArrayList及迭代器(iterator)存储输出数据到枚举方法中。
【实现格式: 】
ArrayList al = new ArrayList();
final Iterator it = al.iterator();
(因为匿名内部类访问的外部类中的 局部变量 必须是被 final 所修饰的)
3、切割文件: (这不是一个流,而是一种实现方式,即可操作的功能)
思路:
1、定义一个数据存储容器(指定数据存储大小);
2、定义计数器(计数读写次数,可便于大文件分割的使用,因为数据操作内存有限);
3、读写一定数据后(满足计数器的定量后),关闭输出流,开启新的存储数据的流以及文件,直到可操作数据结束。
由于读取写入数据时使用的时系统内存,而操作数据的临时内存通常为64MB,所以可以定义多个数据容器,每次提取一部分数据输出到流中(进行计数),但满足一定次数时可以关闭流对象,开启新的流对象进行存储(即可实现切割文件的操作)
——————————————对象流——————————————
十一、对象流: ObjectInputStream 与 ObjectOutputStream ;
从文件中读取对象的属性信息或存储对象的属性信息到文件中 的流。
代码示例:
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.Object"));
Person p = (Person)ois.readObject();
可被操作的类对象(Person)的基本需要:
对象的序列化: (存储文件的后缀名一般为.Object格式。)
1、实现java.io.Serializable接口(这是一个标志接口,即没有可操作方法的接口);
2、使用默认或自定义UID序列号,用于给jvm虚拟机标识(知道该文件是序列化类);
3、当源文件类属性发生改变(增删属性或修饰符等)时,该文件的序列化也将发生改变;
(因为该UID号是根据类中成员属性计算得出的)
4、要使旧的文件还能和修改后的匹配数据,最好是自定义UID序列化。
自定义UID序列号: public static final long serialVersionUID = 42L; (等)
注意: 静态static修饰的类变量(属性),不能被序列化;【属于静态区,非堆内存中数据】
被transient修饰的类变量也不能被序列化。
【transient修饰变量只在堆内存中存在而不能存储到文本文件中】
因为序列化是将堆内存中的类的变量存储到文本文件中(transient修饰的变量不可序列化)。
1、Object流方法:
writeObject() : 写入一个对象的属性到文件中;
(注意: 在结束对象的写入后要在末尾添加写入"null"这个对象,作为结束标识)
readObject() : 每次读取文件中的一个对象(但是是带标识的,所以迭代提取)。
(有null结束标识才能在读取到文件结尾处判断是否null,否则会抛出EOFException异常)
2、输出文件只能是复写,不能在文件末尾追加,否则抛出StreamCorruptedException异常。
——————————————管道流—————————————————
十二、管道流: PipedInputStream 与 PipedOutputStream
涉及多线程的IO流: PipedInputStream、PipedOutputStream
注: 在IO流中既可以输入流读取数据、然后由输出流输出;(IO流中绝大部分流是这样)
也可以写入数据到输出流中,然后传递到输入流缓冲区,由其读出数据后进行操作。
(管道流就是后者这种功能,主要用于Java组件间的数据传递)
连接管道流代码:
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out); : 将读取流连接到对应的输出流。
【在不同线程(run方法中)执行对管道输出流写入数据或从管道输入流读取数据】
管道流应用: 可实现在A组件(例:GUI的对话框)输入数据,由管道输出流输出该数据,传递给B组件中管道读取流,然后在B组件中对数据进行处理或打印等。
扩展性: 输出流,可接收不同源的数据(文件或键盘录入到指定文本框);
读取流,可根据需要输出不同格式的数据或其他处理功能。
管道流方法:
write(byte[] b, int off,int len) : 输出流写入数据方法;
read(byte[] b, int off,int len
); : 读取流读取数据方法,是阻塞式方法(在没获取到数据时会等待直到有数据输入,所以管道流的读取、输出必须是存在于多线程,两者要分开,不然会死锁。)
——————————————RandomAccessFile——————————————
十三、RandomAccessFile:
RandomAccessFile直接继承自Object类,可直接操作文件,且读取、写入均可执行。
(此流,既能读取文件也能写入数据到文件中,因为其内部实现了DataInput和DataOutput接口(DataInputStream和DataOutputStream也各自实现该接口),没有使用InputStream和OutputStream提供的功能,完全独立的类,不属于IO流的子类)
构造函数:
RandomAccessFile(File file,String mode)等 :
创建从中读取和向其中写入(可选: 通过指定mode的数值)的随机访问文件流;
mode操作文件模式: "r" (只读) 、 "rw"(读写);
还有 "rws"和"rwd"(是基于"rw",但要求不同程度的更新数据到底层存储设备。)
功能: 随机读取/写入数据到文件(只能操作文件),因为该流存在文件指针(类似byte[]数组),可通过调整文件指针(可向前、向后)或跳过指定字节数(只能向后)来随机访问(读写)数据。
应用: 因为可通过调整文件指针控制数据的读取/写入位置,所以可结合多线程使用,分段读取、写入(例:分段下载程序)文件,实现多线程同时操作文件功能。(重点应用功能)
方法: (详见java.io.RandomAccessFile类)
readInt(); : 读取一个4字节的整数;
writeInt(); : 写入一个4字节的整数;
……………………………………………
seek(long pos) : 控制文件指针的位置;
skipBytes(int n) : 读取数据时跳过指定数量的字节(跳过只能向后);
———————————数据流与字符编码———————————————
十四、操作数据流与字符编码:
1、操作基本数据类型的流: DataInputStream、DataOutputStream ;
2、内存中操作数据的流 : (没有调用底层资源,关闭流无效)
A、字节数组流 : ByteArrayInputStream、ByteArrayOutputStream;
B、字符数组流:CharArrayReader、CharArrayWriter;
C、字符串流:StringReader、StringWriter;
字符编码:
ASCII : 美国标准信息交换代码(拉丁字母编码);
GBK : 汉语编码,汉字占两字节;
UTF-8 : 万国码,汉字占三字节;
UTF-8修正 : 万国码修正版,汉字占四字节;
ISO8859-1 : 欧洲字母编码表,同ASCII无汉字等字符;
【PS: 中文系统默认编码: GBK,网址(Tomcat)服务器默认编码: ISO8859-1。】
知识点小统计:
装饰流: 缓冲流(BufferedStream,例: LineNumberReader等)、操作基本数据流(DataInputStream/DataOutputStream);
直接操作文件的流: 打印流(PrintStream、PrintWriter)、File类流等;
结合多线程使用的IO流: 管道流(至少两个线程读取、写入)、RandomAccessFile。