目录
一、定义小数组+FileInputStream、小数组+BufferedInputStream、BufferedReader字符流按行和小数组+BufferedReader读取简单说明
一、定义小数组+FileInputStream、小数组+BufferedInputStream、BufferedReader字符流按行和小数组+BufferedReader读取简单说明
首先,对于相关知识点不是很理解的,推荐花几分钟时间看下我之前写的两篇文章,对这些有个大概了解。
解释一下相关类
类 | 相关解释 |
FileInputStream | 输入流,read默认读取一个字节 |
BufferedInputStream | 输入缓冲字节流,一次性可以读取关联文件8*1024个字节 |
BufferedReader | 输入缓冲字符流,一次性可以读取关联文件8*1024个字节 |
InputStreamReader | 字节流转为字符流中间类 |
byte(char) | 这篇文章中指的小数组 |
经过我的测试得出结论,对四种读取效率从高到底排序(质疑的可以下方留言讨论,有更快的读取方式也可以介绍一下):
小数组+FileInputStream > 小数组+BufferedInputStream = 小数组+BufferedReader > BufferedReader按行读取
下面是对四种方式的介绍
1、我认为第一种方式使用小数组+FileInputStream读取方式效率是最高的,就是定义一种byte可以控制的字节流大小进行读取。(注意:是我认为,如果觉得我是错的,可以下方留言)
2、第二种方式小数组+BufferedInputStream进行读取,BufferedInputStream中也定义了一个8*1024的byte缓冲区,可以一次性将需要读取的文件8*1024大小的字节流刷到缓冲区中,其实这种读取方式也是一种小数组,只是内部封装了而已。刷到缓冲区后,我们要定义一个byte去缓冲区读取接收它(不定义效率很低),所以它使用的内存是第一种方式的两倍内存,所以我认为自己定义小数组的读取方式效率最高。
3、第三种方式BufferedReader按行读取,内部也定义了8*1024的char缓冲区,通过InputStreamReader转换流将字符流一次性刷到缓冲区中,效率和第二种方式差不了多少,关键是它从缓冲区进行按行读取效率可能会比BufferedInputStream效率要低。一次性读取和每次读取一行,想想也知道哪个效率高了。
4、第四种方式小数组+BufferedReader进行读取,就是在缓冲区中按行读取的情况下改成按char字符小数组读取,当char数组大于一行又或者说一行很少内容的时候,效率肯定比按行读取高。但是内存上也消耗了一个char数组的大小。
总之,第二种方式是对第一种的内部包装,但是读取的时候需要多定义一个数组。第四种方式仅改变了从每次缓冲区读取大小。不管是内存还是速度上,第一种方式都绝对占据优势。
二、小数组+FileInputStream读取文件
这是一种个人认为最高效可靠的小数组+FileInputStream进行读取方式,下面贴代码。
@Test
public void test1() throws IOException {
//定义可变字符串进行接收
StringBuffer stringBuffer = new StringBuffer();
//定义小数组读取(一次读8kb,2m文件大概读取2*1024/8=256次,也就是与磁盘交换256次)
byte[] bytes = new byte[8*1024];
//使用FileInputStream输入流
try(FileInputStream fileInputStream = new FileInputStream("D:\\project_location\\datastructure\\src\\json.json")) {
long startTime = System.currentTimeMillis();
int len;
while ((len = fileInputStream.read(bytes)) != -1) {
stringBuffer.append(new String(bytes, 0, len));
}
System.out.println(i);
//消耗时间(大概消耗0.16m)
System.out.println("使用小数组+FileInputStream耗时:"+ (System.currentTimeMillis() - startTime) / 1000.0 + "s");
} catch (IOException e) {
e.printStackTrace();
}
}
这里采用了8*1024=8k的byte数组形式读取7m多点的文件(读磁盘数为902次,这是我在while里面定义计数器得到的。计算方式也可以:7*1024*1024/8*1024=896次),每次读取7m的文件大概耗时0.16s左右(网络会影响时间长短)。
如果采取1024*1024=1m的byte数组读取则耗时大概是0.13s左右,并且读磁盘数只有8次。虽然byte数组定义越大读取越快,较少磁盘交互次数,但因为消耗了内存,不见得越大越好。
三、小数组+BufferedInputStream读取文件
这是第二种方式小数组+BufferedInputStream进行读取读取方式,下面贴代码。
@Test
public void test2() throws IOException {
//定义可变字符串进行接收
StringBuffer stringBuffer = new StringBuffer();
//定义小数组读取
byte[] bytes = new byte[8*1024];
//使用BufferedInputStream缓冲流
try(BufferedInputStream is = new BufferedInputStream(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"));) {
long startTime = System.currentTimeMillis();
int len;
while ((len = is.read(bytes)) != -1) {
stringBuffer.append(new String(bytes, 0, len));
}
//消耗时间(大概消耗0.17s)
System.out.println("使用小数组+BufferedIuputStream耗时:"+ (System.currentTimeMillis() - startTime) / 1000.0 + "s");
} catch (IOException e) {
e.printStackTrace();
}
}
因为底层是封装了一个8*1024的缓冲区,关于读磁盘数都和上面第一种方式一样,只是这里多定义了一个外在8*1024的byte去接收字符串,这里耗时大概是0.17s,相比第一种慢了0.01s左右,可能走的封装过程消耗了点时间。其实和第一种效率差不多,除了多消耗一倍内存。
四、BufferedReader按行读取文件
这是第三种BufferedReader按行读取方式,下面贴代码。
@Test
public void test3() {
//创建可变字符流接收
StringBuffer stringBuffer = new StringBuffer();
//使用BufferedReader流 将字节流转为字符流,进行高效读取
try(BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"),"utf-8"))) {
String str = null;
//记录开始时间
long startTime = System.currentTimeMillis();
//按行读取
while ((str = bufferedReader.readLine()) != null) {
stringBuffer.append(str);
}
//花费时间(大概0.26s)
System.out.println("使用BufferedReader耗时:" + (System.currentTimeMillis() - startTime) / 1000.0 + "s");
} catch (Exception e) {
e.printStackTrace();
}
}
以上采用了BufferedReader按行进行读取,7m的文件大概用了0.26s左右。
五、小数组+BufferedReader读取文件
@Test
public void test4() {
//创建可变字符流接收
StringBuilder stringBuilder = new StringBuilder();
//定义小数组读取
char[] chars = new char[8*1024];
//使用BufferedReader流 将字节流转为字符流,进行高效读取
try(BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"),"utf-8"))) {
//记录开始时间
long startTime = System.currentTimeMillis();
int len = 0;
while ((len = bufferedReader.read(chars)) != -1) {
stringBuilder.append(new String(chars, 0, len));
}
//花费时间(大概0.18s)
System.out.println("使用BufferedReader耗时:" + (System.currentTimeMillis() - startTime) / 1000.0 + "s");
} catch (Exception e) {
e.printStackTrace();
}
}
以上采用了小数组+BufferedReader进行读取,7m的文件大概用了0.18s左右。
六、顺提一下拷贝文件
拷贝建议用字节流,贴代码
@Test
public void test5() {
byte[] bytes = new byte[8*1024];
//使用BufferedInputStream输入流
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("D:\\project_location\\datastructure\\src\\json.json"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("D:\\project_location\\datastructure\\src\\json2.json"))) {
long startTime = System.currentTimeMillis();
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
bufferedOutputStream.write(bytes,0, len);
}
//消耗时间(大概消耗0.04s)
System.out.println("使用BufferedInputStream进行拷贝耗时:" + (System.currentTimeMillis() - startTime) / 1000.0 + "s");
} catch (IOException e) {
e.printStackTrace();
}
}
消耗时间竟然只有0.04左右...,不定义byte时,用了0.4,十倍差距。