彻底攻克java流
类图1:
IO分两种流
字节流 InputStream OutputStream
字符流 Reader Writer
他们都是抽象类
具体实现
字节流 FileInputStream FileOutputStream
字符流 FileReader FileWriter
字节流转换成字符流可以用 InputSteamReader OutputStreamWriter
转换成BufferdReader BufferedWriter 他们具有缓冲区
例如:读取文件 从字节流输入到字符流输入
定义一个字节流:
FileInputStream fileInputStream = new FileInputStream("d:/text.txt"); // 定义一个指向D:/TEXT.TXT 的字节流InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);//字节流转换成InputStreamReaderBufferedReader bufferedReader = new BufferedReader(inputSteamReader);//InputStreamReader 转换成带缓存的bufferedReader
可以把读出来的内容赋值给字符
String ss = new String();String s;while((s = bufferedReader.readLine())!=null){ss += s;}
例如:写入文件 从字节流输出到字符流输出
FileOutputStream fileOutputStream = new FileOutputStream("d:/text.txt"); //定义一个指向D:/TEXT.TXT文件 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);bufferedWriter.write(s);bufferedWriter.close();outputStreamWriter.close();fileOutputStream.close();




上面这个图向我们传达了这个信息:链接流链接流对象接收一个原始流对象或者另外一个链接流对象作为流源;另一方面他们对流源的内部工作方法做了相应的改变,这种改变是装饰模式所要达到的目的。比如:
BufferedInputStream“装饰”了InputStream的内部工作方式,使得流的读入操作使用了缓冲机制。在使用了缓冲机制后,不会对每一次的流读入操作都产生一个物理的读盘动作,从而提高了程序的效率,在汲及到物理流的读入时,都应当使用这个装饰流类。
LineNumberInputStream和PushbackInputStream也同样“装饰”了InputStream的内部工作方式,前者使得程序能够按照行号读入数据;后者能够使程序读入的过程中,退后一个字符。
DataInputStream子类读入各种不同的原始数据类型以及String类型的数据,这一点可以从它提供的各种read方法看出来,如:readByte(),readInt(),readFloat()等。
使用基本原则:
根接口是InputStream/OutputStream充当数据源的IO类有FileInputStream/FileOutputStream,ByteArrayInputStream / ByteArrayOutputStream 等,充当装饰功能的IO类有BufferedInputStream / BufferedOutputStream,DataInputStream / DataOutputStream等, 它们都是继承装饰接口FilterInputStream/FilterOutputStream。使用IO时,首先创建一个数据源IO,然后根据需要的功能创建装饰类IO,其构造函数的参数为已创建的数据源IO常用类举例说明:
FileInputStream和FileOutputStream
简单略
ObjectOutputStream和ObjectInputStream
这个流的作用是,直接将一个对象转换为字节流,对象必须implements Serializable
package demo;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class ObjectStreamTest{ public static void main(String[] args) { T t = new T(); t.k = 15; try { FileOutputStream fos = new FileOutputStream("d:/333.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(t); fos.close(); oos.close(); } catch (IOException e) { e.printStackTrace(); } try { FileInputStream fis = new FileInputStream("d:/333.txt"); ObjectInputStream ois = new ObjectInputStream(fis); T t2 = (T) ois.readObject(); System.out.println(t2.i); System.out.println(t2.k); System.out.println(t2.s); System.out.println(t2.j); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }}@SuppressWarnings("all")class T implements Serializable{ int i = 20; short j = 10; String s = "hello"; int k = 100;}
DataInputStream和DataOutputStream
这个是数据流.给我们直接处理基本数据类型的接口,举个最基本的例子,如果我们要将一个float类型的数据写入文件,我们需要先转换成String类型,然后转换成字节数组,这样才能存入..现在我们可以直接用DataInputStream和DataOutputStream来解决这个问题
package demo;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;public class DataStreamTest{ public static void main(String[] args) { //ByteArrayOutputStream可以临时缓存一个对象的字节数组 ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); try { dos.writeChar('d'); dos.writeInt(10); dos.writeShort(50); } catch (IOException e) { e.printStackTrace(); } ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());//ByteArrayOutputStream的用法 DataInputStream dis = new DataInputStream(bais); try { System.out.println(dis.available()); System.out.println(dis.readChar()); System.out.println(dis.readInt()); System.out.println(dis.readShort()); } catch (IOException e) { e.printStackTrace(); } try { dos.close(); dis.close(); } catch (IOException e) { e.printStackTrace(); } }}
BufferedInputStream和BufferedOutputStream
BufferedInputStream当使用read()方法时,实际上是先读取buf中的数据,而不是直接对数据来源作读取。当buf中的数据不足时,BufferedInputStream才会再实现给定的InputStream对象的read()方法,从指定的装置中提取数据。
BufferedOutputStream当使用write()方法写入数据时实际上会先将数据写到buf中,当buf已满时才会实现给定的OutputStream对象的write()方法,将buf数据写到目的地,而不是每次都对目的地作写入的动作
package demo;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class BufferedStreamDemo{ public static final void copy(File srcFile, File distFile) throws IOException { FileInputStream fin = null; BufferedInputStream bis = null; FileOutputStream fout = null; BufferedOutputStream bos = null; try { if (distFile.exists()) { distFile.delete(); } byte[] data = new byte[1024]; fin = new FileInputStream(srcFile); bis = new BufferedInputStream(fin); fout = new FileOutputStream(distFile); bos = new BufferedOutputStream(fout); int readCount = 0; while ((readCount = bis.read(data)) != -1) { bos.write(data, 0, readCount); } // 将缓冲区中的数据全部写出 bos.flush(); } finally { try { if (bos != null) { bos.close(); } } catch (IOException e) { } try { if (bis != null) { bis.close(); } } catch (IOException e) { } try { if (fin != null) { fin.close(); } } catch (IOException e) { } try { if (fout != null) { fout.close(); } } catch (IOException e) { } } } public static void main(String[] args) { try { BufferedStreamDemo.copy(new File("c:\\test1.abs"), new File("c:\\test2.abs")); } catch (IOException e) { e.printStackTrace(); } }}
InputStreamReader和OutputStreamWriter:字符流和字节流之间的转换
Reader 输入流对应于不同的数据源:
FileReader 用于从文件输入;
CharArrayReader 用于从程序中的字符数组输入;
StringReader 用于从程序中的字符串输入;
InputStreamReader从一个数据源读取字节,并自动将其转换成Unicode字符
OutputStreamWriter将字符的Unicode编码写到字节输出流
package demo;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;public class InputStreamReaderTest{ public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("d:/222.txt"); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr);// 这里又用BufferedReader封装起来,其实就是为了可以使用它的ReadLine方法 FileOutputStream fos = new FileOutputStream("d:/555.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw);// 这里同样的用BufferedWriter封装起来,就是为了可以使用它的writer(String )方法..可以看API,其他的都只能write Int类型的数据或者byte类型的 String s2 = null; while ((s2 = br.readLine()) != null) { bw.write(s2); bw.newLine(); } bw.close(); br.close(); } catch (IOException e) { e.printStackTrace(); } }}
疑问:
1、ByteArrayOutputStream和BufferedOutputStream区别
本来这2个没法比较的,非得比较可以为:
(1)、构造方法不一样;
(2)、byte[]转换为InputStream流:InputStream sbs = new ByteArrayInputStream(byte[] buf);
(3)、InputStream转换为byte[]数组
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据int rc = 0;while ((rc = inStream.read(buff, 0, 100)) > 0) {swapStream.write(buff, 0, rc);}byte[] in_b = swapStream.toByteArray(); //in_b为转换之后的结果
2、ArrayList一个基础问题,关于 transient
ArrayList 里面定义:
private transient Object[] elementData;
这里是ArrayList.elementData定义的地方,而elementData是用来存储实际内容的数组, 而transient字是表明域不能序列化,而我在这里能打印出 a b c,这个对transient怎么理解?
package demo;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.ArrayList;public class WriteObject{ public static void main(String[] args) { ArrayList<String> al = new java.util.ArrayList<String>(); al.add("a"); al.add("b"); al.add("c"); try { ByteArrayOutputStream stream = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(stream); out.writeObject(al); byte[] alBytes = stream.toByteArray(); ArrayList<String> all = (ArrayList<String>) new ObjectInputStream(new ByteArrayInputStream(alBytes)).readObject(); for (String s : all) { System.out.println(s); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
序列化有2种方式:
A、只是实现了Serializable接口。
序列化时,调用java.io.ObjectOutputStream的defaultWriteObject方法,将对象序列化。
注意:此时transient修饰的字段,不会被序列化。
B、实现了Serializable接口,同时提供了writeObject方法。
序列化时,会调用该类的writeObject方法。而不是java.io.ObjectOutputStream的defaultWriteObject方法。
注意:此时transient修饰的字段,是否会被序列化,取决于writeObject。