aboutsummaryrefslogtreecommitdiff
path: root/files/ja/web/api/file_handle_api/index.html
blob: 2fa72f854f0f0d01f201b6bd69c39bb870996ae9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
---
title: FileHandle API
slug: Web/API/File_Handle_API
tags:
  - API
  - Files
  - Non Standard
  - Reference
  - WebAPI
translation_of: Web/API/File_Handle_API
---
<p>{{non-standard_header}}</p>

<p>FileHandle API は、ファイルの作成や内容の変更など、ファイルを操作するための API です (<a href="/docs/DOM/File" title="DOM/File">File API</a> とは異なります)。この API を通じたファイル操作は、デバイス上に物理的に格納でき、部分的な編集には、競合問題を避けるためにターンベースのロック機構が使用されています。</p>

<h2 id="API_概観">API 概観</h2>

<p>この API は、次のインターフェースを基にしています:</p>

<ul>
 <li>{{domxref("IDBDatabase.mozCreateFileHandle")}}</li>
 <li>{{domxref("FileHandle")}}</li>
 <li>{{domxref("LockedFile")}}</li>
 <li>{{domxref("FileRequest")}}</li>
</ul>

<p>これは、File API の {{domxref("File")}} インターフェースおよび {{domxref("Blob")}} インターフェースとも接続しています。</p>

<h2 id="基本的な操作">基本的な操作</h2>

<h3 id="FileHandle_インスタンスの作成">FileHandle インスタンスの作成</h3>

<p>このインテントは IndexedDB を通じてファイルを保存しているため、{{domxref("FileHandle")}} インスタンスを作成するのに <a href="/docs/IndexedDB/IDBFactory#open" title="IndexedDB/IDBFactory#open">IndexedDB Database</a> が必要です。</p>

<div style="overflow: hidden;">
<pre class="brush: js">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);
  };
};
</pre>
</div>

<p>{{domxref("IDBDatabase.mozCreateFileHandle","mozCreateFileHandle()")}} は、ファイル名と任意の形式の 2 個の引数を取ります。これらは説明のためのものであり、データベースには使用されません。しかし、これらの値から {{domxref("File")}} オブジェクトの {{domxref("File.name","name")}}{{domxref("File.type","type")}} に継承して生成するため、{{domxref("FileHandle")}} オブジェクトにとって重要です。つまり、例えば空文字にすると実際に存在するファイルと一致しないため、ユニークな名前にしなくてもよいです。</p>

<div class="note">
<p><strong>補足:</strong> 上記のコードは、{{domxref("FileHandle")}} インスタンスを保持している間のみ存在する「一時ファイル」を作成するだけです。ページ更新やアプリ再起動に遭遇するファイルを扱いたい場合は、データベース自身など、ファイルハンドルを永続的な場所に格納する必要があります。詳しくは、後述の {{Anch("File storage")}} を参照してください。</p>
</div>

<h3 id="ファイルの読み書き操作">ファイルの読み書き操作</h3>

<p>ハンドルしたファイルを読んだり書いたりするには、{{domxref("LockedFile")}} を取得する必要があります。{{domxref("FileHandle.open()")}} メソッドがこの操作のためのオブジェクトを提供しており、<code>readonly</code> または <code>readwrite</code> が可能です。<code>readonly</code>{{domxref("LockedFile")}} に書き込みを行おうとすると失敗します。</p>

<h4 id="書き込み">書き込み</h4>

<p>locked ファイルには 3 通りの書込み操作があります:</p>

<ul>
 <li>{{domxref("LockedFile.write","write")}} : これは、ファイル内の {{domxref("LockedFile.location")}} byte の位置から書き込みを開始するメソッドです。</li>
 <li>{{domxref("LockedFile.append","append")}} : これは、常にファイル末尾にコンテンツを追加するメソッドです。</li>
 <li>{{domxref("LockedFile.truncate","truncate")}} : これは、ファイルの最初の nth-first byte までを維持してそれ以降を削除するメソッドです。</li>
</ul>

<pre class="brush: js">// 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);
}
</pre>

<h4 id="読み込み">読み込み</h4>

<p>中間の {{domxref("File")}} オブジェクトや {{domxref("FileReader")}} オブジェクトを使用せずに、{{domxref("LockedFile")}} オブジェクトのコンテンツを直接読み込むことが可能です。{{domxref("LockedFile")}} インターフェースは、{{domxref("LockedFile.readAsText","readAsText")}} メソッドと {{domxref("LockedFile.readAsArrayBuffer","readAsArrayBuffer")}} メソッドを提供しています。</p>

