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

news2025/1/23 12:53:47

背景

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

        但是正常情况下,如果仅仅只是按行写入文件,读取的时候如果不是从第一行开始读,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()) {
    try (FileDataWriter fileDataWriter = FileDataWriter.builder().withFileMaxSize(fileMaxSize)
			.withIndexFixedWidthFactor(indexFixedWidthFactor )
			.withCharset(charset).build(filePath)) {
		for (Long i = 1L; i <= totalSize; i++) {
			fileDataWriter.write(i + "");
		}
	} catch (IOException e) {
		e.printStackTrace();
	}
}

相关配置

fileMaxSize:配置一个文件最大存储的行数
path:文件要存储的路径。可以自定义规则
indexFixedWidthFactor: 索引固定宽度因子,用于计算索引文件中索引的固定宽度。配的越大越浪费空间,配小了更容易触发调整固定宽度
charset:配置写文件的编码

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

相关依赖

<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行的数据文件行偏移量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280907.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot集成Flink-CDC,实现对数据库数据的监听

一、什么是 CDC &#xff1f; CDC 是Change Data Capture&#xff08;变更数据获取&#xff09;的简称。 核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数据表的插入、 更新以及删除等&#xff09;&#xff0c;将这些变更按发生的顺序完整记录下来&…

VisualStudio中配置OpenGL环境并制作模板

VisualStudio中配置OpenGL环境并制作模板 本教程来自&#xff1a;sumantaguha Install Visual Studio Download Microsoft Visual Studio Community 2019 from https://my. visualstudio.com/Downloads?qvisual%20studio%202019&wt.mc_ idomsftvscom~older-downloads and…

工程上LabVIEW常用的控制算法有哪些

在工程应用中&#xff0c;LabVIEW常用的控制算法有很多&#xff0c;它们广泛应用于自动化、过程控制、机器人、测试测量等领域。以下是一些常见的控制算法&#xff1a; 1. PID 控制 用途&#xff1a;PID&#xff08;比例-积分-微分&#xff09;控制是最常用的反馈控制算法&…

WPF1-从最简单的xaml开始

1. 最简单的WPF应用 1.1. App.config1.2. App.xaml 和 App.xaml.cs1.3. MainWindow.xaml 和 MainWindow.xaml.cs 2. 正式开始分析 2.1. 声明即定义2.2. 命名空间 2.2.1. xaml的Property和Attribute2.2.2. xaml中命名空间2.2.3. partial关键字 学习WPF&#xff0c;肯定要先学…

对话小羊驼vicuna

文章目录 1. gpu租用2. 公网网盘存储实例/数据3. 登录实例4. 预训练模型下载5. llama、alpaca、vicuna的前世今生6. 对话Vicuna&#xff08;1&#xff09;llama-2-7b-hf&#xff08;2&#xff09;vicuna-7b-delta-v0&#xff08;3&#xff09;vicuna-7b-v0&#xff08;4&#x…

web路径问题和会话技术(Cookie和Session)

一.Base 1.base介绍①base是HTMl语言的基准网址标签,是一个单标签,位于网页头部文件的head标签内②一个页面最多使用一个base元素,用来提供一个指定的默认目标,是一种表达路径和连接网址的标记③常见的url路径分别有相对路径和绝对路径,如果base标签指定了目标,浏览器将通过这个…

C++17 新特性解析:Lambda 捕获 this

C17 引入了许多改进和新特性&#xff0c;其中之一是对 lambda 表达式的增强。在这篇文章中&#xff0c;我们将深入探讨 lambda 表达式中的一个特别有用的新特性&#xff1a;通过 *this 捕获当前对象的副本。这个特性不仅提高了代码的安全性&#xff0c;还极大地简化了某些场景下…

2025.1.20——二、buuctf BUU UPLOAD COURSE 1 1 文件上传

题目来源&#xff1a;buuctf BUU UPLOAD COURSE 1 1 一、打开靶机&#xff0c;查看信息 这里提示到了文件会被上传到./uploads&#xff0c;有路径&#xff0c;题目也说了upload&#xff0c;所以是文件上传漏洞。好简洁的题目&#xff0c;做过十七关upload-labs的我&#xff0c…

python学opencv|读取图像(四十二)使用cv2.add()函数实现多图像叠加

【1】引言 前序学习过程中&#xff0c;掌握了灰度图像和彩色图像的掩模操作&#xff1a; python学opencv|读取图像&#xff08;九&#xff09;用numpy创建黑白相间灰度图_numpy生成全黑图片-CSDN博客 python学opencv|读取图像&#xff08;四十&#xff09;掩模&#xff1a;三…

