Giter VIP home page Giter VIP logo

fastkv's Introduction

FastKV

Maven Central | English

1. 概述

FastKV是用Java编写的高效可靠的key-value存储库。

FastKV有以下特点:

  1. 读写速度快
    • 二进制编码,编码后的体积相对XML等文本编码要小很多;
    • 增量编码:FastKV记录了各个key-value相对文件的偏移量, 从而在更新数据时可以直接在指定的位置写入数据。
    • 默认用mmap的方式记录数据,更新数据时直接写入到内存即可,没有IO阻塞。
    • 对超大字符串和大数组做特殊处理,另起文件写入,不影响主文件的加载和更新。
  2. 支持多种写入模式
    • 除了mmap这种非阻塞的写入方式,FastKV也支持常规的阻塞式写入方式, 并且支持同步阻塞和异步阻塞(分别类似于SharePreferences的commit和apply)。
  3. 支持多种类型
    • 支持常用的boolean/int/float/long/double/String等基础类型。
    • 支持ByteArray (byte[])。
    • 支持存储自定义对象。
    • 内置Set的编码器 (兼容SharePreferences)。
  4. 支持数据加密
    • 支持注入加密解密的实现,在数据写入磁盘之前执行加密。
    • 解密处理发生在数据解析阶段,解析完成后,数据是缓存的(用HashMap缓存),
      所以加解密会稍微增加写入(put)和解析(loading)的时间,不会增加索引数据(get)的时间。
  5. 支持多进程
    • 项目提供了支持多进程的存储类(MPFastKV)。
    • 支持监听文件内容变化,其中一个进程修改文件,所有进程皆可感知。
  6. 方便易用
    • FastKV提供了了丰富的API接口,开箱即用。
    • 提供的接口其中包括getAll()和putAll()方法, 所以很方便迁移SharePreferences等框架的数据到FastKV, 当然,迁移FastKV的数据到其他框架也很简单。
  7. 稳定可靠
    • 通过double-write等方法确保数据的完整性。
    • 在API抛IO异常时自动降级处理。
  8. 代码精简
    • FastKV由纯Java实现,编译成jar包后体积只有数十K。

2. 使用方法

2.1 导入

dependencies {
    implementation 'io.github.billywei01:fastkv:2.4.3'
}

2.2 初始化

    FastKVConfig.setLogger(FastKVLogger)
    FastKVConfig.setExecutor(Dispatchers.Default.asExecutor())

初始化可以按需设置日志接口和Executor。

2.3 基本用法

    // FastKV kv = new FastKV.Builder(context, name).build();
    FastKV kv = new FastKV.Builder(path, name).build();

    if(!kv.getBoolean("flag")){
        kv.putBoolean("flag" , true);
    }
    
    int count = kv.getInt("count");
    if(count < 10){
        kv.putInt("count" , count + 1);
    }

Builder的构造可传Context或者path。
如果传Context的话,会在内部目录的'files'目录下创建'fastkv'目录来作为文件的保存路径。

2.4 存储自定义对象

    FastEncoder<?>[] encoders = new FastEncoder[]{LongListEncoder.INSTANCE};
    FastKV kv = new FastKV.Builder(context, name).encoder(encoders).build();
        
    List<Long> list = new ArrayList<>();
    list.add(100L);
    list.add(200L);
    list.add(300L);
    kv.putObject("long_list", list, LongListEncoder.INSTANCE);
    
    List<Long> list2 = kv.getObject("long_list");

除了支持基本类型外,FastKV还支持写入对象。
如果要写入自定义对象,需在构建FastKV实例时传入对象的编码器(实现了FastEncoder接口的对象)。
因为FastKV实例加载时会执行自动反序列化,所以需要在实例创建时注入编码器。
另外,如果没有注入编码器,调用putObject接口时会抛出异常(提醒使用者给FastKV实例传入编码器)。

上面LongListEncoder就实现了FastEncoder接口,代码实现可参考: LongListEncoder

编码对象涉及序列化/反序列化。
这里推荐笔者的另外一个框架:https://github.com/BillyWei01/Packable

2.5 数据加密

如需对数据进行加密,在创建FastKV实例时传入 FastCipher 的实现即可。

FastKV kv = FastKV.Builder(path, name)
         .cipher(yourCihper)
         .build()

项目中有举例Cipher的实现,可参考:AESCipher

2.6 迁移 SharePreferences 到 FastKV

FastKV实现了SharedPreferences接口,并且提供了迁移SP数据的方法。
用法如下:

public class SpCase {
   public static final String NAME = "common_store";
   // 原本的获取SP的方法
   // public static final SharedPreferences preferences = AppContext.INSTANCE.getContext().getSharedPreferences(NAME, Context.MODE_PRIVATE);
   
   // 导入原SP数据
   public static final SharedPreferences preferences = FastKV.adapt(AppContext.INSTANCE.getContext(), NAME);
}

2.7 迁移 MMKV 到 FastKV

由于MMKV没有实现 'getAll' 接口,所以无法像SharePreferences一样一次性迁移。
但是可以封装一个KV类,创建 'getInt','getString' ... 等方法,并在其中做适配处理。 可参考:MMKV2FastKV

2.8 多进程

