基于IndexedDB实现简单文件系统

现在的indexedDB已经有几个成熟的库了,比如西面这几个,任何一个都是非常出色的。 用别人的东西好处是上手快,看文档就好,要是文档不太好,那就有点尴尬了。

dexie.js :A Minimalistic Wrapper for IndexedDB

zangodb:MongoDB-like interface for HTML5 IndexedDB

localForage:Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful AP

idb.filesystem.js: HTML5 Filesystem API polyfill using IndexedDB

File System

filer:A wrapper library for the HTML5 Filesystem API what reuses UNIX commands (cp, mv, ls) for its API.

本文的主题是基于indexedDB开发简单的文件系统,当然是简单的,可以有一个思路,觉得原来如此简单。

我也不多说了,源码在 IDBProvider.js,核心的代码反而是  _toPromise,

因为indexed的操作,基本是先创建事务,获得objectStore,再进行增删改查。

说道这里是简单版本,对目录的控制,对文件信息的控制,删除都没有具体实现,为什么呢,等你来啊。

    _toPromise(method, ...args) {
        try {
            return new Promise((resolve, reject) => {
                // 获得事务
                let trans = this.transaction
                // 获得请求
                let req = trans.objectStore(this._storeName)[method](...args)
                // 请求成功
                req.onsuccess = event => resolve(event.target.result)
                // 请求失败
                req.onerror = event => reject(req.error)
                // 事务失败
                trans.onerror = event => reject(trans.error)
            })
        } catch (err) {
            Promise.reject(err)
        }
    }

let _w_ = window
_indexedDB_ = _w_.indexedDB || _w_.mozIndexedDB || _w_.webkitIndexedDB || _w_.msIndexedDB
_w_.IDBTransaction = _w_.IDBTransaction || _w_.webkitIDBTransaction || _w_.msIDBTransaction
_w_.IDBKeyRange = _w_.IDBKeyRange || _w_.webkitIDBKeyRange || _w_.msIDBKeyRange

class IDBProvider {

    constructor() {
        // DB
        this._db = null
        // 实例
        this._instance = null
        // store Name
        this._storeName = IDBProvider._storeName
    }

    get transaction() {
        return this._db.transaction([this._storeName], IDBTransaction.READ_WRITE || ‘readwrite‘)
    }

    _toPromise(method, ...args) {
        try {
            return new Promise((resolve, reject) => {
                // 获得事务
                let trans = this.transaction
                // 获得请求
                let req = trans.objectStore(this._storeName)[method](...args)
                // 请求成功
                req.onsuccess = event => resolve(event.target.result)
                // 请求失败
                req.onerror = event => reject(req.error)
                // 事务失败
                trans.onerror = event => reject(trans.error)
            })
        } catch (err) {
            Promise.reject(err)
        }
    }

    static getInstance(dbVersion = 1.0) {
        if (this._instance) {
            Promise.resolve(this._instance)
        }
        return new Promise((resolve, reject) => {
            let request = _indexedDB_.open(IDBProvider._dbName, dbVersion)
            request.onerror = event => {
                return reject(null)
            }
            request.onsuccess = event => {
                let db = request.result
                // 老版本,新版本是onupgradeneeded
                if (db.setVersion && db.version !== dbVersion) {
                    var setVersion = db.setVersion(dbVersion);
                    setVersion.onsuccess = function () {
                        db.createObjectStore(this._storeName)
                        this._instance = new IDBProvider()
                        this._instance._db = request.result
                        return resolve(this._instance)
                    }
                } else {
                    this._instance = new IDBProvider()
                    this._instance._db = request.result
                    return resolve(this._instance)
                }
            }
            request.onupgradeneeded = event => {
                event.target.result.createObjectStore(this._storeName)
            }
        })
    }

    /**
     * 获取文件
     * @param {*String} path
     */
    getFile(path) {
        return this._toPromise(‘get‘, path)
    }