springBoot 整合ModBus TCP

ModBus是什么&#xff1a; ModBus是一种串行通信协议&#xff0c;主要用于从仪器和控制设备传输信号到主控制器或数据采集系统&#xff0c;例如用于测量温度和湿度并将结果传输到计算机的系统。&#xff08;百度答案&#xff09; ModBus 有些什么东西&#xff1a; ModBus其分…

数据结构——实验二·栈

海~~欢迎来到Tubishu的博客&#x1f338;如果你也是一名在校大学生&#xff0c;正在寻找各种变成资源&#xff0c;那么你就来对地方啦&#x1f31f; Tubishu是一名计算机本科生&#xff0c;会不定期整理和分享学习中的优质资源&#xff0c;希望能为你的编程之路添砖加瓦⭐&…

【IEEE Fellow 主讲报告| EI检索稳定】第五届机器学习与智能系统工程国际学术会议(MLISE 2025)

重要信息 会议时间地点&#xff1a;2025年6月13-15日 中国深圳 会议官网&#xff1a;http://mlise.org EI Compendex/Scopus稳定检索 会议简介 第五届机器学习与智能系统工程国际学术会议将于6月13-15日在中国深圳隆重召开。本次会议旨在搭建一个顶尖的学术交流平台&#xf…

一文详解Filter类源码和应用

背景 在日常开发中&#xff0c;经常会有需要统一对请求做一些处理&#xff0c;常见的比如记录日志、权限安全控制、响应处理等。此时&#xff0c;ServletApi中的Filter类&#xff0c;就可以很方便的实现上述效果。 Filter类 是一个接口&#xff0c;属于 Java Servlet API 的一部…

开发环境搭建-1:配置 WSL (类 centos 的 oracle linux 官方镜像)

一些 Linux 基本概念 个人理解&#xff0c;并且为了便于理解&#xff0c;可能会存在一些问题&#xff0c;如果有根本上的错误希望大家及时指出 发行版 WSL 的系统是基于特定发行版的特定版本的 Linux 发行版 有固定组织维护的、开箱就能用的 Linux 发行版由固定的团队、社区…

llama-2-7b权重文件转hf格式及模型使用

目录 1. obtain llama weights 2. convert llama weights files into hf format 3. use llama2 to generate text 1. obtain llama weights &#xff08;1&#xff09;登录huggingface官网&#xff0c;搜索llama-2-7b &#xff08;2&#xff09;填写申请表单&#xff0c;VP…

ElasticSearch(十一)— Elasticsearch中的SQL语句

一、总概 Elasticsearch 在 Basic 授权中支持以 SQL 语句的形式检索文档&#xff0c;SQL 语句在执行时会被翻译为 DSL 执行。从语法的角度来看&#xff0c;Elastisearch 中的 SQL 语句与RDBMS 中的 SQL 语句基本一致&#xff0c; 所以对于有数据库编程基础的人来说大大降低了使…

吴恩达深度学习——如何实现神经网络

来自吴恩达深度学习&#xff0c;仅为本人学习所用。 文章目录 神经网络的表示计算神经网络的输出激活函数tanh选择激活函数为什么需要非激活函数双层神经网络的梯度下降法 随机初始化 神经网络的表示 对于简单的Logistic回归&#xff0c;使用如下的计算图。 如果是多个神经元…

爬取NBA球员信息并可视化小白入门

网址:虎扑体育-NBA球员得分数据排行 第1页 步骤: 分析页面 确定URL地址模拟浏览器向服务器发送请求数据解析 提取想要的数据保存数据 爬虫所需要的模块 requests(发送HTTP请求)parsel(解析HTML内容)pandas(数据保存模块) 第一步分析页面 --确定是静态页面还是动态页面 右击点…

C语言初阶牛客网刷题——JZ17 打印从1到最大的n位数【难度:入门】

1.题目描述 牛客网OJ题链接 题目描述&#xff1a; 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 用返回一个整数列表来代替打印n 为正整数&#xff0c;0 < n < 5 示例1 输入&…

寒假刷题记录

4968. 互质数的个数 - AcWing题库 涉及&#xff1a;快速幂&#xff0c;欧拉函数&#xff0c;分解质因数 #include <bits/stdc.h> #define fi first #define se second #define endl \n #define pb push_backusing namespace std; using LL long long;const int mod 9…