IO缓冲流
Java 的IO流按流向分为输入流和输出流,按流的性能,又可以将流分为节点流和处理流。
节点流
节点流:直接与数据源相连,读入或读出。
直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。
常用的节点流
- 父 类 :
InputStream
、OutputStream
、Reader
、Writer
- 文 件 :
FileInputStream
、FileOutputStrean
、FileReader
、FileWriter
文件进行处理的节点流 - 数 组 :
ByteArrayInputStream
、ByteArrayOutputStream
、CharArrayReader
、CharArrayWriter
对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组) - 字符串 :
StringReader
、StringWriter
对字符串进行处理的节点流 - 管 道 :
PipedInputStream
、PipedOutputStream
、PipedReader
、PipedWriter
对管道进行处理的节点流
处理流(使用装饰者模式)
处理流和节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。
如BufferedReader
.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
常用的处理流
- 缓冲流:
BufferedInputStream
、BufferedOutputStream
、BufferedReader
、BufferedWriter
增加缓冲功能,避免频繁读写硬盘。 - 转换流:
InputStreamReader
、OutputStreamReader
实现字节流和字符流之间的转换。 - 数据流:
DataInputStream
、DataOutputStream
等-提供将基础数据类型写入到文件中,或者读取出来。
输入字节缓存流BufferedInputStream
/输出字节缓冲流BufferedOutputStream
BufferedOutputsStream,BufferedInputStream
都要包上一层节点流。
也就是说处理流是在节点流的基础之上进行的,带有Buffered的流又称为缓冲流,缓冲流处理文件的输入输出的速度是最快的。所以一般缓冲流的使用比较多。
我们将之前使用节点流改成缓冲流,提高性能。
字节输入流InputStream/字节输出流OutputStream
从文件向程序冲写数据使用InputStream的FileInputStream,按字节数组读取,使用处理流BufferedInputStream包装
1 package com.sxt.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.FileNotFoundException; 7 import java.io.IOException; 8 import java.io.InputStream; 9 10 /** 11 * 四个步骤: 分段读取 文件字节输入流 加入缓冲流 12 * 1、创建源 13 * 2、选择流 14 * 3、操作 15 * 4、释放资源 16 * 17 * @author liuzeyu12a 18 * 19 */ 20 public class BufferedTest01 { 21 22 public static void main(String[] args) { 23 File src = new File("abc.txt"); 24 //2、选择流 25 InputStream is =null; 26 try { 27 is =new BufferedInputStream(new FileInputStream(src)); 28 //3、操作 (分段读取) 29 byte[] flush = new byte[1024]; //缓冲容器 30 int len = -1; //接收长度 31 while((len=is.read(flush))!=-1) { 32 //字节数组-->字符串 (解码) 33 String str = new String(flush,0,len); 34 System.out.println(str); 35 } 36 37 } catch (FileNotFoundException e) { 38 e.printStackTrace(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 }finally { 42 //4、释放资源 43 try { 44 if(null!=is) { 45 is.close(); 46 } 47 } catch (IOException e) { 48 e.printStackTrace(); 49 } 50 } 51 } 52 53 public static void test1() { 54 //1、创建源 55 File src = new File("abc.txt"); 56 //2、选择流 57 InputStream is =null; 58 BufferedInputStream bis =null; 59 try { 60 is =new FileInputStream(src); 61 bis = new BufferedInputStream(is); 62 //3、操作 (分段读取) 63 byte[] flush = new byte[1024]; //缓冲容器 64 int len = -1; //接收长度 65 while((len=is.read(flush))!=-1) { 66 //字节数组-->字符串 (解码) 67 String str = new String(flush,0,len); 68 System.out.println(str); 69 } 70 } catch (FileNotFoundException e) { 71 e.printStackTrace(); 72 } catch (IOException e) { 73 e.printStackTrace(); 74 }finally { 75 //4、释放资源 76 try { 77 if(null!=is) { 78 is.close(); 79 } 80 } catch (IOException e) { 81 e.printStackTrace(); 82 } 83 try { 84 if(null!=bis) { 85 bis.close(); 86 } 87 } catch (IOException e) { 88 e.printStackTrace(); 89 } 90 } 91 } 92 93 }
从程序向文件中写数据使用OutputStream的FileOutputStream,按字节数组写入,使用处理流BufferedOutputsStream包装
1 package com.sxt.io; 2 3 import java.io.BufferedOutputStream; 4 import java.io.File; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.io.OutputStream; 9 10 /** 11 * 文件字节输出流 加入缓冲流 12 *1、创建源 13 *2、选择流 14 *3、操作(写出内容) 15 *4、释放资源 16 * @author liuzeyu12a 17 * 18 */ 19 public class BufferedTest02 { 20 21 public static void main(String[] args) { 22 //1、创建源 23 File dest = new File("dest.txt"); 24 //2、选择流 25 OutputStream os =null; 26 try { 27 os =new BufferedOutputStream( new FileOutputStream(dest)); 28 //3、操作(写出) 29 String msg ="IO is so easy\r\n"; 30 byte[] datas =msg.getBytes(); // 字符串-->字节数组(编码) 31 os.write(datas,0,datas.length); 32 os.flush(); 33 }catch(FileNotFoundException e) { 34 e.printStackTrace(); 35 }catch (IOException e) { 36 e.printStackTrace(); 37 }finally{ 38 //4、释放资源 39 try { 40 if (null != os) { 41 os.close(); 42 } 43 } catch (Exception e) { 44 } 45 } 46 } 47 48 }
一个简单的案例:实现音频的复制粘贴
代码:
1 package com.sxt.io; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileNotFoundException; 8 import java.io.FileOutputStream; 9 import java.io.IOException; 10 import java.io.InputStream; 11 import java.io.OutputStream; 12 13 /** 14 * 文件拷贝:文件字节输入、输出流 15 * 16 * @liuzeyu12a 17 * 18 */ 19 public class Copy { 20 21 public static void main(String[] args) { 22 long t1 = System.currentTimeMillis(); 23 copy("IO开篇.mp4","IO-copy.mp4"); 24 long t2 = System.currentTimeMillis(); 25 System.out.println(t2-t1); 26 } 27 28 public static void copy(String srcPath,String destPath) { 29 //1、创建源 30 File src = new File(srcPath); //源头 31 File dest = new File(destPath);//目的地 32 //2、选择流 33 try( InputStream is=new BufferedInputStream(new FileInputStream(src)); 34 OutputStream os =new BufferedOutputStream( new FileOutputStream(dest)); ) { 35 //3、操作 (分段读取) 36 byte[] flush = new byte[1024]; //缓冲容器 37 int len = -1; //接收长度 38 while((len=is.read(flush))!=-1) { 39 os.write(flush,0,len); //分段写出 40 } 41 os.flush(); 42 }catch(FileNotFoundException e) { 43 e.printStackTrace(); 44 }catch (IOException e) { 45 e.printStackTrace(); 46 } 47 } 48 }
字符输入流 Reader/字符输出流Writer
从文件向程序冲写数据使用Reader的FileReader,按字符数组读取,使用BufferedReader包装
1 package com.sxt.io; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileNotFoundException; 6 import java.io.FileReader; 7 import java.io.IOException; 8 9 /** 10 * 四个步骤: 分段读取 文件字符输入流 加入缓冲流 11 * 1、创建源 12 * 2、选择流 13 * 3、操作 14 * 4、释放资源 15 * 16 * @author liuzeyu12a 17 * 18 */ 19 public class BufferedTest03 { 20 21 public static void main(String[] args) { 22 //1、创建源 23 File src = new File("abc.txt"); 24 //2、选择流 25 BufferedReader reader =null; 26 try { 27 reader =new BufferedReader(new FileReader(src)); 28 //3、操作 (分段读取) 29 String line =null; 30 while((line=reader.readLine())!=null) { 31 //字符数组-->字符串 32 System.out.println(line); 33 } 34 35 } catch (FileNotFoundException e) { 36 e.printStackTrace(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 }finally { 40 //4、释放资源 41 try { 42 if(null!=reader) { 43 reader.close(); 44 } 45 } catch (IOException e) { 46 e.printStackTrace(); 47 } 48 } 49 } 50 51 }
从文件向程序冲写数据使用Writer的FileWriter,按字符数组写出,使用BufferedWriter包装
1 package com.sxt.io; 2 3 import java.io.BufferedWriter; 4 import java.io.File; 5 import java.io.FileNotFoundException; 6 import java.io.FileWriter; 7 import java.io.IOException; 8 9 /** 10 * 文件字符输出流 加入缓冲流 11 *1、创建源 12 *2、选择流 13 *3、操作(写出内容) 14 *4、释放资源 15 * @author liuzeyu12a 16 * 17 */ 18 public class BufferedTest04 { 19 20 public static void main(String[] args) { 21 //1、创建源 22 File dest = new File("dest.txt"); 23 //2、选择流 24 BufferedWriter writer =null; 25 try { 26 writer = new BufferedWriter(new FileWriter(dest)); 27 //3、操作(写出) 28 writer.append("IO is so easy"); 29 writer.newLine(); 30 writer.append("尚学堂欢迎你"); 31 writer.flush(); 32 }catch(FileNotFoundException e) { 33 e.printStackTrace(); 34 }catch (IOException e) { 35 e.printStackTrace(); 36 }finally{ 37 //4、释放资源 38 try { 39 if (null != writer) { 40 writer.close(); 41 } 42 } catch (Exception e) { 43 } 44 } 45 } 46 47 }
字符缓存流文件的拷贝
代码:
1 package com.sxt.io; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.File; 6 import java.io.FileNotFoundException; 7 import java.io.FileReader; 8 import java.io.FileWriter; 9 import java.io.IOException; 10 /** 11 * 文件拷贝:文件字节输入、输出流 12 * 13 * @author liuzeyu12a 14 * 15 */ 16 public class CopyTxt { 17 18 public static void main(String[] args) { 19 copy("abc.txt","abc-copy.txt"); 20 } 21 public static void copy(String srcPath,String destPath) { 22 //1、创建源 23 File src = new File(srcPath); //源头 24 File dest = new File(destPath);//目的地 25 //2、选择流 26 try( BufferedReader br=new BufferedReader(new FileReader(src)); 27 BufferedWriter bw =new BufferedWriter( new FileWriter(dest)); ) { 28 //3、操作 (逐行读取) 29 String line =null; 30 while((line=br.readLine())!=null) { 31 bw.write(line); //逐行写出 32 bw.newLine(); 33 } 34 bw.flush(); 35 }catch(FileNotFoundException e) { 36 e.printStackTrace(); 37 }catch (IOException e) { 38 e.printStackTrace(); 39 } 40 } 41 }
转换流
InputStreamReader和OutputStreamWriter是字符和字节的桥梁,也可称之为字符转换流。原理:字节流+编码。
InputStreamReader
、OutputStreamWriter
要InputStream
或OutputStream
作为参数,实现从字节流到字符流的转换。
构造函数
InputStreamReader(InputStream); //通过构造函数初始化,使用的是本系统默认的编码表GBK。
InputStreamWriter(InputStream,String charSet); //通过该构造函数初始化,可以指定编码表。 OutputStreamWriter(OutputStream); //通过该构造函数初始化,使用的是本系统默认的编码表GBK。 OutputStreamwriter(OutputStream,String charSet); //通过该构造函数初始化,可以指定编码表。
特点:
1、转换流是字符流与字节流之间的桥梁
2、可对读取到的字节指定编码转换成字符
3、可对读取到的字符指定编码转换成字节
何时使用转换流?
1、当字节和字符之间有转换动作时
2、流操作的数据需要编码与解码时
3、FileReader和FileWriter作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接使用子类完成操作,简化代码。
一旦要指定其他编码时,不能使用子类,必须使用字符转换流。
操作的具体的类
InputStreamReader:字节流到字符流之间的转换
OutputStreamReader:字符流到字节流之间的转换
Public class InputStreamReader extends Reader
(1)InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset
读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
(2)每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
(3)为了达到最高效率,可以考虑在 BufferedReader 内包装 InputStreamReader。例如:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); //重要
public class OutputStreamWriter extends Writer
(1)OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset
将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
(2)每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。
(3)为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:
BufferedWriter writer = new BufferedWriter(new OutputStreamReader(System.out)); //重要
转换流的简单使用:利用标准输入流将文本输出到控制台
代码:
1 package io深入学习; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.io.OutputStreamWriter; 8 9 /** 10 * 转换流: 11 * 1、字节流(全是纯文本内容)--->字符(解码) 12 * 2、指定字符集 13 * @author liuzeyu12a 14 * 15 */ 16 public class ConvertStream { 17 18 public static void main(String[] args) { 19 test02(); 20 } 21 public static void test01() { 22 //操作System.in字节输入流,System.out字节输出流 23 try(InputStreamReader reader = new InputStreamReader(System.in); 24 java.io.OutputStreamWriter write = new java.io.OutputStreamWriter(System.out)){ 25 26 }catch(Exception e) { 27 System.out.println("操作异常"); 28 } 29 } 30 //加上缓存区,字符输入--->(程序处理)字节---->字符输出 31 public static void test02() { 32 //操作System.in字节输入流,System.out字节输出流 33 try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 34 BufferedWriter write = new BufferedWriter(new OutputStreamWriter(System.out))){ 35 36 //循环获取键盘的输入 37 String msg=""; 38 while(!msg.equals("exit")) { 39 msg=reader.readLine(); 40 write.write(msg); 41 //小文本需要强制刷新 42 write.flush(); 43 } 44 }catch(IOException e) { 45 System.out.println("操作异常"); 46 } 47 } 48 }
拓展:网络爬虫的简单应用
通过网络流(字节流)--->向字符流的转换,从百度上爬取源码:
代码:
1 package io深入学习; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.FileOutputStream; 6 import java.io.InputStream; 7 import java.io.InputStreamReader; 8 import java.io.OutputStreamWriter; 9 import java.net.URL; 10 11 /** 12 * 转换流: 13 * 1、字节流(全是纯文本内容)--->字符(解码) 14 * 2、指定字符集 15 * @author liuzeyu12a 16 * 17 */ 18 public class ConvertStream2 { 19 20 public static void main(String[] args) { 21 //test02(); 22 test03(); 23 } 24 25 public static void test01() { 26 //获取网络字节流 27 try(InputStream is =new URL("http://www.baidu.com").openStream()){ 28 int temp = 0; 29 while((temp = is.read())!=-1) { 30 System.out.print((char)temp); //字节数不够出现乱码 31 } 32 33 }catch(java.io.IOException e) { 34 e.printStackTrace(); 35 } 36 } 37 38 //爬取百度的源码 39 public static void test02() { 40 //获取网络字符流 41 //这边百度源码采用UTF-8,而工程的字符采用GBK,为了不造成乱码,于是可以指定字符集 42 try(InputStreamReader reader =new InputStreamReader( 43 new URL("http://www.baidu.com").openStream(),"UTF-8")){ 44 int temp = 0; 45 while((temp = reader.read())!=-1) { 46 System.out.print((char)temp); 47 } 48 49 }catch(java.io.IOException e) { 50 e.printStackTrace(); 51 } 52 } 53 //爬取百度的源码,+缓冲 54 public static void test03() { 55 //获取网络字符流 56 //这边百度源码采用UTF-8,而工程的字符采用GBK,为了不造成乱码,于是可以指定字符集 57 try(BufferedReader reader =new BufferedReader( 58 new InputStreamReader( 59 new URL("http://www.baidu.com").openStream(),"UTF-8")); 60 BufferedWriter write = 61 new BufferedWriter(new OutputStreamWriter( 62 new FileOutputStream("baidu.html"),"UTF-8"))){ 63 64 String line = null; 65 while((line = reader.readLine())!=null) { 66 write.write(line); 67 } 68 69 }catch(java.io.IOException e) { 70 e.printStackTrace(); 71 } 72 } 73 }
jdk 1.60 开发文档
https://www.cnblogs.com/hopeyes/p/9736642.html
https://www.cnblogs.com/zhaoyanjun/p/6292384.html