    /**
     * 写入文件
     * @param {*String} path 路径
     * @param {*String|Blob} content 内容
     * @param {*String} type
     * @param {*String} append 暂无用
     */
    async writeToFile(path, content, type = null, append = false) {
        let data = content
        // 不是blob,转为blob
        if (content instanceof ArrayBuffer) {
            data = new Blob([new Uint8Array(content)], { type })
        } else if (typeof content === ‘string‘) {
            data = new Blob([content], { type: ‘text/plain‘ })
        } else {
            data = new Blob([content])
        }
        await this._toPromise(‘put‘, data, path)
        return this.getFile(path)

        /*
        return new Promise((resolve, reject) => {
            let data = content
            // 不是blob,转为blob
            if (content instanceof ArrayBuffer) {
                data = new Blob([new Uint8Array(content)], { type })
            } else if (typeof content === ‘string‘) {
                data = new Blob([content])
            }

            // 存入数据
            let trans = this.transaction
            trans.objectStore(this._storeName).put(data, path)

            trans.objectStore(this._storeName).get(path).onsuccess = event => {
                resolve(event.target.result)
            }

            trans.onerror = event => {
                reject(trans.error)
            }
        }) */
    }

    readEntries(path = ‘‘) {
        if (!path) {
            return this.readAllEntries()
        }
        return this._toPromise(‘getAllKeys‘, IDBKeyRange.lowerBound(path)).then(r => r.filter(p => {
            // 以当前路径开头 && (截断当前为空字符串,或者截断后以/开头)
            return p.indexOf(path) === 0 && (p.substring(path.length) === ‘‘ || p.substring(path.length).indexOf(‘/‘) === 0)
        }))
    }

    readAllEntries() {
        return this._toPromise(‘getAllKeys‘)
    }

    ensureDirectory(directory = ‘‘) {
        return Promise.resolve(directory)
    }

    clear() {
        return this._toPromise(‘clear‘).then(r => true)
    }

    /**
     * 加工处理path,比如特殊字符,比如以/开头等等
     * @param {*String} path
     */
    _handlePath(path) {
        return path
    }
}

IDBProvider._dbName = ‘_fs_db_‘
IDBProvider._storeName = ‘_fs_store‘

// 测试语句
// 读取某个目录的子目录和文件:  IDBProvider.getInstance().then(fs=>fs.readEntries()).then(f=>console.log(f))
// 写文件         IDBProvider.getInstance().then(fs=>fs.writeToFile(‘music/txt.txt‘,‘爱死你‘)).then(f=>console.log(f))
// 获取文件:     IDBProvider.getInstance().then(fs=>fs.getFile(‘music/txt.txt‘)).then(f=>console.log(f))
// 递归创建目录:  IDBProvider.getInstance().then(fs=>fs.ensureDirectory(‘music/vbox‘)).then(r=>console.log( r))
// 递归获取:     IDBProvider.getInstance().then(fs=>fs.readAllEntries()).then(f=>console.log(f))
// 删除所有:     IDBProvider.getInstance().then(fs=>fs.clear()).then(f=>console.log(f)).catch(err=>console.log(err)) 

引用:

Indexed Database API

Indexed DB API

使用 IndexedDB

Basic concepts - Web APIs | MDN

Storing images and files in IndexedDB

IndexedDB 开发指南

时间: 2024-10-08 19:35:19

基于IndexedDB实现简单文件系统的相关文章

基于 lua-resty-upload 实现简单的文件上传服务

今天了解了一下 lua-resty-upload 模块,并基于 lua-resty-upload 模块简单实现了一个基本的表单文件上传服务. lua-resty-upload 在 github 上的项目地址为: https://github.com/openresty/lua-resty-upload 从实现可以看到,其实 upload 服务的实现还是比较简单的,就一个源文件 lualib/resty/upload.lua,总的代码行数也只有 300 行不到. 下面我整理了一下搭建文件上传服务的

基于mogileFS搭建分布式文件系统--海量小文件的存储利器

