zoukankan      html  css  js  c++  java
  • 基于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 开发指南

     

  • 相关阅读:
    HDU_1016——素环问题DFS
    什么是REST?以及RESTful的实现
    WebApi系列~基于RESTful标准的Web Api
    理解RESTful架构
    国内技术管理人员批阅google的“春运交通图”项目
    项目质量量化考核建议
    设计模式在交易系统中的应用
    修改Chrome临时文件位置
    百度员工离职总结:如何做个好员工?
    Firebird数据库系统的开发团队
  • 原文地址:https://www.cnblogs.com/wangchaoyuana/p/7497405.html
Copyright © 2011-2022 走看看