FileHandle API

翻译不完整。 请帮助我们翻译这篇文章!

{{non-standard_header}}

FileHandle API允许处理文件,包括创建文件和修改其内容(unlike the File API)。由于通过该API操作的文件可以物理存储在设备上,因此编辑部分使用基于回合的锁定机制,以避免出现种族问题。

API概述

该API基于以下接口:

  • {{domxref("IDBDatabase.mozCreateFileHandle")}} (was called {{domxref("IDBDatabase.mozCreateFileHandle")}}.)
  • {{domxref("IDBMutableFile")}} (was previously {{domxref("FileHandle")}}.)
  • {{domxref("LockedFile")}}
  • {{domxref("FileRequest")}}

它还与File API,尤其是 {{domxref("File")}} 和{{domxref("Blob")}} 接口具有连接。

Basic operations

创建文件句柄

因为目的是允许通过IndexedDB存储文件,所以创建{{domxref(“ FileHandle”)}}实例需要IndexedDB Database

var IDBReq = indexedDB.open("myFileStorageDataBase");

IDBReq.onsuccess = function(){
  var DB = this.result;
  var buildHandle = DB.mozCreateFileHandle("test.txt", "plain/text");
    
  buildHandle.onsuccess = function(){
    var myFileHandle = this.result;
    console.log('handle', myFileHandle);
  };
};

{{domxref("IDBDatabase.mozCreateFileHandle","mozCreateFileHandle()")}}接受两个参数:名称和可选类型。 这两个都是描述性的,数据库不使用。 但是,它们对于{{domxref("FileHandle")}}对象很重要,因为它可以生成{{domxref("File")}}对象,这些对象继承自己的{{domxref("File.name","name")}}和{{domxref("File.type","type")}}的值。 就是说,由于名称与任何实际文件名都不匹配,因此它可以是一个空字符串,甚至不必是唯一的。

Note: the above code only creates a "temporary file" that exists only while you hold the {{domxref("FileHandle")}} instance. If you want a file to survive a page refresh/app relaunch, you need to store the handle in a more permanent location, like the database itself. See {{Anch("File storage")}} below to learn more about this.

执行读写操作

要在已处理的文件中进行读取或写入,需要获取{{domxref("LockedFile")}}。 {{domxref("FileHandle.open()")}} 方法提供了这样的对象,该对象可以是readonly的也可以是readwrite的。 对readonly{{domxref("LockedFile")}} 对象执行写操作的任何尝试都将失败。

Writing

There are three possible writing operations on a locked file:

  • {{domxref("LockedFile.write","write")}} : It's an arbitrary writing method which starts writing in the file at the {{domxref("LockedFile.location")}} byte.
  • {{domxref("LockedFile.append","append")}} : This operation always writes content at the end of the file.
  • {{domxref("LockedFile.truncate","truncate")}} : This operation keeps the nth-first bytes of the file and removes the rest.
// Get a LockedFile object from the handle
var myFile = myFileHandle.open('readwrite');

// Start a writing operation
var writing = myFile.append('Some content');

writing.onsuccess = function () {
  console.log('Writing operation successful');
}

writing.onerror = function () {
  console.log('Something goes wrong in the writing process: ' + this.error);
}

Reading

可以直接写入{{domxref("LockedFile")}} 对象的内容,而无需使用中间的{{domxref("File")}}对象和 {{domxref("FileReader")}}对象。 {{domxref("LockedFile")}}接口提供了{{domxref("LockedFile.readAsText","readAsText")}}方法和{{domxref("LockedFile.readAsArrayBuffer","readAsArrayBuffer")}}方法 。

这两种方法期望一个大小来指示必须从{{domxref("LockedFile.location")}}字节开始读取多少个字节。

要读取整个文件,需要知道其大小。 可以通过{{domxref("LockedFile.getMetadata()")}}方法来检索此信息(及其最后修改日期)。

// Get a LockedFile object from the handle
var myFile = myFileHandle.open('readwrite');

// Retrieve the size of the file
var getmeta = myFile.getMetadata();

getmeta.onsuccess = function () {
  var size = this.result.size;

  // The reading operation will start with the byte at index 0 in the file
  myFile.location = 0;

  // Start a reading operation for the whole file content
  var reading = myFile.readAsText(size);

  reading.onsuccess = function () {
    console.log('The content of the file is:');
    console.log(this.result);
  }

  reading.onerror = function () {
    console.log('Something goes wrong in the reading process: ' + this.error);
  }
}

文件快照

在许多情况下,获取文件快照可能很方便。 例如,许多API都期望使用{{domxref("Blob")}}或{{domxref("File")}}对象,例如{{domxref("FileReader")}}(易于使用) 读取整个文件)或{{domxref("XMLHttpRequest")}}。

