zoukankan      html  css  js  c++  java
  • HTML5之本地文件系统API

    HTML5之本地文件系统API - File System API

    新的HTML5标准给我们带来了大量的新特性和惊喜,例如,画图的 画布Canvas,多媒体的audio和 video等等。除了上面我们提到的,还有比较新的特性 - File System API,它能够帮助我们来突破沙箱访问我们本地的文件系统,从而有效的弥补桌面和web应用之间的鸿沟。在今天这篇文章中,我们将会介绍基本的File system API的知识,探索HTML5的本地文件系统API的新特性,希望大家能够喜欢!

    介绍

    “我们不再需要下载并且安装软件。一个简单的web浏览器和一个可供使用的互联网就足以让我们在任何时间,任何地点,还有任何平台上使用任何web应用程序。”

    简单来说,web应用很酷,但是相对于桌面应用来说,它们有比较显著的弱点:它们无法在一个有层次的文件夹结构体即文件系统中互动和组织。 幸运的是,如果我们使用Filesystem API,我们可以做到。这个API帮助我们控制私有的本地文件系统“沙箱(sandbox)",在这里我们可以读和写文件,创建和排列文件夹。虽然在我们写这篇文章的时候,只有Google的Chrome完整的支持Filesystem API,我觉得我们还是有必要学习这个强大并且方便的 本地存储特性。

    本地文件系统API包含了俩个不同的版本。异步API,对于一般的应用来说非常有用。同步API,特别为web设计。这篇文章中,我们将介绍异步版本的API。

    步骤一:开始

    首先我们需要通过请求一个LocalFile对象来得到HTML5文件系统的访问,使用window.requetFileSystem全局方法:

    window.requestFileSystem(type, size, successCallback, opt_errorCallback)

    前俩个参数,你指定需要的生命周期类型和文件系统的大小。一个持久性的(Persistent)文件系统非常适合长期保存用户数据。浏览器不会删除,除非用户特意要求。一个临时性(Temporary)的文件系统非常适合web应用来缓存数据,但是在浏览器删除文件系统后任然可以操作。size用来指定字节大小,一般指定有效的最大访问存储大小。

    第三个参数是一个回调函数(callback),当用户代理成功的提供了一个文件系统后触发。它的主要参数是一个FileSystem对象。并且我们可以添加一个可选的callback函数,用来在出错的时候调用,或者请求被拒绝的时候。参数是一个FileError对象。虽然这个对象是可选的,最好还是捕捉这些错误,因为很多地方可能会出错。

    文件系统得到这些方法依赖于最初包含的document。所有的document或者web应用来自于同一个最初来源共享一个文件系统。两个document或者应用来自于不同的来源完全不同并且不可联系。一个文件系统严格被限制访问一个应用,不能访问另外一个应用保存的数据。同时也对于其它的文件独立。这是一件好事:让文件访问不相干的系统文件资源,例如,操作系统的文件,完全没有必要,也不安全。

    我们看看这个例子:

    window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
    window.requestFileSystem(window.TEMPORARY, 5*1024*1024, initFS, errorHandler);
    
    function initFS(fs){
      alert("Welcome to Filesystem! It's showtime :)"); // Just to check if everything is OK :)
      // place the functions you will learn bellow here
    }
    function errorHandler(){
      console.log('An error occured');
    } 
    

    这里我们创建而来一个临时的5M文件系统存储。提供了一个成功的callback函数,用阿里操作我们的文件系统。并且添加了一个错误处理,用来处理错误。这里errorhandler()方法非常具有一般性。 如果你想的话,你可以创建一个优化版本,显示给用户更加详细的error信息。

    function errorHandler(err){
     var msg = 'An error occured: ';
    
      switch (err.code) {
        case FileError.NOT_FOUND_ERR:
          msg += 'File or directory not found';
          break;
    
        case FileError.NOT_READABLE_ERR:
          msg += 'File or directory not readable';
          break;
    
        case FileError.PATH_EXISTS_ERR:
          msg += 'File or directory already exists';
          break;
    
        case FileError.TYPE_MISMATCH_ERR:
          msg += 'Invalid filetype';
          break;
    
        default:
          msg += 'Unknown Error';
          break;
      };
    
     console.log(msg);
    };

    这个你得到的文件对象拥有一个name(一个唯一的文件系统名称,由浏览器赋值)并且ROOT属性参考文件系统的ROOT目录。这是一个DirectoryEntry对象,可以嵌套使用。每一个文件目录都可以包含文件,由FileEntry对象标示。DirectoryEntry对象定义使用路径名称得到DirectoryEntry和FileEntry的方法(如果不存在路径名,会创建新的目录)。DirectoryEntry同时定义了createReader()工厂方法用来返回一个DirectoryReader对象用来列出一个文件夹。FileEntry类定义了一个得到File对象的方。你可以使用FileReader对象来读取文件。FileEntry定义了另外一个方法用来返回一个FileWriter对象,你可以将内容写到文件中。

    听起来是不是有点儿复杂?通过下面的例子我们会更清楚的理解。

    步骤二:处理文件夹

    很显然,第一件我们需要做的事就是创建一些目录。虽然ROOT目录已经村存在,你不希望把所有的文件都保存在那里。文件夹使用DirectoryEntry对象来创建。在下面的例子中我们将在ROOT文件夹中创建一个文件夹:Documents

    fs.root.getDirectory('Documents', {create: true}, function(dirEntry) {
      alert('You have just created the ' + dirEntry.name + ' directory.');
    }, errorHandler); 
    

    getDiretory()方法用来读和创建目录。作为第一个参数,你可以传递一个名字或者路径来寻找或者创建。我们设计第二个参数为true,因为我们需要创建一个目录 - 不是读一个已存在的目录。当然我们在最后添加了一个错误的callback方法。

    这里我们创建了一个目录,接着我们创建一个子目录。这个方法类似除了一下一点,我们修改第一个参数为”Documents/Music“。很简单是不是,如果你想创建一个子目录,Sky,使用俩个父目录那么怎么做呢? 如果你使用Documents/Music/Nature/Sky作为路径参数,你会得到错误,因为你不能创建一个没有父目录的目录。解决方式是一个一个的创建。但是这样很低效并且麻烦。更好的解决方式:创建一个方法用来自动创建目录:

    function createDir(rootDir, folders) {
      rootDir.getDirectory(folders[0], {create: true}, function(dirEntry) {
        if (folders.length) {
          createDir(dirEntry, folders.slice(1));
        }
      }, errorHandler);
    };
    createDir(fs.root, 'Documents/Images/Nature/Sky/'.split('/'));

    使用这个小技巧,我们只需要提供完整的路径就能自动为我们创建文件夹。

    接下来我们需要检查我们的文件系统。我们创建一个DirectoryReader对象,使用ReadEntries()方法来读取目录中的内容。

    fs.root.getDirectory('Documents', {}, function(dirEntry){<br>
      var dirReader = dirEntry.createReader();
      dirReader.readEntries(function(entries) {<br>
        for(var i = 0; i < entries.length; i++) {
          var entry = entries[i];
          if (entry.isDirectory){
            console.log('Directory: ' + entry.fullPath);
          }
          else if (entry.isFile){
            console.log('File: ' + entry.fullPath);
          }
        }
    
      }, errorHandler);
    }, errorHandler);

    在以上代码中,isDirectory和isFile属性用来得到不同的输出文件或者文件夹。而且我们使用fullPath属性来得到完整的输入内容,而不是仅仅名字。

    这里有两种方式来删除一个DirectoryEntry:remove()和removeRecursively()。第一个删除需要被删除文件夹为空,否则会得到错误。

    fs.root.getDirectory('Documents/Music', {}, function(dirEntry) {
      dirEntry.remove(function(){
        console.log('Directory successfully removed.');
      }, errorHandler);
    }, errorHandler);
    
    If the Music folder has files within it, then you need to use the second method, which recursively deletes the directory and all of its contents.
    
    fs.root.getDirectory('Documents/Music', {}, function(dirEntry) {
      dirEntry.removeRecursively(function(){
        console.log('Directory successufully removed.');
      }, errorHandler);
    }, errorHandler);

    步骤三:处理文件

    上面我们介绍了如何创建目录,下面我们介绍如何创建文件。

    以下例子在ROOT目录创建了一个空的文件gbin1.txt。

    fs.root.getFile('gbin1.txt', {create: true, exclusive: true}, function(fileEntry) {
      alert('A file ' + fileEntry.name + ' was created successfully.');
    }, errorHandler);

    getFile方法的第一个参数可以是绝对或者相对路径,但是必须是合法的。例如,没有父目录创建一个文件会得到一个错误。第二个参数是一个对象说明,如果文件不存在的话描述功能行为。在这个例子中:create:true表示如果文件不存则创建一个文件,如果存在则抛出错误(exclusive:true)。否则如果create:false,简单取得文件并返回。

    fs.root.getFile('gbin1.txt', {create: false}, function(fileEntry) {
      fileEntry.createWriter(function(fileWriter) {
        window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder;
        var bb = new BlobBuilder();
        bb.append('Filesystem API is awesome!');
        fileWriter.write(bb.getBlob('text/plain'));
      }, errorHandler);
    }, errorHandler);

    以上代码中,我们返回了text.txt文件,创建了FileWriter对象。我们然后通过创建一个新的BlobBuilder对象添加内容并且使用了FileWriter的write()方法。

    调用getFile()方法只会返回FileEntry对象。并不返回文件的内容。因此,如果我们想读出文件内容,我们需要使用File对象和FileReader对象。

    fs.root.getFile('test.txt', {}, function(fileEntry) {
      fileEntry.file(function(file) {
        var reader = new FileReader();
        reader.onloadend = function(e) {
          alert(this.result);
        };
        reader.readAsText(file);
      }, errorHandler);
    }, errorHandler);

    我们已经写入了文件一些内容,但是如果以后添加更多内容呢?为了添加内容到已存在的文件,又需要调用FileWriter。我们可以使用seek()方法重新将writer添加到文件。seek接受字节偏移(byte offset)这个参数,并且设置file writer的位置。

    fs.root.getFile('test.txt', {create: false}, function(fileEntry) {
      fileEntry.createWriter(function(fileWriter) {
        fileWriter.seek(fileWriter.length);
        window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder;
        var bb = new BlobBuilder();
        bb.append('Yes, it is!');
        fileWriter.write(bb.getBlob('text/plain'));
      }, errorHandler);
    }, errorHandler);
    

    如果需要删除文件,我们调用entry.remove()。一个参数是一个没有参数的回调函数,当文件被成功删除后调用。第二个参数是一个可选的错误回调函数。

    fs.root.getFile('test.txt', {create: false}, function(fileEntry) {
      fileEntry.remove(function() {
        console.log('File successufully removed.');
      }, errorHandler);
    }, errorHandler);

    步骤四:处理文件和目录

    FileEntry和DirectoryEntry分享同一个API方法来拷贝,移动和重命名。这里有俩个方法你可以使用进行操作:copyTo()和moveTo()。他们都接受同样的参数:

    copyTo(parentDirEntry, opt_newName, opt_successCallback, opt_errorCallback); 
    
    moveTo(parentDirEntry, opt_newName, opt_successCallback, opt_errorCallback); 
    

    第一个参数是目标父目录,即你希望拷贝到的位置。第二个参数是可选的新文件名字,实际只有拷贝到同一个目录才需要。否则得到错误信息。其它俩个参数前面介绍过了。

    我们看一个实例,下面我们拷贝gbin1.txt从Root到Documents目录:

    function copy(currDir, srcEntry, destDir) {
      currDir.getFile(srcEntry, {}, function(fileEntry) {
        currDir.getDirectory(destDir, {}, function(dirEntry) {
          fileEntry.copyTo(dirEntry);
        }, errorHandler);
      }, errorHandler);
    }
    
    copy(fs.root, 'test.txt', 'Documents/');

    下面是一个移动gbin1.txt到Document的例子:

    function move(currDir, srcEntry, dirName) {
      currDir.getFile(srcEntry, {}, function(fileEntry) {
        currDir.getDirectory(dirName, {}, function(dirEntry) {
          fileEntry.moveTo(dirEntry);
        }, errorHandler);
      }, errorHandler);
    }
    
    move(fs.root, 'gbin1.txt', 'Documents/');

    下面是重命名的例子:

    function rename(currDir, srcEntry, newName) {
      currDir.getFile(srcEntry, {}, function(fileEntry) {
        fileEntry.moveTo(currDir, newName);
      }, errorHandler);
    }
    
    rename(fs.root, 'gbin1.txt', 'gbtags.txt');

    更多资源

    如果你希望了解更多内容,请参考如下:

    总结

    HTML5的文件系统API是一个强大的技术,提供了很多web应用技术的新的体验。不过实话实说,目前非常新,没有广泛的浏览器支持。但是未来肯定会有很大的改观。或许你愿意成为先行者!Enjoy!

    just do myself
  • 相关阅读:
    一行代码更改博客园皮肤
    fatal: refusing to merge unrelated histories
    使用 netcat 传输大文件
    linux 命令后台运行
    .net core 使用 Nlog 配置文件
    .net core 使用 Nlog 集成 exceptionless 配置文件
    Mysql不同字符串格式的连表查询
    Mongodb between 时间范围
    VS Code 使用 Debugger for Chrome 调试vue
    css权重说明
  • 原文地址:https://www.cnblogs.com/rookieCat/p/4635549.html
Copyright © 2011-2022 走看看