//有时间再排版吧,累觉不爱 3/18
一、Java的流:
各种各样的流对应各种各样的管道,它们有些可以套在一起使用。
二、分类:
输入流:进入程序(写的代码) 输出流:从程序(写的代码)出去
字节流,字符流——-处理的数据单位不同
节点流,处理流——-功能不同
节点流:流 (管道)直接怼到文件 (水桶)上的流。
处理流:包在别的流 (管道)上面的流 (管道)。
凡是以stream结尾的都是字节流 三、节点流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.io.*;public class TestFileInputStream { public static void main (String[] args) { int b = 0 ; FileInputStream in = null ; try { in = new FileInputStream("d:\\share\\java\\io\\TestFileInputStream.java" ); } catch (FileNotFoundException e) { System.out.println("找不到指定文件" ); System.exit(-1 ); } try { long num = 0 ; while ((b=in.read())!=-1 ){ System.out.print((char )b); num++; } in.close(); System.out.println(); System.out.println("共读取了 " +num+" 个字节" ); } catch (IOException e1) { System.out.println("文件读取错误" ); System.exit(-1 ); } } }
这个程序执行结束后,读出的文件,如果有中文,则会显示乱码。因为它是一个字节字节地读,而中文占用的不止一个字节。
2、FileOutputStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.io.*;public class TestFileOutputStream { public static void main (String[] args) { int b = 0 ; FileInputStream in = null ; FileOutputStream out = null ; try { in = new FileInputStream("e:/javatest/testfile.java" ); out = new FileOutputStream("e:/javatest/8/HWJ.java" ); while ((b=in.read())!=-1 ){ System.out.print((char )b); out.write(b); } in.close(); out.close(); } catch (FileNotFoundException e2) { System.out.println("找不到指定文件" ); System.exit(-1 ); } catch (IOException e1) { System.out.println("文件复制错误" ); System.exit(-1 ); } System.out.println("文件已复制" ); } }
FileOutputStream(path,append):如果第二个参数写为true,则可以向文件后面追加。
3、FileReader 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.io.*;public class TestFileReader { public static void main (String[] args) { FileReader fr = null ; int c = 0 ; try { fr = new FileReader("e:\\javatest\\8\\io\\TestFileReader.java" ); int ln = 0 ; while ((c = fr.read()) != -1 ) { System.out.print((char )c); } fr.close(); } catch (FileNotFoundException e) { System.out.println("找不到指定文件" ); } catch (IOException e) { System.out.println("文件读取错误" ); } } }
这个程序执行结束,如果文件里面有中文,则会完美的将中文读出。因为这是以字符的形式读出。
4、FileWriter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.io.*;public class TestFileWriter { public static void main (String[] args) { FileWriter fw = null ; try { fw = new FileWriter("e:\\javatest\\8\\heijudy.txt" ); fw.write("我的导师叫那英~" ); fw.close(); } catch (IOException e1) { e1.printStackTrace(); System.out.println("文件写入错误" ); System.exit(-1 ); } System.out.println("文件写入完成" ); } }
这个程序如果目标目录下没有这个文件,则会自动创建一个文件。然后把字符串给写进去。 FileWriter(path,append):如果第二个参数写为true,则可以向文件后面追加。
四、处理流
1、缓冲流(带小桶的流) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.io.*;public class TestBufferStream1 { public static void main (String[] args) { try { FileInputStream fis = new FileInputStream( "e:\\javatest\\8\\io\\test.java" ); BufferedInputStream bis = new BufferedInputStream(fis); int c = 0 ; System.out.println(bis.read()); System.out.println(bis.read()); bis.mark(2 ); for (int i = 0 ; i <= 10 && (c = bis.read()) != -1 ; i++) { System.out.print((char ) c + " " ); } System.out.println(); bis.reset(); for (int i = 0 ; i <= 10 && (c = bis.read()) != -1 ; i++) { System.out.print((char ) c + " " ); } bis.close(); } catch (IOException e) { e.printStackTrace(); } } }
BufferedInputStream.mark(int readlimit) 意思是:
标记当前位置,在后面读取readlimit个字节之前有效。
但实际中并不是这样!!!
实际中是这样的:
当BufferedInputStream调用了mark(不管这里是几)后,后面读取的字节数如果超过了流的Size,则这个标记失效。代码中设置的Size=5的BufferedInputStream证实了这个。
(2)、BufferedWriter、BufferedReader 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.io.*;public class TestBufferStream2 { public static void main (String[] args) { try { BufferedWriter bw = new BufferedWriter(new FileWriter( "e:/javatest/8/我的家在东北.txt" )); BufferedReader br = new BufferedReader(new FileReader( "e:/javatest/8/我的家在东北.txt" )); String s = null ; for (int i = 1 ; i <= 100 ; i++) { s = String.valueOf(Math.random()); bw.write(s); bw.newLine(); } bw.flush(); while ((s = br.readLine()) != null ) { System.out.println(s); } bw.close(); br.close(); } catch (IOException e) { e.printStackTrace(); } } }
BufferedWriter.newLine()//写一个换行符
BufferedWriter.write(String s,int off,int len)//写一个字符串s,从off写len个字符。off和len可以缺省,那么就写整个s。也有写字符数组的方法,类似。
有一个很好用的方法: BufferedReader.readLine()//读一行内容 它可以直接读出一行内容,即便是为了这个方法,也值得在其他流上套一个BufferedReader
2、转换流 转换流概念图片
(1)、OutputStreamWriter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.io.*;public class TestTransForm1 { public static void main (String[] args) { try { OutputStreamWriter osw = new OutputStreamWriter( new FileOutputStream("e:\\javatest\\8\\io\\char.txt" )); osw.write("mircosoft ibm sun apple hp" ); System.out.println(osw.getEncoding()); osw.close(); osw = new OutputStreamWriter(new FileOutputStream( "e:\\javatest\\8\\io\\char.txt" , true ), "GBK" ); osw.write(" mircosoft ibm sun apple hp" ); System.out.println(osw.getEncoding()); osw.close(); InputStreamReader isr = new InputStreamReader(new FileInputStream( "e:\\javatest\\8\\io\\char.txt" )); BufferedReader br = new BufferedReader(isr); String s; s = br.readLine(); System.out.println(s); br.close(); } catch (FileNotFoundException e2) { System.out.println("找不到指定文件" ); System.exit(-1 ); } catch (IOException e) { e.printStackTrace(); } System.out.println("FINISH" ); } }
图片:大管道套小管道 OutputStreamWriter.write(String str,int off,int len):可以写一个字符串从off开始len个字符。 off和len可以缺省,那么默认写全部str。 代码中的: osw.write(“ mircosoft ibm sun apple hp”, 3, 2);证实了这个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.io.*;public class TestTransForm2 { public static void main (String args[]) { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = null ; try { s = br.readLine(); while (s != null ) { if (s.equalsIgnoreCase("exit" )) break ; System.out.println(s.toUpperCase()); s = br.readLine(); } br.close(); } catch (IOException e) { e.printStackTrace(); } } }
//System.in是个阻塞式的流,如果你没有输入,它就傻傻的等待~ 图片:三个管道,读字节>读字符>读一行字符串
3、数据流 图片:概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import java.io.*;public class TestDataStream { public static void main (String[] args) { * ByteArrayOutputStream 的创建完成了2个操作: * 一、在内存中分配了一个字节数组(即:缓冲区) * 二、一根流管道怼在了这个字节数组上 */ ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); try { * 向这个流dos里面写了一个double,一个boolean * * 实际上是先把这两个数据写到了刚才在内存中分配 * 的字节数组(缓冲区)中暂时保存起来 */ dos.writeDouble(Math.random()); dos.writeBoolean(true ); * 创建一个字节数组输入流,将输出流的字节数组(缓冲区) * 的内容以字节数组的形式返回 */ ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray()); System.out.println(bais.available()); DataInputStream dis = new DataInputStream(bais); * 正确的read的顺序应该和write的顺序相同。 * 如果相反,则会产生错误。 * “先写先读”-----先进先出-----队列 */ System.out.println(dis.readDouble()); System.out.println(dis.readBoolean()); * 关闭后,字符数组消失,管道都消失 */ dos.close(); dis.close(); } catch (IOException e) { e.printStackTrace(); } } }
4、print流 图片:概念
(1)、PrintStream ① 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.io.*;public class TestPrintStream1 { public static void main (String[] args) { PrintStream ps = null ; try { FileOutputStream fos = new FileOutputStream( "e:\\javatest\\8\\io\\char.txt" , true ); ps = new PrintStream(fos); } catch (IOException e) { e.printStackTrace(); } if (ps != null ) { System.setOut(ps); } System.out.println("\n中国好声音第四季----周杰伦歌迷见面会~~~~~~~~~~才怪~" ); ps.close(); } }
图片:管道套管道图,把往控制台的输出流设置为自己创建的流。
② 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.io.*;public class TestPrintStream2 { public static void main (String[] args) { String filename = args[0 ]; if (filename != null ) { list(filename, System.out); } } public static void list (String f, PrintStream fs) { try { BufferedReader br = new BufferedReader(new FileReader(f)); String s = null ; while ((s = br.readLine()) != null ) { fs.println(s); } br.close(); } catch (IOException e) { fs.println("无法读取文件" ); } } }
读取一个参数(文件名),然后输出到控制台
(2)、PrintWriter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import java.util.*;import java.io.*;public class TestPrintStream3 { public static void main (String[] args) { String s = null ; * 一根管道怼到了标准输入上(键盘上) */ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try { * 后面带true的参数,用于写日志 */ FileWriter fw = new FileWriter("e:\\javatest\\8\\io\\char.txt" , true ); * 又一根管道PrintWriter怼到了FileWriter流上 */ PrintWriter log = new PrintWriter(fw); * br.readLine():此处是从标准输入流中读取一行内容 */ while ((s = br.readLine()) != null ) { if (s.equalsIgnoreCase("exit" )) break ; System.out.println(s.toUpperCase()); * */ log.println("-----" ); log.println(s.toUpperCase()); log.flush(); } log.println("===" + new Date() + "===" ); * flush()刷新此输出流并强制写出所有缓冲的输出字节 */ log.flush(); log.close(); } catch (IOException e) { e.printStackTrace(); } } }
5、Object流 直接将Object写入或写出
* 序列化:把一个Object直接转换为字节流写到硬盘(或者网络)上去。
Java序列化:
类通过实现 java.io.Serializable(标记性的接口) 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。 序列化接口没有方法或字段,仅用于标识可序列化的语义。 类实现Serializable接口,做了标记之后。实质上是告诉编译器,“我可以被序列化,come on~序列化我吧~~”。
关键字transient: 修饰变量,在序列化的时候不予考虑(即:往硬盘上写的时候,直接忽视它,当它是透明的)
transient使用小结(原文地址:http://blog.csdn.net/lanxuezaipiao/article/details/16358677 ) 1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。 2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。 3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
优点: 比DataInputStream、DataOutputStream流更方便,ObjectInputStream、ObjectOutputStream可以直接读写一个Object对象。而不用一个数据一个数据地读写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.io.*;public class TestObjectIO { public static void main (String args[]) throws Exception { T t = new T(); t.k = 8 ; * 输出流 * 一个管道套一个管道怼在了文件上 */ FileOutputStream fos = new FileOutputStream("e:\\javatest\\8\\char.txt" ); ObjectOutputStream oos = new ObjectOutputStream(fos); * ObjectOutputStream.writeObject(Object o)//直接写一个对象进去 */ oos.writeObject(t); oos.flush(); oos.close(); * 输入流 * 一个管道套一个管道怼在了文件上 */ FileInputStream fis = new FileInputStream("e:\\javatest\\8\\char.txt" ); ObjectInputStream ois = new ObjectInputStream(fis); T tReaded = (T) ois.readObject(); System.out.println(tReaded.i + " " + tReaded.j + " " + tReaded.d + " " + tReaded.k); } } class T implements Serializable { int i = 10 ; int j = 9 ; double d = 2.3 ; transient int k = 15 ; }
此例中,变量k被transient修饰,所以不能被序列化。输出tReaded.k的结果为0。
java.io.Externalizable: 实现了Serializable接口,对象序列化的过程自动进行,由JVM帮你控制。这TM自己控制不了它怎么序列化的,总感觉不太爽啊(¬_¬),Java还很人性的提供了Externalizable接口(估计是顾及到了一些程序员的感受(๑•ᴗ•๑))。
其实, public interface Externalizable extends Serializable 它是Serializable的子接口~^_^~ 程序员可以实现里面的readExternal(ObjectInput in)和writeExternal(ObjectOutput out) 方法, 就可以自己控制序列化的过程。