目录
节点流
类型 | 字符型 | 字节流 |
---|---|---|
File文件 |
FileReader
、
FileWriter
|
FileInputStream
、
FileOutputStream
|
内存数
组
|
CharArrayReader
、
CharArrayWriter
|
ByteArrayInputStream
、
ByteArrayOutputStream
|
内存字
串
|
StringReader
、
StringWriter
| |
管道
|
PipedReader
、
PipedWriter
|
PipedInputStream,
PipedOutputStream
|
文件节点流
- FileInputStream("文件名称"),如果文件不存在则FileNotFoundException
- FileInputStream(File)
- FileOutputStream(“文件名称”) 如果文件不存在则新建文件,如果文件存在则覆盖文件内容
- FileOutputStream(String name文件名称, boolean append是否采用追加方式)
FileInputStream和FileOutputStream两个类属于结点流,第一个类的源端和第二个类的目的端都是磁盘文件,它们的构造方法允许通过文件的路径名来构造相应的流。
如:
内存数组节点
- CharArrayReader(char[] buf)其中char[]就是数据的来源,也就是说Reader就是从char[]中读取数据
- CharArrayRead(char[] buf, int offset, int length)
内存字串流
String str = " 亚洲说: ‘ 我爱小黑 ’" ;StringReader sr = new StringReader ( str );int cc ;while (( cc = sr . read ()) !=- 1 )System . out . print (( char ) cc );sr . close ();
StringWriter用于给一个StringBuffer中写入数据,实现一个可边长的字串
Scanner sc=new Scanner(System.in);
try (StringWriter sw = new StringWriter ();Writer fw = new FileWriter ( "c:/console.txt" )){String temp = sc . nextLine ();while ( ! temp . equals ( "quit" )){if ( temp != null && temp . trim (). length () > 0 )sw . write ( temp + "\n" );temp = sc . nextLine ();}fw . write ( sw . toString ());}
总结
- 读写文件使用节点流FileInputStream/FileOutputStream和FileReader/FileWriter,如果操作文本文件,建议使用FileReader/FileWriter,如果操作二进制文件建议使用 FileInputStream/FileOutputStream
- 需要建立缓冲区(建立临时文件的方式效率低),可以考虑使用内存节点,例如 CharArrayReader/CharArrayWriter、StringReader/StringWriter和 ByteArrayInputStream/ByteArrayOutputStream
- 如果需要一个二进制缓冲区可以使用ByteArrayInputStream/ByteArrayOutputStream,如果需要一个字符缓存可以使用CharArrayReader/CharArrayWriter、StringReader/StringWriter
- 如果数据量不是特别大使用CharArrayReader/CharArrayWriter更为方便,如果数据量大而且可能需要直接操作缓冲区则使用StringReader/StringWriter
- StringWriter中提供了方法getBuffer():StringBuffer
过滤流类型
处理类型 | 字符流 | 字节流 |
---|---|---|
缓存 |
BufferedReader
、
BufferedWriter
|
BufferedInputStream
、
BufferedOutputStream
|
过滤类型 |
FilterReader
、
FilterWriter
|
FilterInputStream
、
FilterOutputStream
|
桥接处理
|
InputStreamReader
、
OutputStreamWriter
| |
对象序列化处理
|
ObjectInputStream
、
ObjectOutputStream
| |
数据转换
|
DataInputStream
、
DataOutputStream
| |
行数统计
|
LineNumberReader
|
LineNumberInputStream
|
回滚处理
|
PushbackReader
|
PushbackInputStream
|
打印功能
|
PrintWriter
|
PrintStream
|
过滤流
就是decorate模式中的抽象装饰角色
public class FilterInputStream extends InputStream { // 典型的装饰模式protected volatile InputStream in ; // 被装饰目标protected FilterInputStream ( InputStream in ) { // 通过构造器组装被装饰对象this . in = in ;}public int read () throws IOException { // 调用 Filter 中的 read 方法时实际操作是由被装饰对象实现的return in . read ();}}
所谓的过滤流实际上就是类似上面的加密处理,在输入之后(后置处理,被装饰对象先执行)或者输出之前(前置处理,先处理然后被装饰对象执行)进行一下额外的处理,最终实际操作是调用被装饰对象的方法完成工作,依靠这种装饰模式实现在节点流的基础上附加额外功能.当然也允许多个过滤流嵌套从而达到功能累加的目的
FilterInputStream实际上就是一个装饰抽象角色
自定义流实现循环13加密:
读取数据不变:FileReader---BufferedReader
写出数据自定义过滤流SecurityWriter(FilterWriter)
public class SecurityWriter extends FilterWriter {protected SecurityWriter ( Writer out ) {super ( out );}public void write ( int c ) throws IOException {if ( c >= 'a' && c <= 'z' ) {c = ( c - 'a' + 13 ) % 26 + 'a' ;} else if ( c >= 'A' && c <= 'Z' ) {c = ( c - 'A' + 13 ) % 26 + 'A' ;}super . write ( c );}}
public class SecurityReader extends FilterReader {
protected SecurityReader ( Reader in ) {super ( in );}public int read () throws IOException {int c = super . read ();if ( c >= 'a' && c <= 'z' ) {c = ( c - 'a' + 13 ) % 26 + 'a' ;} else if ( c >= 'A' && c <= 'Z' ) {c = ( c - 'A' + 13 ) % 26 + 'A' ;}return c ;}}
加密算法:
- 数字:如果不是9的数字,在原来的基础上加1,比如5变成6, 3变成4,如果是9的数字,变成0。
- 字母字符:如果是非z字符,向右移动一个,比如d变成e, G变成H,如果是z,z->a, Z-A。字符需要保留大小写
- 非字母字符:比如‘,&^ 保留不变,中文也保留不变
桥接转换流
InputStreamReader和OutputStreamWriter是java.io包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介:从字节输入流读入字节,并按编码规范转换为字符;往字节输出流写字符时先将字符按编码规范转换为字节。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范,以便把以字节方式表示的流转换为特定平台上的字符表示。
转换流可以在构造时指定其编码字符集
InputStreamReader构造器
- InputStreamReader(InputStream)
- InputStreamReader(InputStream, String)
- InputStreamReader(InputStream, Charset)
- InputStreamReader(InputStream, CharsetDecorder)
Reader r = new InputStreamReader ( System . in );int kk = r . read (); // 例如输入的是 “ 中国 ” ,这里实际读取的是 " 中 "// 因为这里读取的是一个字节,所以输入 " 中国 " ,实际读取的是 " 中 " 的一个字节,输出显示为 ?kk = System . in . read ();System . out . println ( " 输入的是: " + ( char ) kk );
InputSteram is=new InputStreamReader(System.in,”iso8859-1”);
Reader r=new InputStreamReader(System.in, "gbk");
int kk = r . read (); // 例如输入的是 " 中国 " ,实际读取的是 " 中 "System . out . println ( " 输入的是: " + ( char ) kk );
注意:一般不建议自行设置编码字符集,除非是必须的
缓冲流
缓冲流是套接在响应的节点流之上,对续写的数据提供缓冲的功能,提高读写的效率,同时增加了一些新方法
以介质是硬盘为例,字节流和字符流的弊端:在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。为了解决以上弊端,采用缓存流。
InputStream is = new FileInputStream("d:\\FileTest.java");
long start=System.currentTimeMillis();// 获取从 1970-1-1 0:0:0 到当前的毫米值int con = is.read();while (con != -1) {System.out.write(con);con = is.read();}long end=System.currentTimeMillis();is.close();System.out.println(" 统计时间为 :"+(end-start)+"ms");60ms
构造方法
- BufferedReader(Reader)不定义缓存大小,默认8192
- BufferedReader(Reader in, int size)size为自定义缓冲区的大小
- BufferedWriter(Writer)
- BufferedWriter(Writer out, int size)size为自定义缓冲区的大小
- BufferedInputStream(InputStream)
- BufferedInputStream(InputStream in, int size)size为自定义缓冲区的大小
- BufferedOutputStream(OutputStream)
- BufferedOutputStream(OuputStream out, int size)size为自定义缓冲区的大小
InputStream is = new BufferedInputStream(newFileInputStream("d:\\FileTest.java"));long start=System.currentTimeMillis();int con = is.read();// 这里并不是直接从文件中进行读取,而是从缓存中进行读while (con != -1) {System.out.write(con);con = is.read();}long end=System.currentTimeMillis();is.close();System.out.println(" 统计时间为 :"+(end-start)+"ms");is.close();10ms
缓冲输入流的方法
BuffedReader提供了一个方法readLine():String,但是BufferedInputStream中并没有这个
- BufferedReader提供了readLine方法用于读取一行字符串,以\r或\n分割(换行符)
- 如果读取内容为null,则表示读取到了流的末尾
- readLine方法会自动剔除本行内容末尾的换行符
- BufferedWriter提供了newLine方法用于写入一个行分隔符
键盘录入
BufferedReader br = new BufferedReader ( new InputStreamReader ( System . in ));System . out . println ( " 输入数据 " ) ;String temp = "" ;while (( temp = br . readLine ()). trim (). length () > 0 ){if ( "quit" . equals ( temp )) break ;System . out . println ( temp );}br . close ();
BufferedWriter bw = new BufferedWriter ( new OutputStreamWriter ( System . out ));bw . write ( " 只有缓冲区满才自动进行输出显示 " );bw . flush (); // 刷新缓冲区,否则看不到输出内容System . in . read ();bw . close (); // 关闭输出时会首先自动进行刷新缓冲区
过滤流使用必须有对应的节点流,因为过滤流是装饰节点流,不是有具体的操作目标
数据流
- 只有字节流,没有对应的字符流
- DataInputStream(InputStream)
- DataOutputStream(OutputStream)
读取、写出一个double数据到文件中
// 使用数据流就可以直接操作简单类型数据double dd = 123.4567 ;FileOutputStream fos = new FileOutputStream ( "d:\\a.data" );fos . write (( dd + "" ). getBytes ());fos . close ();// 如果不使用数据流,则需要额外编码进行数据类型转换FileInputStream fis = new FileInputStream ( "d:/a.data" );byte [] buffer = new byte [ 8192 ];int len = fis . read ( buffer );fis . close ();String str = new String ( buffer , 0 , len );double dd = Double . parseDouble ( str );System . out . println ( dd );
加入需要写一个double,然后一个String,然后再一个int 需要将输入内容转换为String,并且为了区分数据需要引入特殊符号,例如@@,输入数据为123.456@@shi ya zhou@@12。从功能角度上说没问题,但是编码太复杂了,所以引入Data类型的输入输出流
// 这里不使用 OutputStream 定义变量的原因是:需要使用 DataOutputStream 中定义的特殊方法,而不是父类中定义的通用方法DataOutputStream dos = new DataOutputStream ( newFileOutputStream ( "d:\\a.data" ));dos . writeDouble ( 123.456 );dos . writeChars ( " 赵天爱小猴 !" );dos . writeInt ( 12 );dos . close ();
double salary = 123.456 ;String ss = " 赵天爱小猴,小猿爱小主,小胡招小天 " ;int age = 12 ;DataOutputStream dos = new DataOutputStream ( new BufferedOutputStream ( newFileOutputStream ( "d:\\aa.data" )));dos . writeDouble ( salary );dos . writeInt ( ss . length ());dos . writeChars ( ss );dos . writeInt ( age );dos . close ();
读取数据
double salary=0;
String str = "" ;int age = 0 ;// 读取数据的前提是必须知道数据的结构DataInputStream dis = new DataInputStream ( new BufferedInputStream ( newFileInputStream ( "d:\\aa.data" )));salary = dis . readDouble ();StringBuilder sb = new StringBuilder ();int len = dis . readInt ();for ( int i = 0 ; i < len ; i ++ ) sb . append ( dis . readChar ());str = sb . toString ();age = dis . readInt ();System . out . println ( salary + "---" + str + "---" + age );
DataOutputStream dos=new DataOutputStream(new FileOutputStream("data2.txt"));
dos . writeDouble ( 1234.56 );String str = " 猴子愛小終,小終愛信心 " ;dos . writeUTF ( str );dos . writeInt ( 99 );dos . close ();DataInputStream dis = new DataInputStream ( new FileInputStream ( "data2.txt" ));double d1 = dis . readDouble ();String ss = dis . readUTF ();int kk = dis . readInt ();System . out . println ( d1 + "\t" + ss + "\t" + kk );dis . close ();
打印流
- 输出引用类型,实际上是调用对象的toString方法转换为String进行输出
public void println ( Object x ) {String s = String . valueOf ( x ); // 调用 String 类中的静态方法将 object 类型的数据转换为字符串synchronized ( this ) {print ( s );newLine (); //print('\n')}}//String 中的 valueOf 方法的定义public static String valueOf ( Object obj ) {return ( obj == null ) ? "null" : obj . toString (); // 如果输出对象非空,则调用对象的 toString 方法}
- PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息
- PrintWriter和PrintStream有自动的flush功能 textOut.flushBuffer();
PrintWriter ( OutputStream out ) // 参数是一个字节流,但是不需要通过桥接处理PrintWriter ( OutputStream out , boolean autoFlush )PrintStream ( OutputStream )PrintStream ( OutputStream out , boolean autoFlush )