一、前言
所谓IO,也就是Input/Output。Java程序跟外部进行的数据交换就叫做Java的IO操作。程序中数据的输入输出,被抽象为流, 按照相对于程序的流向,可分为输出流和输入流。 按照数据流的格式,可分为字节流和字符流。Java IO流的体系很庞大,功能丰富。
本文主要探讨了Java中字节操作和字符操作的区别。
二、字节操作和字符操作
下图可以表示Java 的IO体系:
类似于C语言中二进制文件和文本文件的区别,字符其实只是一种特殊的二进制字节,是按照一定的编码方式处理之后,按照一定规则来存储信息的数据,字符在计算机中也是由二进制组成的,只不过这种二进制可以按照一种规则解码后,成为人类可以直接阅读的自然语言,而普通的二进制文件只有计算机能直接“阅读”。字节操作和字符操作的区别就在于数据的格式。
在Java中,字节输入输出流有两个抽象基类:
- 字节输入流:InputStream
- 字节输出流:OutputStream
字符输入输出流也有两个抽象基类:
-
字符输入流:Reader
-
字符输出流:Writer
此外, Java提供了从字节流到字符流的转换流,分别是InputStreamReader和OutputStreamWriter,但没有从字符流到字节流的转换流。实际上:
字符流=字节流+编码表
一次读取一个字节数组的效率明显比一次读取一个字节的效率高,因此Java提供了带缓冲区的字节类,称为字节缓冲区类:BufferedInputStream和BufferedOutputStream,同理还有字符缓冲区类BufferedReader和BufferedWriter。
在使用场景上,无法直接获取文本信息的二进制文件,比如图片,mp3,视频文件等,只能使用字节流。而对于文本信息,则更适合使用字符流。
三、两种方式的效率测试
下面通过编写测试程序来比较两种方式的效率区别:
3.1 测试代码
笔者编写了8个方法来分别测试字节方式/字符方式的输入输出流,带缓冲区的输入输出流。
package com.verygood.island;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.platform.commons.annotation.Testable;
import java.io.*;
/**
* @author <a href="mailto:kobe524348@gmail.com">黄钰朝</a>
* @description
* @date 2020-05-27 08:50
*/
@Testable
public class UnitTest {
public static final String PATH = "C:\\Users\\Misterchaos\\Documents\\Java Develop Workplaces\\" +
"Github repository\\island\\src\\test\\java\\com\\verygood\\island\\";
/**
* 用于输出的对象
*/
public static byte[] outputbytes = null;
public static char[] outputchars = null;
int count = 1;
/**
* 用于输入的对象
*/
public static final File inputFile = new File("C:\\Users\\Misterchaos\\Downloads\\安装包\\TEST.zip");
@BeforeClass
public static void before() {
StringBuilder stringBuilder = new StringBuilder("");
for (int i = 0; i < 1000000; i++) {
stringBuilder.append("stringstringstringstringstringstring");
}
outputbytes = stringBuilder.toString().getBytes();
outputchars = stringBuilder.toString().toCharArray();
}
@Test
public void test0() {
System.out.println("--------------------------------------------------------");
System.out.println(" 测试输出流 ");
System.out.println("--------------------------------------------------------");
}
// 字节流
@Test
public void test1() {
try {
System.out.println("********方式一:字节流输出**********");
// 新建文件命名
String name = PATH + "字节流输出文件.txt";
File file = new File(name);
// 创建输入输出流对象
FileOutputStream fos = new FileOutputStream(file);
// 读写数据
long s1 = System.currentTimeMillis();// 测试开始,计时
writeBytes(fos);
long s2 = System.currentTimeMillis();// 测试结束,计时
fos.close();
System.out.println("输出文件耗时:" + (s2 - s1) + "ms");
System.out.println("文件大小:" + file.length() / 1024 + "KB");
file.delete();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e