1.0.0 • Published 3 years ago

react-native-filebase v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

react-native-filebase

类似于nosql数据库,依赖于react-native-fs开发的一款本地数据库。

开发数据库的目的

为了帮助那些想要存储大量数据却找不到合适的数据库的人快速上手。

曾经在我的项目中就遇到了这个问题,我开发的是一款写日记的app,为了让用户体验更好的编辑效果,我采用了富文本的形式实现图文混合编辑,最终生成的数据是html。

那时候我选择react-native-storage存储用户的日记,但是在测试过程中,只存储了两张base64格式的图片就提示磁盘空间不足。

后来我换成了一个sqlite数据库react-native-sqlite-storage。这款数据库并没有详细的文档解释api,只是放了几个例子,而且存储字符串极其困难,存储html还需要自己手动去转义html中的“/>”和标签属性的双引号等等,对于web前端程序员来说,学习sql语句才是最麻烦的事情。

出于这些原因,我决定自己去实现一款本地数据库,一切从简单出发,快速的上手。

安装

npm i react-native-filebase

你也可以选择yarn安装

yarn add react-native-filebase

配置

前面说了,这款本地数据库依赖react-native-fs 所以只需要配置它就行了。

本包的开发环境是react-native :"0.64.2",react: "17.0.1", "react-native-fs": "^2.18.0"

如果你的rn环境小于0.61,可能会不支持,需要安装@2.13.2!版本的fs模块,具体的配置可以去他的GitHub上面找到配置方法。

然后再修改本模块的packge.json文件的依赖就可以了,其实核心代码不过一百行。

android

第一步

打开android/settings.gradle 文件,添加下面两句

include ':react-native-fs'

project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')

第二步

打开android/app/build.gradle 文件,添加:

dependencies {
    ...
    implementation project(':react-native-fs')		//添加这句
}

第三步

因为需要读写文件,所以需要添加读写的权限。找到AndroidManifest.xml文件,在android/app/src/main目录下。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.diaryapp">
	...
    添加下面两句
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

注意事项

因为fs模块在Android10以及以上的版本,或者targetSdkVersion>=29的版本存在权限问题,经过我在issues上面寻找,找到了解决问题。

需要在AndroidManifest.xml文件中添加下面这句

<application
      ....
      添加这句
      android:requestLegacyExternalStorage="true"

在fs的GitHub的issues中,听说如果targetSdkVersion = 30,compileSdkVersion = 30。你可能还需要添加

<application 
      ...
      添加这句
      android:preserveLegacyExternalStorage="true"

但是我添加了之后编译会报错,可能我的sdk版本不是30。

如果有任何问题,可以向我提问。

使用

首先我们要明白几个概念,nosql数据库是没有表的概念,只有文档和集合的概念,你可以理解为文档就是一个数组,集合就是一个对象,文档中存放集合。或者你也可以把文档理解为sql数据库的表,集合理解为列。此数据库不必手动的创建,id值也不必传入,如果传入将被覆盖,一切从简单出发。

注意: 因为内部使用任务队列,所有的操作都是异步的,但是却不能通过.then拿着值,只能通过回调函数拿到值,你也可以用Promise的形式进行封装。

import DataBase from 'react-native-filebase'

const DB = new DataBase()

DB.openDataBase('dbName')
	.then(()=>{
    	console.log('数据库打开成功')
	})
	.catch(()=>{
    	console.log('数据库打开失败')
	})

//数据库所有的操作都是基于数据库打开之后,如果数据库没有打开,后续的操作会被加入任务队列,等到数据库打开后会自动执行任务队列。
//所以不必担心要等数据库打开才能操作数据库

增加数据

DB.create({name:'法外狂徒张三', age: 17}, (success)=>{}, (error)=>{})

DB.createMulti([{name:'法外狂徒张三', age: 17},{name:'守法好公民李四', age: 20}],  (success)=>{}, (error)=>{})

删除数据

DB.deleteDataById(123321123456, (success)=>{}, (error)=>{})