<p>これら 2 個のメソッドは、ファイル開始位置からの読み込むサイズを {{domxref("LockedFile.location")}} byte で指定して読み込みます。示すサイズを指定します。</p>

<p>ファイル全体を読み込むには、そのサイズを知る必要があります。この情報 (および最終変更日の日付) は、{{domxref("LockedFile.getMetadata()")}} メソッドを通して取得できます。</p>

<pre class="brush: js">// 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);
  }
}
</pre>

<h3 id="File_スナップショット">File スナップショット</h3>

<p>In many cases it can be handy to get a snapshot of the file. For example, there are many APIs that expect {{domxref("Blob")}} or {{domxref("File")}} objects such as domxref("FileReader")}} (which can be easier to use to read the whole file) or {{domxref("XMLHttpRequest")}}.</p>

<p>It's possible to get a {{domxref("File")}} object representing the current state of the file handled by the {{domxref("FileHandle")}} object by using the {{domxref("FileHandle.getFile","getFile")}} method. Such a {{domxref("File")}} object is completely desynchronized from the original file, which means any change made to that object will never be reflected to the handled file as well as any change made to the handled file will never be pushed to the {{domxref("File")}} object.</p>

<pre class="brush: js">var mySnapshot = null;
var request = myFileHandle.getFile();

request.onsuccess = function () {
  mySnapshot = this.result;
}
</pre>

<h3 id="進捗の管理">進捗の管理</h3>

<p>All the methods from the {{domxref("LockedFile")}} interface return a {{domxref("FileRequest")}} object. Such an object is basically a {{domxref("DOMRequest")}} with an extra power: it allows to monitor the progress of an operation. Sometimes writing and reading operations can be very long, therefore it is a good idea to monitor the operation to provide feedback to the user. Such monitoring can be done using the {{domxref("FileRequest.onprogress")}} event handler.</p>

<pre class="brush: js">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')
}
</pre>

<h2 id="File_ストレージ">File ストレージ</h2>

<p>When a file handle is created, the associated file only exists as a "temporary file" as long as 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 database (not necessarily the one used to create the {{domxref("FileHandle")}} object).</p>

<pre class="brush: js">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.')
    }
  }
}
</pre>

<p>A file stored that way is physically put on the device. The database itself only stores a pointer to that file. It means that if the {{domxref("FileHandle")}} object is stored several times in several DBs or several data stores, all those objects will reference the same unique file. This is not a problem because to access the file, a {{domxref("LockedFile")}} object is required and operations on such object are performed in <a href="http://en.wikipedia.org/wiki/Isolation_%28database_systems%29" title="http://en.wikipedia.org/wiki/Isolation_%28database_systems%29">isolation</a>, meaning that once a {{domxref("LockedFile")}} is active, all operations of this {{domxref("LockedFile")}} are guaranteed to happen sequentially on the underlying file without being interleaved with operations from other {{domxref("LockedFile")}}.</p>

<h3 id="安全な書込み操作">安全な書込み操作</h3>

<p>For performance reasons, write (and read) operations are done in memory. Periodically, the results of those operation are asynchronously flushed to the device storage area. If for some reason a problem occurs before that, you can lose the results of some operations. To avoid that problem, you can force the data to be flushed by using the {{domxref("LockedFile.flush()")}} method. Once this method has been successfully called, you can be sure your change on the file will be safe.</p>

<pre class="brush: js">// 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);
}</pre>

<h2 id="API_の互換性">API の互換性</h2>

<h3 id="FileWriter_と_API_が異なるのはなぜですか?">FileWriter と API が異なるのはなぜですか?</h3>

<p>The <a href="http://dev.w3.org/2009/dap/file-system/file-writer.html" title="http://dev.w3.org/2009/dap/file-system/file-writer.html">FileWriter specification</a> defines FileWriters, objects aiming at representing editable files. <a href="http://lists.w3.org/Archives/Public/public-webapps/2012JanMar/0886.html" title="http://lists.w3.org/Archives/Public/public-webapps/2012JanMar/0886.html">Discussions on public-webapps</a> 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.</p>

<h3 id="Browser_Compatibility" name="Browser_Compatibility">仕様書</h3>

<p>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.</p>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">仕様</th>
   <th scope="col">実装状況</th>
   <th scope="col">コメント</th>
  </tr>
  <tr>
   <td>{{SpecName('FileSystem')}}</td>
   <td>{{Spec2('FileSystem')}}</td>
   <td>Draft proposal.</td>
  </tr>
 </tbody>
</table>

<h3 id="ブラウザの互換性">ブラウザの互換性</h3>

<div>
<div>Supported in Firefox 15.</div>
</div>