天天看点

黑马程序员-Java基础总结11——IO流(二)

黑马程序员-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<InputStream> al = new ArrayList<InputStream>();       
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。