可以使用{{domxref("FileHandle.getFile","getFile")}}获得一个{{domxref("File")}}对象,该对象代表{{domxref("FileHandle")}}对象处理的文件的当前状态方法。 这样的{{domxref("File")}}对象与原始文件完全不同步,这意味着对该对象所做的任何更改将永远不会反映到已处理文件中,并且对已处理文件所做的任何更改也将永远不会被反映。 推送到{{domxref("File")}}对象。

var mySnapshot = null;
var request = myFileHandle.getFile();

request.onsuccess = function () {
  mySnapshot = this.result;
}

管理进度

来自{{domxref("LockedFile")}}接口的所有方法都返回一个{{domxref("FileRequest")}}对象。 这样的对象基本上是具有额外功能的{{domxref("DOMRequest")}}:它可以监视操作的进度。 有时读写操作可能会很长,因此最好监视该操作以向用户提供反馈。 可以使用{{domxref("FileRequest.onprogress")}}事件处理程序来完成此类监视。

var progress = document.querySelector('progress');
var myFile   = myFileHandle.open('readonly');

// Let's read a 1GB file
var action   = myFile.readAsArrayBuffer(1000000000);

action.onprogress = function (event) {
  if (progress) {
    progress.value = event.loaded;
    progress.max   = event.total;
  }
}

action.onsuccess = function () {
  console.log('Yeah \o/ Just read a 1GB file');
}

action.onerror = function () {
  console.log('Oups :( Unable to read a 1GB file')
}

文件储存

创建文件句柄时,只要您持有{{domxref("FileHandle")}}实例,关联文件就仅作为“临时文件”存在。 如果您希望文件在页面刷新/应用重新启动后仍然存在,则需要将句柄存储在数据库中(不一定是用于创建{{domxref("FileHandle")}} object)。

var IDBReq = window.indexedDB.open('myFileStorageDataBase');

// If necessary, let's create a datastore for the files
IDBReq.onupgradeneeded = function () {
  this.result.createObjectStore('files');
}

IDBReq.onsuccess = function () {
  var DB = this.result;

  // Let's create a new file
  var handleReq = DB.mozCreateFileHandle("test.txt", "plain/text");

  handleReq.onsuccess = function () {
    var myFileHandle = this.result;
    var store = DB.transaction(['files'], 'readwrite').objectStore('files');

    // Let's store the file permanently
    // HINT: it could be handy to use the file name as the storage key
    var storeReq = store.add(myFileHandle, myFileHandle.name);

    storeReq.onsuccess = function () {
      console.log('The file has been successfully stored and can be retrieved anytime.')
    }
  }
}

以这种方式存储的文件将物理地放置在设备上。数据库本身仅存储指向该文件的指针。这意味着,如果{{domxref("FileHandle")}} 对象在多个DB或多个数据存储中存储了几次,则所有这些对象都将引用同一个唯一文件。这不是问题,因为要访问文件,需要一个{domxref("LockedFile")}}对象,并且对该对象的操作是独立执行的,这意味着一旦{{domxref("LockedFile")}} 在激活状态下,保证此 {{domxref("LockedFile")}} 的所有操作在基础文件上顺序发生,而不会与其他{{domxref("LockedFile")}}的操作交错。

安全的写操作

出于性能原因,写(和读)操作是在内存中完成的。这些操作的结果定期异步刷新到设备存储区域。如果由于某种原因在此之前出现问题,则可能会丢失某些操作的结果。为了避免这个问题,可以使用 {{domxref("LockedFile.flush()")}} 方法。成功调用此方法后,可以确保对文件的更改是安全的。

// Get a LockedFile object from the handle
var myFile = myFileHandle.open('readwrite');

// Start a writing operation
var writing = myFile.append('Some content');

writing.onsuccess = function () {
  console.log('Writing operation successful');

  var saving = myFile.flush();

  saving.onsuccess = function () {
    console.log('The file has been successfully stored');
  }
}

writing.onerror = function () {
  console.log('Something goes wrong in the writing process: ' + this.error);
}

API兼容性

Why a different API than FileWriter?

The FileWriter specification defines FileWriters, objects aiming at representing editable files. Discussions on public-webapps led to the conclusion that the API would behave poorly in the case of different entities writing concurrently to the same file. The outcome of this discussion is the FileHandle API with its LockedFile and transaction mechanism.

Specifications

A formal specification draft is being written. As it does not fully match the current implementation, be warned that the implementation and/or the specification will be subject to changes.

Specification Status Comment
{{SpecName('FileSystem')}} {{Spec2('FileSystem')}} Draft proposal

Browser compatibility

{{CompatibilityTable}}
Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support {{CompatNo}} 15 {{CompatNo}} {{CompatNo}} {{CompatNo}}
Feature Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support {{CompatNo}} 15 {{CompatNo}} {{CompatNo}} {{CompatNo}}