项目提供了支持多进程的实现:MPFastKV
MPFastKV除了支持多进程读写之外,还实现了SharedPreferences的接口,包括支持注册OnSharedPreferenceChangeListener;
其中一个进程修改了数据,所有的进程都会感知(通过OnSharedPreferenceChangeListener回调)。
可参考 MultiProcessTestActivityTestService

需要提醒的是,由于支持多进程需要维护更多的状态,MPFastKV 的写入要比FastKV慢不少, 所以在不需要多进程访问的情况下,尽量用 FastKV。

2.9 Kotlin 委托

Kotlin是兼容Java的,所以Kotlin下也可以直接用FastKV或者SharedPreferences的API。
此外,Kotlin还提供了“委托属性”这一语法糖,可以用于改进key-value API访问。
可参考:KVData

2.10 注意事项

  1. 不同版本之间,不要改变路径和名字,否则会打开不同的文件。
  2. 如果使用了Cipher(加密),不要更换,否则会打开文件时会解析不了。 不过从没有使用Cipher到使用Cipher是可以的,FastKV会先解析未加密的数据,然后在重新加密写入
  3. 同一个key, 对应的value的操作应保持类型一致。 比如,同一个key, A处putString, B处getInt, 则无法返回预期的value。

3. 性能测试

  • 测试数据:搜集APP中的SharePreferences汇总的部份key-value数据(经过随机混淆)得到总共六百多个key-value。
    分别截取其中一部分,构造正态分布的输入序列,进行多次测试。
  • 测试机型:华为P30 Pro
  • 测试代码:Benchmark

测试结果如下:

更新:

25 50 100 200 400 600
SP-commit 114 172 411 666 2556 5344
DataStore 231 625 1717 4421 7629 13639
SQLiteKV 192 382 1025 1565 4279 5034
SP-apply 3 9 35 118 344 516
MMKV 4 8 5 8 10 9
FastKV 3 6 4 6 8 10

查询:

25 50 100 200 400 600
SP-commit 1 3 2 1 2 3
DataStore 57 76 115 117 170 216
SQLiteKV 96 161 265 417 767 1038
SP-apply 0 1 0 1 3 3
MMKV 0 1 1 5 8 11
FastKV 0 1 1 3 3 1

每次执行Benchmark获取到的结果有所浮动,尤其是APP启动后执行多次,部分KV会变快(JIT优化)。
以上数据是取APP冷启动后第一次Benchmark的数据。

4. 参考链接

相关博客:
https://juejin.cn/post/7018522454171582500

由于提供给Android平台的版本和纯JDK的版本的差异越来越多,所以分开仓库来维护。
纯JDK版本的链接为:
https://github.com/BillyWei01/FastKV-Java

License

See the LICENSE file for license rights and limitations.

fastkv's People

Contributors

billywei01 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fastkv's Issues

架构兼容疑问

请问该库是否和MMKV一样,兼容armeabi架构需要另外编译 ?

putString没用

保存不下来,重启app就丢失了,是path填错了?

咨询下项目的情况

麻烦问下这个工具有在线上验证过么?比如大量用户、大量机型、大量业务逻辑的状态下。

多谢~~~

提一个必现的ANR case

class ChannelExecutor(capacity: Int) : Executor {
    private val channel = Channel<Any>(capacity)

    override fun execute(command: Runnable) {
        channel.runBlock {
            command.run()
        }
    }
}

private val UnconfinedCoroutineScope = CoroutineScope(Dispatchers.Unconfined)

private val IOCoroutineScope = CoroutineScope(Dispatchers.IO)

fun Channel<Any>.runBlock(block: suspend CoroutineScope.() -> Unit) {
    UnconfinedCoroutineScope.launch {
        send(0)
        IOCoroutineScope.launch {
            block()
            receive()
        }
    }
}
fun main() {
    FastKVConfig.setExecutor(ChannelExecutor(4))
    CoroutineScope(Dispatchers.Main.immediate).launch { 
        val faskKV = FastKV.Builder(appContext.cacheDir, "test").build()
        // 这里就不会执行了
        println("")
    }
}

如何查看本地缓存文件内容?

本地缓存文件一个比较大的需求就是,直接查看文件内容。

使用什么文件查看打开kva、kvb文件比较好呢?使用txt会有很多NULL字符

提议:过期失效时间

请问会不会考虑把过期失效策略的相关功能做进来呢,感觉实际工作中还是挺常用的。

mmkv如何快速迁移到fastkv

目前项目遇到数据丢失的问题,key很多不好管理,key分类后一个一个的调用encode来迁移也很麻烦

说一个小小的缺点

最近自己写的项目准备引入这个库来替换sp,但是遇到了两个问题
1个问题是Gson转换导致的,可参考issue
#16
第二个问题是,假设你一开始用
fastkv.putInt("testKey",1).
但是后面的业务你准备把testKey对应的value设置为String
fastKv.putString("test","1234")
这个时候就会直接报错了。虽然业务上大概率不会这么做,我是在测试时发现了这个问题

然而sp和mmkv是没有这个缺陷的。

主要是因为框架把key和container做了一层映射关系,这种关系是强绑定的,导致后面key的value不能做任何类型的变更,一旦出现这个问题,就会应用崩溃,只有卸载重装或者重新发包覆盖才可解决。

这两个问题从本质上来说,属于同一个问题

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.