Java基础—IO小结(二)缓冲流与其它流的使用
一、缓冲流的使用
每个字节流都有对应的缓冲流:
BufferedInputStream / BufferedOutputStream
构造器:
方法摘要与对应节点流类似
使用缓冲流实现文件复制:实际中也是;其中流的关闭只需要关闭缓冲流,内部嵌套的字节流会自动关闭。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void testBuffered1() { // 同样需要先关联文件,注意文本使用Reader Writer,非文本使用fis fos File file1 = new File("D:\\test\\1.jpg"); File file2 = new File("D:\\test\\2.jpg"); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { // 创建节点流 FileInputStream fis = new FileInputStream(file1); FileOutputStream fos = new FileOutputStream(file2); // 将节点流包装为缓冲流 bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); // 准备缓冲的数组 byte[] bytes = new byte[20]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes, 0, len); // 写完后将最后的进行刷新一下 bos.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { // 关闭流,注意流的关闭顺序,直接关闭缓冲流时,会自动先关闭对应节点流 if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
BufferedReader与BufferedWriter的使用也是与对应节点流类似
演示独有的readLine方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void testBufferedReader() { File file1 = new File("D:\\test\\hello.txt"); BufferedReader br = null; try { FileReader fr = new FileReader(file1); br = new BufferedReader(fr); // 使用br独有的读行的操作 String s = null; while ((s = br.readLine()) != null) { System.out.println(s); } } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } }
// 注意,读取doc文档需要使用字节流(即使文档全部是文本组成,doc也已经不是纯文本文件了)
二、转换流的使用
InputStreamReader / OutputStreamWriter
JDK中的介绍如下:需要分清编码与解码的过程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。 每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。 为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如: BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。 每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。 为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如: Writer out = new BufferedWriter(new OutputStreamWriter(System.out)); 代理对 是一个字符,它由两个 char 值序列表示:高 代理项的范围为 '\uD800' 到 '\uDBFF',后跟范围为 '\uDC00' 到 '\uDFFF' 的低 代理项。 错误代理元素 指的是后面不跟低代理项的高代理项,或前面没有高代理项的低代理项。 此类总是使用字符集的默认替代序列 替代错误代理元素和不可映射的字符序列。如果需要更多地控制编码过程,则应该使用 CharsetEncoder 类。
解码,解成我们能够看得懂的,也就是解成字符串
简单示例如下:(不是特别重要,不作特别介绍这里)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void test1() { File file = new File("D:\\test\\hello.txt"); // 异常处理暂略 FileInputStream fis = new FileInputStream(file); // 字节流到字符流的解码 InputStreamReader isr = new InputStreamReader(fis, "GBK"); BufferedReader br = new BufferedReader(isr); String s; // 缓冲流的操作略去 }
三、标准输入输出流
也就是我们常见的Syetem.out/in
接收用户输入使用示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void test1() { BufferedReader br = null; try { InputStream in = System.in; // 转换成字符流 InputStreamReader isr = new InputStreamReader(in); br = new BufferedReader(isr); String s; while (true) { System.out.println("请输入字符串:"); s = br.readLine(); if ("exit".equalsIgnoreCase(s)) { break; } String s1 = s.toUpperCase(); System.out.println(s1); } } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } }
四、其它流
1.打印流
打印流都是输出流,所以分为两个:字节打印流和字符打印流
像我们常用的Sytem.out返回的就是一个打印流
关于打印流的信息,请参见 酒香逢 的随笔:http://www.cnblogs.com/fnz0/p/5423201.html
2.数据流
用来处理基本数据类型(包括String等)
数据流请参见:http://baihe747.iteye.com/blog/2072146
3.对象流
推荐的序列化与反序列工具是hutool的ObjectUtil的相关方法!
序列化:
序列化一个类的示例:(必须实现相关接口,并且属性也需要实现Serializable接口)——ObjectOutputStream
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void test1() { // 对象 Person p1 = new Person("小明", 18); Person p2 = new Person("小红", 23); ObjectOutputStream oos = null; try { // 对象流 FileOutputStream fos = new FileOutputStream(new File("person.txt")); oos = new ObjectOutputStream(fos); oos.writeObject(p1); oos.writeObject(p2); } catch (IOException e) { e.printStackTrace(); } finally { if (oos != null) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class Person implements Serializable{ String name; Integer age; public Person(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
应当加上版本号声明:
class Person implements Serializable{
private static final long serialVersionUID = 1L;
结果:
反序列化:——ObjectInputStream
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void test2() { ObjectInputStream ois = null; try { FileInputStream fis = new FileInputStream(new File("person.txt")); ois = new ObjectInputStream(fis); // 反序列化到内存中了 Person p1 = (Person) ois.readObject(); System.out.println("p1 = " + p1); Person p2 = (Person) ois.readObject(); System.out.println("p2 = " + p2); } catch (Exception e) { e.printStackTrace(); } finally { if (ois != null) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
结果:
当然,除了上述的文件流,我们还可以进行byte[]数组流的序列化与反序列化,相关的工具类,推荐如下:
package cn.itcast_03_netty.sendobject.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ByteObjConverter {
/**
* 使用IO的inputstream流将byte[]转换为object
* @param bytes
* @return
*/
public static Object byteToObject(byte[] bytes) {
Object obj = null;
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream oi = null;
try {
oi = new ObjectInputStream(bi);
obj = oi.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bi.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
oi.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return obj;
}
/**
* 使用IO的outputstream流将object转换为byte[]
* @param bytes
* @return
*/
public static byte[] objectToByte(Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = null;
try {
oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
bytes = bo.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bo.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
oo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
}
4.随机存取流
可以解决之前不能追加文件内容,只能覆盖的情况