DB.deleteDataByKey({age: 17}, (success)=>{}, (error)=>{})

修改数据

DB.updateDataById(123321123456, {age: 20},(Object)=>{}, (error)=>{})

DB.updateDataByKey({name:'法外狂徒张三'}, {age:22}, (Array)=>{}, (error)=>{})

查找数据

DB.findAllData((arr)=>{}, (error)=>{})

DB.findDataById(123321123456, (Object)=>{}, (error)=>{})

DB.findDataByKey({name:'法外狂徒张三'}, (arr)=>{}, (error)=>{})

API

create(data: Object, success: Function, error: Function) : Promise <String>

存储的数据必须是一个对象,如果不是对象将会报错,传数组也不行。id值会自动加上,请不要加id值,会被覆盖。

createMulti(data: Array, success: Function, error: Function): Promise <String>

必须传入数组, 数组中必须是对象,例如:[ {a: 1,2,3}, {a: 'haha'} ],否则报错,例如:1,1

deleteDataById(id: Number, success: Function, error: Function): Promise <Void>

删除id对应的数据,id是唯一的,所以只会删除一条

deleteDataByKey(condition: Object, success: Function, error: Function): Promise <String>

删除多条数据,condition是指要删除哪些数据,只能传一个对象,比如删除所有age是18的人:{age:18}

updateDataById(id: Number, success: Function, error: Function): Promise<String>

通过id更新一条数据

updateDataByKey(condition: Object, success: Function, error: Function): Promise<String>

通过key更新多条数据,传入的condition和data必须是对象,否则报错

findAllData(success: Function, error: Function): Promise<String>

查询所有数据

findDataById(id: Number, success: Function, error: Function): Promise<String>

通过id查询一条数据

findDataByKey(condition: Object, success: Function, error: Function): Promise<String>

condition必须是对象,否则报错

最后的话

代码放这了,想添加功能的自己去添加

const RNFS = require('react-native-fs')
import {
  PermissionsAndroid
} from 'react-native'

const RootPath = RNFS.DocumentDirectoryPath

//数据库的所有分片
const COLLECT = Symbol('collect')

//当前操作的分片
const CURREN_COLLECT = Symbol('curren_collect')

//数据库的名称
const DBNAME = Symbol('dbName')

//数据库打开的状态
const STATUS = Symbol('status')
let _status = false

//任务队列,当数据库还没有打开的时候,把任务都放进队列,然后依次执行
const QUEUE = Symbol('queue')

//任务队列的执行状态,是否在执行任务队列
const QUEUE_STATUS = Symbol('queue_status')

//当前是否有任务在进行。如果有任务正在进行,则把当前任务放进任务队列依次执行
const HANDING = Symbol('handing')
let _handing = false

export default class DataDB {

  constructor() {
    initData.call(this)
  }


//打开数据库
  async openDataBase(db){
    //设置当前数据库名字
    this[DBNAME] = db

    try {
      //检查权限
      let judge = await getPermissions()
      if(!judge){
        return Promise.reject('用户拒绝授权')
      }

      let dbPath = `${RootPath}/${db}`

      //查看数据库是否存在
      let exists = await RNFS.exists(dbPath)

      // 数据库不存在则创建,设置当前操作的分片
      if(!exists){
        await RNFS.mkdir(dbPath)
        this[CURREN_COLLECT] = `${dbPath}/${Date.now()}.db`
      }

      // 获取所有分片
      let collect = await getCollect.call(this, dbPath)
      

      // 更新当前数据库为打开状态
      this[STATUS] = true

      return Promise.resolve(true)

    }catch (err){
      return Promise.reject(err)
    }

  }