一.分布式文件系统    1.简介 分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连.分布式文件系统的设计基于客户机/服务器模式.一个典型的网络可能包括多个供多用户访问的服务器.另外,对等特性允许一些系统扮演客户机和服务器的双重角色.例如,用户可以"发表"一个允许其他客户机访问的目录,一旦被访问,这个目录对客户机来说就像使用本地驱动器一样. 当下我们处在一个互联网飞速发展的信息社会,在

(6)基于hadoop的简单网盘应用实现2

一.调用hadoop api实现文件的上传.下载.删除.创建目录和显示功能 (1)添加必要的hadoop jar包. A.首先将Hadoop1.1.2.tar.gz解压到某一个磁盘下. B.右键选择工程,选择build path...., build configure path: C.将hadoop1.1.2文件夹下的jar包添加进去: 还有lib文件夹下的所有jar包(注意:jasper-compiler-5.5.12.jar和jasper-runtime-5.5.12.jar不要引进,否则

Hibernate中,基于Annotation的简单树形结构的实现

在系统设计中,经常用到递归性质的树形结果,比如菜单.多级分类等,一般是在同一个表中定义父子关系实现这种结构. 下面是在Hibernate中,基于Annotation的简单树形结构的实现: 第一步:创建Entity类,并添加注解实现关联关系    ps: 主要是利用@ManyToOne 和 @OneToMany 配置在同一个Entity类中实现树形递归的结构.hibernate注解形式比在xml配置更加简洁 TreeNode.java 1 package com.hfut.hibernate; 2

jmGraph:一个基于html5的简单画图组件

jmGraph:一个基于html5的简单画图组件 特性: 代码书写简单易理解 面向对象的代码结构 对图形控件化 样式抽离 模块化:入seajs实现模块化开发 兼容性:暂只推荐支持html5的浏览器:ie9+,chrome,firefox等. jiamao/jmgraph · GitHub APIs jmgraph是一个基于html5的WEB前端画图组件. 前端画图对象控件化,支持鼠标和健盘事件响应,可对单个控件样式设定,支持简单的动画处理.可大大地简化前端画图.

(8)基于hadoop的简单网盘应用实现4

文件结构 (1).index.jsp首页面实现 index.jsp <%@ include file="head.jsp"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@page import="org.apache.hadoop.fs.FileSta

基于AVR128的简单Modbus协议实现

Modbus通讯协议是由Modicon公司在1979年开发的,应用于工业现场控制的总线协议.Modbus通讯系统包括带有可编程控制的芯片节点和公共传输线组成,其目的是用于多节点数据的采集和监控.Modbus协议采用主从模式,通讯系统中有一个主机对多个节点从机进行监控,从机节点最多支持247个.每个从机均有自己独立的从机地址,而且改地址能够被主机识别. 能够支持Modbus协议的通讯系统有RS-232,RS-422,RS-485等.同时Modbus协议具有标准.开放.免费.帧格式简单等特点而被广大

基于redis 内存数据库简单使用

在ecplise中使用内存数据的客端户,前提要准备要下载两个jar包 commons-pool2-2.0.jar jedis-2.4.2.jar 前提准备做好了,那我们就开启redis的服务,打开一个命令窗口输入如下命令:redis-server  或redis-server  redis根目\redis.conf 服务器已经开启了,注意端号是6377 2.在eclipse 创建一个项目,把redist需要的包导入项目中 3.写一个Jedis工具类 public class JedisUtil 

&nbsp; &nbsp; &nbsp; &nbsp; 基于bind的简单DNS搭建

我们都知道互联网通信是基于IP地址的,然而我们在访问一个网站的时候只需输入主机名(有时也指我们所说的域名)即可实现,那是因为我们在背后用到了将主机名解释为了对应的IP地址的机制--DNS.下面我们来介绍DNS的实现过程. 一:bind的安装配置(正反解析): 1.bind 介绍:bind:bekerleyinternet name domain,我们简单的理解它是用bind 工具实 现DNS服务器的配置. 2.bind 安装:bind 安装比较简单我们可以使用下面命令安装并查看安装bind都生成