news 2026/8/6 18:44:08

java文件按行写入数据后并创建行索引及查询

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java文件按行写入数据后并创建行索引及查询

背景

当有很多数据需要存储,这些数据只是想要简单的按行存储和查询,不需要进行其他条件搜索,此时就可以考虑不需把这些数据存储在数据库,而是直接写入文件,然后从文件中查询

但是正常情况下,如果仅仅只是按行写入文件,读取的时候如果不是从第一行开始读,java api是不支持直接定位到某行开始查询,比如如果想查出第1000行之后的数据,此时需要先读取前面999行的数据之后才能读取第1000行的数据,可想而知性能好不到哪去。

有些人可能会说用RandomAccessFile可以直接跳过一定偏移量定位到999行,可是正常情况下,我们并不能知道999行对应的偏移量,也就无法知道要跳过多少偏移量直接定位到999行。

本文主要是提供了解决上面问题的工具。

实现功能

1.可以按行写入数据,并对写入的每一行创建索引

2.基于索引快速定位到行所在位置,不需要一行行遍历
3.支持对写入数据进行分片。比如写入1W条数据,1000条数据一个文件

4.支持分页查询

5.支持指定行号查询

6.支持写部分数据后,继续往后添加新数据

7.不支持从中间插入数据(后续不会支持,因为目前的实现机制从中间插入,插入行后面的所有行都得重新构造索引)

代码地址

g5zhu5896/file-storage · GitHub

介绍

核心类

FileDataWriter

用于往文件中写入数据并创建索引

使用:

String path= "/file/张三/"; Integer totalSize = 10000; Integer fileMaxSize=1000; String charset=CharsetUtil.UTF_8; Long indexFixedWidthFactor = 3l; //如果文件已存在写入会报错 if (!new File(path).exists()) { WriteMode writeMode = WriteMode.NOT_ALLOW_REPEATED; try (FileDataWriter fileDataWriter = FileDataWriter.builder().withFileMaxSize(fileMaxSize) .withIndexFixedWidthFactor(indexFixedWidthFactor) .withWriteMode(writeMode) .withCharset(charset).build(filePath)) { for (Long i = 1L; i <= totalSize; i++) { fileDataWriter.write(i + ""); } } catch (IOException e) { e.printStackTrace(); } }

相关配置

fileMaxSize:配置一个文件最大存储的行数path:文件要存储的路径。可以自定义规则indexFixedWidthFactor: 索引固定宽度因子,用于计算索引文件中索引的固定宽度。配的越大越浪费空间,配小了更容易触发调整固定宽度charset:配置写文件的编码 writeMode: 写入模式NOT_ALLOW_REPEATED: 不允许重复写入,当写入文件夹已存在数据,会直接抛异常OVERRIDE:覆盖模式,当写入文件夹已存在数据,会删除文件重新写入APPEND:追加模式,当写入文件夹已存在数据,会往最新的数据文件的最后一行继续写(APEEND 模式在存在数据文件时下 charset、fileMaxSize、indexFixedWidthFactor会无效)

FileDataPageReader

使用:

String path= "/file/张三/"; //如果文件不存在则无法读取 if (!new File(path).exists()) { FileDataPageReader fileDataPageReader = FileDataPageReader.builder().build(path); //分页查询 //从第二页开始查询 Integer page = 2; //一页查20条 Integer pageSize=20 List<String> strings = fileDataPageReader.readPage(page, pageSize); //将行内容转成Interger,此处也可以把json转成对象 List<Integer> strings = fileDataPageReader.readPage(page, pageSize,item->{ return new Integer(item); }); //指定行数查询 //从第5行开始查 Integer startIndex = 5; //共查100条 Integer size = 100; List<String> strings = fileDataPageReader.read(startIndex, size); //将行内容转成Interger,此处也可以把json转成对象 List<Integer> strings = fileDataPageReader.read(startIndex, size,item->{ return new Integer(item); }); //获取总行数 Integer totalSize=fileDataPageReader.getTotalSize(); }

文件介绍

(目前文件后缀只能写死,可以通过改Constants类调整生成后缀)

.dat文件

数据文件,按行写入。会有多个,文件如下图所示

.idx

行索引文件,会有多个,存储每一行对应的文件偏移量,通过该文件快速定位数据文件的行偏移量,如下图所示

cfg

配置文件,记录当前文件的一些配置信息,如下图所示

相关配置

fileMaxSize:配置每一个文件最大存储的行数totalSize:总行数charset:配置写文件的编码columnIndexWidthMap:行索引动态固定宽度map,主要用于减少索引文件的大小。有序,{1:4,1852:8}表示1-1851行的间距是4,1852及之后的行的间距是8下面配置主要是WriteMode.APPEND用的newCurrentRow: 最新数据文件最后写入行行数+1后的行数newIndexFixedWidth:最新文件最后一行写入后的索引固定宽度newDataFilePointer:最新数据文件的最后写入行写入后末尾的偏移量newIndexFilePointer:最新索引文件的最写入行写入后末尾的偏移量

相关依赖

<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> <scope>provided</scope> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.26</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency>

注意