  //插入一条数据
  async create(data, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_create.bind(this, data, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行或者任务队列正在执行,则把本次任务放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_create.bind(this, data, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _create.call(this, data, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  // 插入多条数据
  async createMulti(data, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_createMulti.bind(this, data, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行,或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_createMulti.bind(this, data, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _createMulti.call(this, data, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  //查询全部数据
  async findAllData(success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_findAllData.bind(this, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_findAllData.bind(this, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _findAllData.call(this, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  //通过id查询一条数据
  async findDataById(id,success,error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_findDataById.bind(this, id, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_findDataById.bind(this, id, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _findDataById.call(this, id, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  // 通过key查询多条数据
  async findDataByKey(condition, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_findDataByKey.bind(this, condition, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_findDataByKey.bind(this, condition, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _findDataByKey.call(this, condition, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  //通过id删除一条数据
  async deleteDataById(id, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_deleteDataById.bind(this, id, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_deleteDataById.bind(this, id, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _deleteDataById.call(this, id, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }

  }


  //通过key删除多条数据
  async deleteDataByKey(condition, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_deleteDataByKey.bind(this, condition, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行,或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_deleteDataByKey.bind(this, condition, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _deleteDataByKey.call(this, condition, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  // 通过id改一条数据
  async updateDataById(id, updateData, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_updateDataById.bind(this, id, updateData, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行,或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_updateDataById.bind(this, id, updateData, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _updateDataById.call(this, id, updateData, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }

  //通过key修改多条数据
  async updateDataByKey(condition, updateData, success, error){
    try {
      //检查当前数据库是否打开,如果没有打开,则放进任务队列
      let status = this[STATUS]
      if(!status){
        this[QUEUE].push(_updateDataByKey.bind(this, condition, updateData, success, error))
        return Promise.resolve('pending')
      }

      // 如果当前有任务在执行,或者任务队列正在执行,则放入任务队列
      if(this[HANDING] || this[QUEUE_STATUS]){
        this[QUEUE].push(_updateDataByKey.bind(this, condition, updateData, success, error))
        return Promise.resolve('pending')
      }

      // 当前没有任务队列在执行,修改状态有任务在执行
      this[HANDING] = true

      await _updateDataByKey.call(this, condition, updateData, success, error)
      // 任务执行完修改状态没有任务在执行
      this[HANDING] = false

      return Promise.resolve('done')

    } catch (err){
      return Promise.reject(err)
    }
  }


}



//通过key修改多条数据
async function _updateDataByKey(condition, updateData, success, error){
  try {
    //检查查询条件是否是对象,如果不是对象或者是数组就返回[]
    if(!(condition instanceof Object) || Array.isArray(condition)){
      return success && success(null)
    }

    //获取查询条件的key
    let key = Object.keys(condition)
    //如果查询条件是空对象,返回[]
    if(key.length === 0){
      return success && success([])
    }

    // 检查修改的对象是否对象,基本数据类型和数组都报错
    if (!(updateData instanceof Object) || Array.isArray(updateData)){
      return error && error('修改数据必须是对象')
    }

    //存放被修改之前的数据
    let updateArr = []

    for (let path of this[COLLECT]){
      let data = await RNFS.readFile(path)
      data = data.slice(0, -1)
      data = JSON.parse(`[${data}]`)
      //用于判断是否修改了当前分片的数据
      let judge = false

      data = data.map(item => {
        // 筛选符合条件的数据
        let assert = key.every(k => {
          return item[k] === condition[k]
        })
        if (assert){
          judge = true
          updateArr.push(item)
          item = {...item, ...updateData}
        }
        return item
      })

      if (judge){
        let jsonData = JSON.stringify(data)
        jsonData = jsonData.slice(1, -1) + ','
        await RNFS.unlink(path)
        await RNFS.writeFile(path, jsonData)
      }

    }

    return success && success(updateArr)

  } catch (err){
    return error && error(err)
  }
}



// 通过id改一条数据
async function _updateDataById(id, updateData, success, error){
  id = Number(id)
  //检查id值是不是数值
  if(Number.isNaN(id)){
    return error && error('传入的id值不符合规范')
  }

  // 检查更改的数据是不是对象,基本数据类型和数组都报错
  if(!(updateData instanceof Object) || Array.isArray(updateData)){
    return error && error('传入的值不是对象')
  }

  // 禁止更改id值
  if(updateData.id){
    Reflect.deleteProperty(updateData, 'id')
  }

  try{

    for (let path of this[COLLECT]) {
      let data = await RNFS.readFile(path)
      data = data.slice(0, -1)
      data = JSON.parse(`[${data}]`)

      let index = data.findIndex(item => item.id === id)
      if(index > -1){
        data[index] = {...data[index], ...updateData}
        let jsonData = JSON.stringify(data)
        jsonData = jsonData.slice(1, -1) + ','
        await RNFS.unlink(path)
        await RNFS.writeFile(path, jsonData)
        return success && success(data[index])
      }

    }

    return success && success(null)

  } catch (err){
    return error && error(err)
  }
}


// 通过key删除多条数据
async function _deleteDataByKey(condition, success, error){

  //检查数据类型,不是对象报错,是数组报错
  if(!(condition instanceof Object) || Array.isArray(condition)){
    return error && error('传入的值不符合规定')
  }

  // 获取条件对象的key值
  let key = Object.keys(condition)
  //条件key为空,返回null
  if(key.length === 0){
    return success && success(null)
  }

  try{
    //存放被删除的数据
    let delData = []

    for (let path of this[COLLECT]){
      let data = await RNFS.readFile(path)
      //去掉最后的逗号
      data = data.slice(0, -1)
      //序列化数组
      data = JSON.parse(`[${data}]`)

      //保存数据被修改之前的长度
      let length = data.length

      console.warn('保存数据被修改之前的长度', data.length)

      for (let i = 0; i < data.length; i++) {
        let item = data[i]
        let judge = key.every(k => {
          return item[k] === condition[k]
        })
        if(judge){
          delData.push(item)
          data.splice(i, 1)
          i--
        }
      }

      //如果删除后,分片的内容为空,就删除分片
      if(data.length === 0){
        console.log('如果删除后,分片的内容为空,就删除分片')
        await RNFS.unlink(path)
      } else if(length > data.length){
        //如果数据被修改了,就重新写入当前分片
        console.log('如果数据被修改了,就重新写入当前分片')
        await RNFS.unlink(path)
        let JSONData = JSON.stringify(data)
        JSONData = JSONData.slice(1, -1) + ','
        await RNFS.writeFile(path, JSONData)
      }

    }

    return success && success(delData)

  }catch (err){
    error &&  error(err)
  }


}


//通过id删除一条数据
async function _deleteDataById(id, success, error){

  id = Number(id)
  //检查id值是不是数值
  if(Number.isNaN(id)){
    return error && error('输入的id值不符合规范')
  }

  try {

    for (let i =0;i< this[COLLECT].length; i++){
      let data = await RNFS.readFile(this[COLLECT][i])
      //去掉最后的逗号
      data = data.slice(0, -1)

      //序列化数组
      data = JSON.parse(`[${data}]`)

      for (let j = 0; j < data.length;j++) {
        let item = data[j]
        if(item.id !== id){
         continue
        }
        data.splice(j, 1)
        //检查删除之后的数据长度是否为0,如果为0就删除分片
        if(data.length === 0) {
          await RNFS.unlink(this[COLLECT][i])
          // this[COLLECT].splice(i, 1)
          return success && success(item)
        }
        //删除当前分片,因为fs模块无法覆盖的bug
        await RNFS.unlink(this[COLLECT][i])
        data = JSON.stringify(data)
        data = data.slice(1, -1) + ','
        //重新写入分片
        await RNFS.writeFile(this[COLLECT][i], data)
        return success && success(item)
      }

    }

    //没有查询到要删除的数据
    return success && success(null)

  } catch (err){
    error && error(err)
  }


}



//通过key查询多条数据
async function _findDataByKey(condition, success, error){

  try {
    //检查查询条件是否是对象,如果不是对象或者是数组就返回[]
    if(!(condition instanceof Object) || Array.isArray(condition)){
      return success && success([])
    }

    //获取查询条件的key
    let key = Object.keys(condition)
    //如果查询条件是空对象,返回[]
    if(key.length === 0){
      return success && success([])
    }

    //存放查找的数据
    let allData = []

    for (let path of this[COLLECT]) {
      let data = await RNFS.readFile(path)
      //去掉最后的逗号
      data = data.slice(0, -1)

      //序列化数组
      data = JSON.parse(`[${data}]`)

      data.forEach(item => {
        if(key.every(k => item[k] === condition[k])){
          allData.push(item)
        }
      })
    }

    return success && success(allData)

  } catch (err){
    error && error(err)
  }

}



//通过id查询一条数据
async function _findDataById(id, success,error){

  try {

    for (let path of this[COLLECT]) {
      let data = await RNFS.readFile(path)
      //去掉最后的逗号
      data = data.slice(0, -1)

      //序列化数组
      data = JSON.parse(`[${data}]`)

      //查找数据
      let result = data.find(item => {
        return item.id === id
      })
      // 如果找到就返回
      if(result){
        return success && success(result)
      }
    }


    //如果没有找到就返回null
    return success && success(null)

  } catch (err){
    error && error(err)
  }

}


// 查询全部数据
async function _findAllData(success, error){
  try {
    //创建空数组,用于存放所有分片数据
    let allData = []
    console.log(this[COLLECT])
    for (let path of this[COLLECT]) {
      //检查当前分片是否存在
      let exists = await RNFS.exists(path)
      if(!exists){
        continue
      }

      let data = await RNFS.readFile(path)
      //去掉最后的逗号
      data = data.slice(0, -1)
      //序列号数组
      data = JSON.parse(`[${data}]`)
      allData.push(...data)
    }
    // console.log('全部数据', allData)
    return success && success(allData)

  } catch (err){
    return error && error(err)
  }
}



// 创建多条数据
async function _createMulti(data, success, error){

  //检查传入的数据是否是数组,如果不是数组则抛出错误
  if(!Array.isArray(data)){
    return error && error(new Error('传入的值不是一个数组'))
  }

  // 检查是否是空数组
  if(data.length === 0){
    return success && success(data)
  }

  // 检查数组中的元素是否是数组或者是基本数据类型
  let isObj = data.every(item => {
    if(Array.isArray(item)){
      return false
    }
    return item instanceof Object
  })

  if(!isObj){
    return error && error(new Error('数组中只能包含对象'))
  }

  //循环为数据添加唯一id
  data.forEach(item => {
    item.id = Date.now() + Number.parseInt(Math.random(1)*1000)
  })


  try {
    // 设置当前分片地址
    await getCollectStats.call(this)

    //把数据转成json然后在尾部加一个逗号用来parse
    let JSONdata = JSON.stringify(data)
    // 去除数组的方括号再加一个逗号
    JSONdata = JSONdata.slice(1, -1) + ','

    //把数据写入最后
    await RNFS.write(this[CURREN_COLLECT], JSONdata, -1)

    // 调用成功回调
    return success && success(data)

  } catch (err){
    return error && error(new Error(err))
  }

}


//创建一条数据
async function _create (data, success, error){

  try {

    //检查传入的数据是否是对象,如果是数组或者是基本数据类型则抛出错误
    if(!(data instanceof Object) || Array.isArray(data)){
      return error && error(new Error('传入的值不是一个对象'))
    }

    //如果是空对象,直接返回
    if(Object.keys(data).length === 0){
      return success && success(data)
    }

    //为数据创建唯一id
    data.id = Date.now() + Number.parseInt(Math.random(1)*1000)

    // 设置当前分片地址
    await getCollectStats.call(this)

    //把数据转成json然后在尾部加一个逗号用来parse
    let JSONdata = JSON.stringify(data) + ','

    //把数据写入分片最后
    await RNFS.write(this[CURREN_COLLECT], JSONdata, -1)

    // 调用成功回调
    return success && success(data)

  } catch (err){
    return error && error(new Error(err))
  }

}


//获取每个分片的信息,根据分片大小是否创建新的分片,并且设置当前分片的地址,(如果分片大于1kb就会新建分片)
async function getCollectStats(){

  try {
    //限制大小为1kb
    const limit = 1024 ** 2

    //获取所有的分片
    const collect = this[COLLECT]

    // 检查分片中可以存数据的分片
    for (let path of collect){
      let exists = await RNFS.exists(path)
      //如果分片不存在,则设置当前分片为不存在的分片
      if (!exists){
        this[CURREN_COLLECT] = path
        return Promise.resolve(this[CURREN_COLLECT])
      }
      //如果分片存在,检查是否超出限制,没有超出限制就设置为当前的分片
      let stat = await RNFS.stat(path)
      if (stat.size < limit){
        this[CURREN_COLLECT] = path
        return Promise.resolve(this[CURREN_COLLECT])
      }
    }

    //如果超出限制或者没有分片,新建一个分片,并且更新
    let collectPath = `${RootPath}/${this[DBNAME]}/${Date.now()}.db`

    // 添加新建分片到所有分片
    this[COLLECT].push(collectPath)
    //设置当前操作的分片为新建的分片
    this[CURREN_COLLECT] = collectPath
    return Promise.resolve(this[CURREN_COLLECT])

  }catch (err){
    return Promise.reject(err)
  }

}

// 获取所有分片
async function getCollect(dir){
  try {
    //读取数据库,获取所有文档
    let files = await RNFS.readDir(dir)
    let collectPath = []

    // 把文档路径放入数组
    files.forEach(item => {
      collectPath.push(item.path)
    })
    // 把数据放进实例
    this[COLLECT] = collectPath
    return Promise.resolve(collectPath)

  }catch (err){
    return Promise.reject(err)
  }
}


function initData(){
  Object.defineProperties(this, {
    [COLLECT]:{
      value: [],
      configurable: false,
      writable: true,
      enumerable: false
    },
    [DBNAME]:{
      value: '',
      configurable: false,
      writable: true,
      enumerable: false
    },
    [STATUS]: {
      get: function (){
        return _status
      },
      set: async function (value){
        // 修改为false说明数据库没有打开,不执行任务队列
        if(!value){
          return _status = value
        }

        _status = value
        // 修改为true,说明数据库打开了,依次执行任务队列的任务

        //遍历执行任务
        for (let task of this[QUEUE]){
          await task()
        }
        //清空任务队列
        this[QUEUE] = []
        return _status

      },
      configurable: false,
      enumerable: false
    },
    [QUEUE]: {
      value: [],
      configurable: false,
      writable: true,
      enumerable: false
    },
    [QUEUE_STATUS]: {
      value: false,
      configurable: false,
      writable: true,
      enumerable: false
    },
    [HANDING]: {
      get: function (){
        return _handing
      },
      set: async function (value){
        // 如果修改为true,说明有任务正在执行,任务队列不执行
        _handing = value
        if(value){
          return _handing
        }

        //更新任务队列执行状态,正在执行任务
        this[QUEUE_STATUS] = true

        // 如果修改为false,说明当前主线程空闲,依次执行任务队列里面的任务

        for (let task of this[QUEUE]) {
          await task()
        }
        // 清空任务队列
        this[QUEUE] = []

        //更新任务队列执行状态,执行任务执行完毕
        this[QUEUE_STATUS] = false

        return _handing

      },
      configurable: false,
      enumerable: false
    },
    [CURREN_COLLECT]:{
      value: '',
      configurable: false,
      writable: true,
      enumerable: false
    }
  })
}

async function getPermissions(){

  let permissions = []

  if(!(await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE))){
    permissions.push(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE)
  }

  if( !(await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)) ){
    permissions.push(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)
  }

  // 如果权限都有则返回true
  if(permissions.length === 0){
    return Promise.resolve(true)
  }

  let result = await PermissionsAndroid.requestMultiple(permissions)
  let key = Object.keys(result)

  let judge = key.every(k => {
    return result[k]
  })

  return Promise.resolve(judge)

}