大家知道java RandomAccessFile类 提供了光标定位到文本指定位置 实现随机读取,对于大文本性能很高,但是jdk没有提供定位到指定位置后找到行头再开始读取的这样一个功能,这里手写一个,实现光标定位到指定位置后,定位到行头,并一次读取指定大小的数据,数据完整不会有乱码。
public class FileRandomRead {
/**
*
* 对于一个超大文本文件,文件中每一行数据都是一条有效数据。每行数据大小小于1KB
*
* 现在要随机从文件某个位置开始,每次读取不少于128KB的数据。
*
* 要保证读取的内容中必须包含开始位置,并且开始、与结束部分,是完成的一行数据。
*
* */
public static void main(String[] args) throws IOException {
File file = new File("d:/javatest/random.txt");
long randomLocation = (long) (Math.random() * file.length());
//unit test
randomLocation = 17;
List<String> list = randomReadLine(file, randomLocation);
list.stream().forEach(System.out::println);
}
public static List<String> randomReadLine(File file, long pos) throws IOException {
@Cleanup
final RandomAccessFile f = new RandomAccessFile(file, "r");
String separator = System.getProperty("line.separator");
f.seek(pos);
int c = f.read();
//判断是否换行,寻找行开头
while (c != 10 && --pos != -1) {
f.seek(pos);
c = f.read();
}
//纠正位置
f.seek(++pos);
List<String> lineList = new ArrayList<>();
String line;
while ((line = f.readLine()) != null) {
//RandomAccessFile会将编码格式转换成 ISO-8859-1,所以此处要转回来
lineList.add(new String(line.getBytes("ISO-8859-1"), "utf-8"));
String content = String.join(separator, lineList);
//业务要求最少读取128kb
if (content.getBytes().length >= 128 * 1000) {
break;
}
}
return lineList;
}
}
如果对你有帮助,别忘了给文章点赞呦~