本文代码仅基于Test.main中的demo进行测试验证过,所以依然可能存在bug,但个人感觉测试的demo已经挺多的了.

核心逻辑

定位数据行

主要通过RandomAccessFile.seek快速定位到行偏移量,然后通过索引文件获取具体的行偏移量。这没什么好说的,

从索引文件中获取数据行偏移量

索引文件需要存储数据行中的偏移量,但是索引文件中包含很多行,我们想知道数据行的偏移量在索引文件中的哪个位置,也无法直接定位。

所以为了快速从索引文件中定位到数据行的偏移量,采用了索引固定宽度的做法。具体如下

假设indexFixedWidthFactor=3

step1:写入第1行数据,假设占用行偏移量9,宽度为1,则当前索引固定宽度为curFixedWidth=1+indexFixedWidthFactor=4,写入索引文件第1行的偏移量为0000(记录的是写入前的偏移量,那才是行开始位置)代码在FileDataWriter.write)

step2:写入第2行数据,假设占用10个行偏移量,加上第1行的偏移量后为19,写入第2行偏移量0009,以此类推,第3行为0019

step3:直到写入103行,假设写入后的行偏移量的行偏移量为10009,由于10009宽度为5,大于curFixedWidth,于是重新计算当前索引固定宽度为curFixedWidth=5+indexFixedWidthFactor=8,所以第104行的行偏移量是00010009。以此类推

step4:假设150行宽度依然小于8,然后写到151行,当前文件写满,需要写下一个文件,则会从头如step1一样计算索引固定宽度curFixedWidth=1+indexFixedWidthFactor=4。

step5:假设只写到179行,最后的curFixedWidth=4,此时会将配置信息写入 cfg 文件,其中包括columnIndexWidthMap={1:4, 104:8, 151:4}(代码在FileDataWriter.close)

step6:,由于是每一行的行偏移量是固定宽度,读取的时候就可以基于columnIndexWidthMap和要读取的行号,计算出行数据文件的行偏移量在索引文件中的偏移量,直接读取出数据文件的行偏移量(代码在FileDataPageReader.computeSeek)(如假设要从120行开始读取,则行偏移量为4*(104-1)+8*(120-104),从此处往后读取8位及120行的数据文件行偏移量

可以优化的点

现在写索引文件是按字符写入的,比如0001,写入就是四个字符,其实可以根据数字大写,根据实际长度写入short,int,long 类型数据,这样可以减少索引文件的体积。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/6 18:42:59

5分钟快速掌握VeraCrypt:开源磁盘加密的实战指南

5分钟快速掌握VeraCrypt&#xff1a;开源磁盘加密的实战指南 【免费下载链接】VeraCrypt Disk encryption with strong security based on TrueCrypt 项目地址: https://gitcode.com/GitHub_Trending/ve/VeraCrypt VeraCrypt是一款基于TrueCrypt的开源磁盘加密软件&…

作者头像 李华
网站建设 2026/8/6 18:41:50

如何在Windows电脑上免费畅玩Switch游戏:yuzu模拟器完整指南

如何在Windows电脑上免费畅玩Switch游戏&#xff1a;yuzu模拟器完整指南 【免费下载链接】yuzu 任天堂 Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu 想要在您的Windows电脑上体验《塞尔达传说&#xff1a;旷野之息》、《超级马里奥&#xff1…

作者头像 李华
网站建设 2026/8/6 18:41:01

游戏本办公两用笔记本推荐,来酷斗战者 战7000P 酷睿版兼顾两种需求

很多人买电脑时面临一个两难选择&#xff1a;买游戏本吧&#xff0c;怕太重太张扬、在公司拿出来不合适&#xff1b;买轻薄本吧&#xff0c;下班想打两把游戏根本跑不动。其实这个矛盾并非无解&#xff0c;关键在于找到一台外观设计相对克制、性能又足够强劲的机器。今天做一期…

作者头像 李华
网站建设 2026/8/6 18:39:25

Oracle DELETE操作全解析:从原理到高性能批量删除实战

在数据库开发与运维的日常工作中&#xff0c;你是否曾因一个看似简单的数据删除操作而陷入困境&#xff1f;尤其是在处理Oracle这类关键业务数据库时&#xff0c;DELETE语句的执行结果远不止“数据消失”那么简单&#xff0c;其背后涉及的事务控制、回滚机制、空间释放以及对性…

作者头像 李华
网站建设 2026/8/6 18:37:00

云端部署AI Agent实战:基于腾讯云Lighthouse与OpenClaw的完整指南

1. 项目缘起&#xff1a;为什么要在云端折腾OpenClaw&#xff1f;最近几个月&#xff0c;AI Agent&#xff08;智能体&#xff09;这个概念火得不行&#xff0c;从各种技术论坛到社交媒体&#xff0c;几乎每天都能看到新的框架和玩法。作为一个喜欢折腾新技术的开发者&#xff…

作者头像 李华
网站建设 2026/8/6 18:35:28

ViGEmBus终极指南:Windows虚拟手柄驱动快速配置手册

ViGEmBus终极指南&#xff1a;Windows虚拟手柄驱动快速配置手册 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 想要在Windows上解决游戏手柄兼容性问题&…

作者头像 李华