1.测试方式
分别采用随机读取和顺序读取的方式读取文件
2.Demo代码
package test;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class IOTest {
public static void main(String[] args) throws IOException {
//缓存大小设置为1000000字节
int bufferSize=100000000;
//要读取的文件路径
String filePath = "D:\\testc.rar";
//顺序读取计算所用时间
sequentialRead(filePath,bufferSize);
//随机读取,计算所用时间
randomRead(filePath,bufferSize);
}
private static void randomRead(String filePath, int bufferSize) throws IOException {
//创建文件进行随机读取
RandomAccessFile aFile = new RandomAccessFile(filePath,"r");
FileChannel inChannel = aFile.getChannel();
//开始时间
Long beginTime = System.currentTimeMillis();
//创建buffer
ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
//进行10次随机读取
for (int i = 0; i < 10; i++) {
long pos =(long) (Math.random()*inChannel.size());
//根据随机位置读取文件
inChannel.read(buffer,pos);
buffer.clear();
}
//关闭文件和通道
inChannel.close();
aFile.close();
//结束时间,记录耗时
Long endTime = System.currentTimeMillis();
long time = endTime-beginTime;
System.out.println("随机读耗时:"+time+"ms");
}
private static void sequentialRead(String filePath, int bufferSize) throws IOException {
//顺序读取
File aFile = new File(filePath);
FileInputStream inFile = new FileInputStream(aFile);
FileChannel inChannel = inFile.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
//开始时间
Long beginTime = System.currentTimeMillis();
//顺序读取十次
for (int i = 0; i < 10; i++) {
inChannel.read(buffer);
buffer.clear();
}
//关闭文件和通道
inChannel.close();
inFile.close();
//记录耗时
Long endTime = System.currentTimeMillis();
long time = endTime-beginTime;
System.out.println("顺序读取耗时:"+time +"ms");
}
}
3.测试结果
bufferSize(byte) | 文件大小 | 顺序读耗时(ms) | 随机读耗时(ms) | 随机/顺序 |
100000000 | 320M | 352 | 609 | 1.73 |
230 | 666 | 2.90 | ||
275 | 650 | 2.36 | ||
1.2G | 648 | 789 | 1.22 | |
658 | 824 | 1.25 | ||
634 | 697 | 1.10 | ||
1000000 | 6.4M | 5 | 6 | 1.20 |
4 | 5 | 1.25 | ||
5 | 4 | 0.80 | ||
320M | 4 | 10 | 2.50 | |
5 | 12 | 2.40 | ||
6 | 11 | 1.83 | ||
1.2G | 14 | 17 | 1.21 | |
6 | 14 | 2.33 | ||
6 | 15 | 2.50 | ||
100 | 6.4M | 2 | 1 | 0.50 |
1 | 1 | 1.00 | ||
1 | 1 | 1.00 | ||
320M | 2 | 2 | 1.00 | |
1 | 2 | 2.00 | ||
4 | 3 | 0.75 | ||
1.2G | 1 | 4 | 4.00 | |
1 | 2 | 2.00 | ||
1 | 2 | 2.00 |
4.结果分析
影响测试结果的因素很多,测试注意点如下
1.文件不能太小,文件太小可能会第一次读取的时候就被加到了缓存中,后续都是读取的缓存。
2.读取顺序不能变。如果先随机读,在顺序读。随机读的时候会把一些数据放入缓存,顺序读的时候就会加速。这样就无法分辨是因为顺序读快还是因为读缓存导致的快。
3.bufferSize不能太小,原因如1。
除了文件太小的情况下会个别案例出现随机读更快的情况,绝大多数都是顺序读更快。
相关问题
顺序读取具体能快多少?
这个问题没有一个固定的答案,因为顺序读取与随机读取的速度差异会受到很多因素的影响,包括硬盘的类型、硬盘的转速、数据的大小、存储设备的缓冲区大小、操作系统的文件系统类型、数据的碎片化程度等等。
在传统的机械硬盘(HDD)中,顺序读取的速度可以比随机读取快十倍甚至更多。对于固态硬盘(SSD)来说,由于它们的硬盘头移动速度极快,因此顺序读取和随机读取的速度差距会小很多,但通常顺序读取的速度依然会比随机读取快。
值得注意的是,这里说的是一般情况,具体的速度差异还需要实际测试才能得出。
5.java技术栈中的使用
1.kafka.是按顺序写入的
2.mysql InnoDB:在批量写入的时候会使用顺序IO做优化
3.starRocks:先将数据写入内存缓冲区,再以顺序IO方式刷入磁盘。