DIR : /home/kozerus/public_html/koh5_fileapi.html
/home/kozerus/public_html
<html lang="en" dir="ltr" itemscope itemtype="http://schema.org/Article">
<head>
<meta charset="utf-8">
<meta property="twitter:account_id" content="1593210261" />
<!-- Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Eric Bidelman - e.bidelman@google.com
*
*
*
-->
<title>h5rocks Exploring the FileSystem APIs - HTML5 Rocks</title>
<meta name="description" content="The FileSystem APIs give applications the ability to read/write files and directories in a secure, sandboxed file system on a user's local machine.">
<meta name="keywords" content="html5,html 5,html5 demos,html5 examples,javascript,css3,notifications,geolocation,web workers,apppcache,file api,filereader,indexeddb,offline,audio,video,drag and drop,chrome,sse,mobile">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<meta name="theme-color" content="#f04530">
<link rel="shortcut icon" href="/favicon.ico">
<meta itemprop="name" content="Exploring the FileSystem APIs - HTML5 Rocks">
<meta itemprop="image" content="http://www.html5rocks.com/static/images/html5rocks-logo-wings.png">
<link rel="alternate" hreflang="de" href="loc/de/">
<link rel="alternate" hreflang="es" href="loc/es/">
<link rel="alternate" hreflang="it" href="loc/it/">
<link rel="alternate" hreflang="ja" href="loc/ja/tutorials/file/filesystem/">
<link rel="alternate" hreflang="ko" href="loc/ki/tutorials/file/filesystem/">
<link rel="alternate" hreflang="ru" href="loc/ru/tutorials/file/filesystem/">
<link rel="alternate" hreflang="zh" href="loc/zh/tutorials/file/filesystem/">
<link rel="stylesheet" media="all" href="lib/css/v2-combined.min_20131111.css">
<link href="//fonts.googleapis.com/css?family=Open+Sans:300,400,400italic,600,800|Source+Code+Pro" rel="stylesheet">
<link rel="apple-touch-icon" href="/static/images/identity/HTML5_Badge_64.png">
<link rel="apple-touch-icon-precomposed" href="/static/images/identity/HTML5_Badge_64.png">
<script src="lib/js/modernizr.custom.82437.js"></script>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5-els.js"></script>
<![endif]-->
<style>
</style>
</head>
<body data-href="tutorials-file-filesystem" onload="" class="article tutorial">
<header class="main" id="siteheader">
<h1 id="title">
<a href="/en/" title="koh5rocks">koh5rocks</a>
</h1>
<a href="#sitenav" id="navtoggle">Show navigation</a>
<a id="toctoggle" href="#toc">toc</a>
<nav id="sitenav">
<ul>
<li id="home_menu"><a href="/en/" class="home">Home</a></li>
<li id="tutorials_menu"><a href="/en/tutorials/?page=1" class="tutorials">Tutorials</a></li>
<li id="updates_menu"><a href="http://updates.html5rocks.com/" class="updates">Updates</a></li>
</ul>
</nav>
<nav class="toc" id="toc">
<h1>Table of Contents</h1>
<ul>
<li><a href='#toc-introduction'>Introduction</a></li>
<li><a href='#toc-requesting'>Requesting a file system</a></li>
<li><a href='#toc-file'>Working with files</a></li>
<li><a href='#toc-dir'>Working with directories</a></li>
<li><a href='#toc-copy-rename-move'>Copying, renaming, and moving</a></li>
<li><a href='#toc-filesystemurls'>filesystem: URLs</a></li>
<li><a href='#toc-dir-fullexample'>Putting it all together</a></li>
<li><a href='#toc-usecases'>Use Cases</a></li><li><a href='#toc-references'>Reference specifications</a></li>
</ul>
<h1 class="visible-title">Localizations:</h1>
<ul>
<li><a href="/de/tutorials/file/filesystem/">Deutsch</a></li>
<li><a href="/it/tutorials/file/filesystem/">Italiano</a></li>
<li><a href="/ja/tutorials/file/filesystem/">???</a></li>
<li><a href="/ru/tutorials/file/filesystem/">P??????</a></li>
<li><a href="/zh/tutorials/file/filesystem/">?? (??)</a></li>
</ul>
</nav>
</header>
<div class="body-content">
<section class="title">
<section class="title-text container">
<h1>ka6/ko/index.html</h1>
<a href="/en/" class="watermark">HTML5 Rocks</a>
</section>
</section>
<article class="content-wrapper">
<section class="container">
<div class="article-meta" id="article-meta">
<nav class="toc">
<h1>toc</h1>
<ul>
<li><a href='#toc-introduction'>Introduction</a></li>
<li><a href='#toc-requesting'>Requesting a file system</a></li>
<li><a href='#toc-file'>Working with files</a></li>
<li><a href='#toc-dir'>Working with directories</a></li>
<li><a href='#toc-copy-rename-move'>Copying, renaming, and moving</a></li>
<li><a href='#toc-filesystemurls'>filesystem: URLs</a></li>
<li><a href='#toc-dir-fullexample'>Putting it all together</a></li>
<li><a href='#toc-usecases'>Use Cases</a></li>
<li><a href='#toc-references'>Reference specifications</a></li>
</ul>
</nav>
<aside class="localizations">
<h1>Loc</h1>
<ul>
<li><a href="/de/tutorials/file/filesystem/">Deutsch</a></li>
<li><a href="/it/tutorials/file/filesystem/">Italiano</a></li>
<li><a href="/ja/tutorials/file/filesystem/">???</a></li>
<li><a href="/ru/tutorials/file/filesystem/">P??????</a></li>
<li><a href="/zh/tutorials/file/filesystem/">?? (??)</a></li>
<li><a href="https://github.com/html5rocks/www.html5rocks.com/blob/master/CONTRIBUTING.md">Contribute another</a></li>
</ul>
</aside>
</div>
<div class="content" id="article-content">
<section class="byline">
<div class="byline-content">
<section class="author-images">
<a href="/profiles/#ericbidelman">
<img src="/static/images/profiles/ericbidelman.png" itemprop="photo" alt="Eric Bidelman" title="Eric Bidelman">
</a>
</section>
<section class="meta">
<div class="authors">
<strong>By</strong> <a href="/profiles/#ericbidelman">Eric Bidelman</a>
</div>
<div class="date">
<time pubdate><strong>Published:</strong> January 4th, 2011</time>
<time class="updated"><strong>Updated:</strong> July 30th, 2013</time>
<span><strong>Comments:</strong> <a href="#disqus_thread" class="load-comments" data-disqus-identifier="http://www.html5rocks.com/tutorials/file/filesystem/">0</a></span>
</div>
<div id="notcompatible" class="hidden">
Your browser may not support the functionality in this article.
</div>
</section>
<div class="clear"></div>
</div>
</section>
<p>The API is broken up into various themes:</p>
<ul>
<li>Reading and manipulating files:
<code>File</code>/<code>Blob</code>, <code>FileList</code>, <code>FileReader</code></li>
<li>Creating and writing:
<code>Blob()</code>, <code>FileWriter</code></li>
<li>Directories and file system access:
<code>DirectoryReader</code>, <code>FileEntry</code>/<code>DirectoryEntry</code>, <code>LocalFileSystem</code>
</li>
</ul>
<h3 id="toc-support">Browser support & storage limitations</h3>
<h2 id="toc-requesting">Requesting a file system</h2>
<pre class="prettyprint">
// Note: The file system has been prefixed as of Google Chrome 12:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(<var>type</var>, <var>size</var>, <var>successCallback</var>, <var>opt_errorCallback</var>)
</pre>
<p>Example usage:</p>
<pre class="prettyprint">
function onInitFs(fs) {
console.log('Opened file system: ' + fs.name);
}
<b>window.requestFileSystem</b>(<b>window.TEMPORARY</b>, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
</pre>
<pre class="prettyprint">
function errorHandler(e) {
var msg = '';
switch (e.code) {
case <b>FileError.QUOTA_EXCEEDED_ERR</b>:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case <b>FileError.NOT_FOUND_ERR</b>:
msg = 'NOT_FOUND_ERR';
break;
case <b>FileError.SECURITY_ERR</b>:
msg = 'SECURITY_ERR';
break;
case <b>FileError.INVALID_MODIFICATION_ERR</b>:
msg = 'INVALID_MODIFICATION_ERR';
break;
case <b>FileError.INVALID_STATE_ERR</b>:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
console.log('Error: ' + msg);
}
</pre>
<pre class="prettyprint">
window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
window.requestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, function(e) {
console.log('Error', e);
});
</pre>
<p id="toc-fileentry">Properties and methods of <code>FileEntry</code>:</p>
<pre class="prettyprint">
fileEntry.isFile === true
fileEntry.isDirectory === false
fileEntry.name
fileEntry.fullPath
...
fileEntry.getMetadata(successCallback, opt_errorCallback);
fileEntry.remove(successCallback, opt_errorCallback);
fileEntry.moveTo(dirEntry, opt_newName, opt_successCallback, opt_errorCallback);
fileEntry.copyTo(dirEntry, opt_newName, opt_successCallback, opt_errorCallback);
fileEntry.getParent(successCallback, opt_errorCallback);
fileEntry.toURL(opt_mimeType);
fileEntry.file(successCallback, opt_errorCallback);
fileEntry.createWriter(successCallback, opt_errorCallback);
...
</pre>
<p>The following code creates an empty file called "log.txt" in the root of the app's file system:</p>
<pre class="prettyprint">
function onInitFs(fs) {
<b>fs.root.getFile</b>('log.txt', <b>{create: true, exclusive: true}</b>, function(fileEntry) {
// fileEntry.name == 'log.txt'
// fileEntry.fullPath == '/log.txt'
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
</pre>
<h3 id="toc-file-readingbyname">Reading a file by name</h3>
<pre class="prettyprint">
function onInitFs(fs) {
<b>fs.root.getFile</b>('log.txt', {}, function(fileEntry) {
// Get a File object representing the file,
// then use FileReader to read its contents.
fileEntry.<b>file</b>(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
</pre>
<h3 id="toc-file-writing">Writing to a file</h3>
<p>The following code creates an empty file called "log.txt" (if it doesn't exist)
and fills it with the text 'Lorem Ipsum'.</p>
<pre class="prettyprint">
function onInitFs(fs) {
<b>fs.root.getFile</b>('log.txt', <b>{create: true}</b>, function(fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
<b>fileEntry.createWriter</b>(function(fileWriter) {
<b>fileWriter.onwriteend</b> = function(e) {
console.log('Write completed.');
};
<b>fileWriter.onerror</b> = function(e) {
console.log('Write failed: ' + e.toString());
};
// Create a new Blob and write it to log.txt.
var blob = new Blob(['Lorem Ipsum'], {type: 'text/plain'});
<b>fileWriter.write</b>(blob);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
</pre>
<p>This time, we call the FileEntry's <code>createWriter()</code> method to
obtain a <code>FileWriter</code> object. Inside the success callback, event
handlers are set up for <code>error</code> and <code>writeend</code> events.
The text data is written to the file by creating a blob, appending text to it,
and passing the blob to <code>FileWriter.write()</code>.</p>
<h3 id="toc-file-appending">Appending data to a file</h3>
<p>The following code appends the text 'Hello World' to the end of our log file.
An error is thrown if the file does not exist.</p>
<pre class="prettyprint">
function onInitFs(fs) {
<b>fs.root.getFile</b>('log.txt', <b>{create: false}</b>, function(fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function(fileWriter) {
<b>fileWriter.seek(fileWriter.length); // Start write position at EOF.</b>
// Create a new Blob and write it to log.txt.
var blob = new Blob(['Hello World'], {type: 'text/plain'});
<b>fileWriter.write</b>(blob);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
</pre>
<h3 id="toc-file-user-selected">Duplicating user-selected files</h3>
<p>The following code allows a user to select multiple files using
<code><input type="file" multiple /></code> and creates copies of those
files in the app's sandboxed file system.</p>
<pre class="prettyprint"><input type="file" id="myfile" <b>multiple</b> /></pre>
<pre class="prettyprint">
document.querySelector('#myfile').onchange = function(e) {
var files = <b>this.files</b>;
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
// Duplicate each file the user selected to the app's fs.
for (var i = 0, file; file = files[i]; ++i) {
// Capture current iteration's file in local scope for the getFile() callback.
(function(f) {
fs.root.getFile(<b>f.name</b>, {create: true, exclusive: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
<b>fileWriter.write(f);</b> // Note: write() can take a File or Blob object.
}, errorHandler);
}, errorHandler);
})(file);
}
}, errorHandler);
};
</pre>
<p>Although we've used an input for the file import, one could easily leverage
<a href="/tutorials/dnd/basics/#toc-desktop-dnd-into">HTML5 Drag and Drop</a>
to achieve the same objective.</p>
<p>As noted in the comment, <code>FileWriter.write()</code> can accept a <code>Blob</code>
or <code>File</code>. This is because <code>File</code> inherits from <code>Blob</code>.
Therefore, all file objects are blobs.</p>
<h3 id="toc-file-removing">Removing a file</h3>
<p>The following code deletes the file 'log.txt'.</p>
<pre class="prettyprint">
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getFile('log.txt', {create: false}, function(fileEntry) {
<b>fileEntry.remove(function() {
console.log('File removed.');
}, errorHandler);</b>
}, errorHandler);
}, errorHandler);
</pre>
<h2 id="toc-dir">Working with directories</h2>
<p>Directories in the sandbox are represented by the
<a href="http://dev.w3.org/2009/dap/file-system/pub/FileSystem/#the-directoryentry-interface"><code>DirectoryEntry</code></a>
interface, which shares most of <a href="#toc-fileentry">FileEntry</a>'s properties
(they inherit from a common <code>Entry</code> interface). However, <code>DirectoryEntry</code>
has additional methods for manipulating directories.</p>
<p>Properties and methods of <code>DirectoryEntry</code>:</p>
<pre class="prettyprint">
dirEntry.isDirectory === true
// See the section on <a href="#toc-fileentry">FileEntry</a> for other inherited properties/methods.
...
var dirReader = dirEntry.createReader();
dirEntry.getFile(path, opt_flags, opt_successCallback, opt_errorCallback);
dirEntry.getDirectory(path, opt_flags, opt_successCallback, opt_errorCallback);
dirEntry.removeRecursively(successCallback, opt_errorCallback);
...
</pre>
<h3 id="toc-dir-creating">Creating directories</h3>
<p>Use the <code>getDirectory()</code> method of <code>DirectoryEntry</code>
to read or create directories. You can pass either a name or path as
the directory to look up or create.</p>
<p>For example, the following code creates a directory named "MyPictures" in the
root directory:</p>
<pre class="prettyprint">
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.<b>getDirectory</b>('MyPictures', {create: true}, function(dirEntry) {
...
}, errorHandler);
}, errorHandler);
</pre>
<h3 id="toc-dir-subirs">Subdirectories</h3>
<p>Creating a subdirectory is exactly the same as creating any other directory. However,
the API throws an error if you attempt to create a directory whose immediate
parent does not exist. The solution is to create each directory sequentially, which
is rather tricky to do with an asynchronous API.</p>
<p>The following code creates a new hierarchy (music/genres/jazz) in the
root of the app's FileSystem by recursively adding each subdirectory after its
parent folder has been created.</p>
<pre class="prettyprint">
var path = 'music/genres/jazz/';
function createDir(rootDirEntry, folders) {
// Throw out './' or '/' and move on to prevent something like '/foo/.//bar'.
if (folders[0] == '.' || folders[0] == '') {
folders = folders.slice(1);
}
rootDirEntry.<b>getDirectory</b>(folders[0], <b>{create: true}</b>, function(dirEntry) {
// Recursively add the new subfolder (if we still have another to create).
if (folders.length) {
createDir(dirEntry, folders.slice(1));
}
}, errorHandler);
};
function onInitFs(fs) {
createDir(fs.root, path.split('/')); // fs.root is a DirectoryEntry.
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
</pre>
<p>Now that "music/genres/jazz" is in place, we can pass its full path
to <code>getDirectory()</code> and create new subfolders or files under it.
For example:</p>
<pre class="prettyprint">
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getFile('/music/genres/jazz/song.mp3', {create: true}, function(fileEntry) {
...
}, errorHandler);
}, errorHandler);
</pre>
<h3 id="toc-dir-reading">Reading a directory's contents</h3>
<p>To read the contents of a directory, create a <code>DirectoryReader</code>
and call its <code>readEntries()</code> method. There is no
guarantee that all of a directory's entries will be returned
in a single call to <code>readEntries()</code>. That means you need to keep calling
<code>DirectoryReader.readEntries()</code> until no more results are returned.
The following is code that demonstrates this:</p>
<pre class="prettyprint"><ul id="filelist"></ul></pre>
<pre class="prettyprint">
function toArray(list) {
return Array.prototype.slice.call(list || [], 0);
}
function listResults(entries) {
// Document fragments can improve performance since they're only appended
// to the DOM once. Only one browser reflow occurs.
var fragment = document.createDocumentFragment();
entries.forEach(function(entry, i) {
var img = <b>entry.isDirectory</b> ? '<img src="folder-icon.gif">' :
'<img src="file-icon.gif">';
var li = document.createElement('li');
li.innerHTML = [img, '<span>', entry.name, '</span>'].join('');
fragment.appendChild(li);
});
document.querySelector('#filelist').appendChild(fragment);
}
function onInitFs(fs) {
var dirReader = <b>fs.root.createReader()</b>;
var entries = [];
// Call the reader.readEntries() until no more results are returned.
var readEntries = function() {
<b>dirReader.readEntries </b>(function(results) {
if (!results.length) {
listResults(entries.sort());
} else {
entries = entries.concat(toArray(results));
readEntries();
}
}, errorHandler);
};
readEntries(); // Start reading dirs.
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
</pre>
<h3 id="toc-dir-removing">Removing a directory</h3>
<p>The <code>DirectoryEntry.remove()</code> method behaves just like
<a href="#toc-file-removing"><code>FileEntry</code></a>'s. The difference:
attempting to delete a non-empty directory results in an error.</p>
<p>The following removes the empty directory "jazz" from "/music/genres/":</p>
<pre class="prettyprint">
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getDirectory('music/genres/jazz', {}, function(dirEntry) {
<b>dirEntry.remove(function() {
console.log('Directory removed.');
}, errorHandler);</b>
}, errorHandler);
}, errorHandler);
</pre>
<h4 id="toc-dir-rremoving">Recursively removing a directory</h4>
<p>If you have a pesky directory that contains entries, <code>removeRecursively()</code>
is your friend. It deletes the directory and its contents, recursively.</p>
<p>The following code recursively removes the directory "music" and all the
files and directories that it contains:</p>
<pre class="prettyprint">
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getDirectory('/misc/../music', {}, function(dirEntry) {
<b>dirEntry.removeRecursively(function() {
console.log('Directory removed.');
}, errorHandler);</b>
}, errorHandler);
}, errorHandler);
</pre>
<h2 id="toc-copy-rename-move">Copying, renaming, and moving</h2>
<p><code>FileEntry</code> and <code>DirectoryEntry</code> share common operations.</p>
<h3 id="toc-dir-move-copy">Copying an entry</h3>
<p>Both <code>FileEntry</code> and <code>DirectoryEntry</code> have a
<code>copyTo()</code> for duplicating existing entries. This method automatically
does a recursive copy on folders.</p>
<p>The following code example copies the file "me.png" from one directory to another:</p>
<pre class="prettyprint">
function copy(cwd, src, dest) {
cwd.getFile(src, {}, function(fileEntry) {
cwd.getDirectory(dest, {}, function(dirEntry) {
<b>fileEntry.copyTo</b>(dirEntry);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
copy(fs.root, '/folder1/me.png', 'folder2/mypics/');
}, errorHandler);
</pre>
<h3 id="toc-dir-move-rename">Moving or renaming an entry</h3>
<p>The <code>moveTo()</code> method present in
<code>FileEntry</code> and <code>DirectoryEntry</code>
allows you to move or rename a file or directory.
Its first argument is the parent directory to move the file under, and its second
is an optional new name for the file. If a new name isn't provided, the file's
original name is used.</p>
<p>The following example renames "me.png" to "you.png", but does not move the file:</p>
<pre class="prettyprint">
function rename(cwd, src, newName) {
cwd.getFile(src, {}, function(fileEntry) {
<b>fileEntry.moveTo</b>(cwd, newName);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
rename(fs.root, 'me.png', 'you.png');
}, errorHandler);
</pre>
<p>The following example moves "me.png" (located in the root directory) to
a folder named "newfolder".</p>
<pre class="prettyprint">
function move(src, dirName) {
fs.root.getFile(src, {}, function(fileEntry) {
fs.root.getDirectory(dirName, {}, function(dirEntry) {
<b>fileEntry.moveTo</b>(dirEntry);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
move('/me.png', 'newfolder/');
}, errorHandler);
</pre>
<h2 id="toc-filesystemurls">filesystem: URLs</h2>
<p>The FileSystem API exposes a new URL scheme, <code>filesystem:</code>,
that can be used to fill <code>src</code> or <code>href</code> attributes.
For example, if you wanted to display an image and have its
<a href="http://dev.w3.org/2009/dap/file-system/pub/FileSystem/#the-fileentry-interface"><code>fileEntry</code></a>,
calling <code>toURL()</code> would give you the file's <code>filesystem:</code> URL:</p>
<pre class="prettyprint">
var img = document.createElement('img');
img.src = <b>fileEntry.toURL</b>(); // filesystem:http://example.com/temporary/myfile.png
document.body.appendChild(img);
</pre>
<p>Alternatively, if you already have a <code>filesystem:</code> URL,
<code>resolveLocalFileSystemURL()</code> will get you back the
<a href="http://dev.w3.org/2009/dap/file-system/pub/FileSystem/#the-fileentry-interface"><code>fileEntry</code></a>:</p>
<pre class="prettyprint">
window.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL ||
window.webkitResolveLocalFileSystemURL;
var url = 'filesystem:http://example.com/temporary/myfile.png';
<b>window.resolveLocalFileSystemURL</b>(url, function(fileEntry) {
...
});
</pre>
<h2 id="toc-dir-fullexample">Putting it all together</h2>
<h3 id="toc-samples-basic">Basic example</h3>
<p>This demo lists the files/folders in the filesystem.</p>
<iframe src="http://playground.html5rocks.com/?mode=frame&hu=180&hl=160#filesystem_apis" style="border: none; width: 100%; height: 460px;"></iframe>
<h3 id="toc-samples-terminal">HTML5 Terminal</h3>
<p>This shell replicates some of the common operations in a UNIX filesystem
(such as <code>cd</code>, <code>mkdir</code>, <code>rm</code>, <code>open</code>,
and <code>cat</code>) by abstracting the FileSystem API. To add content, open
the app, then drag and drop files from your desktop onto the terminal window.</p>
<!--<iframe id="terminal-iframe" src="terminal.html"></iframe>-->
<figure>
<a href="http://www.htmlfivewow.com/demos/terminal/terminal.html"target="_blank">
<img src="terminal.png" alt="Click to open the HTML5 Wow Terminal" title="Click to open the HTML5 Wow Terminal">
</a>
<figcaption>
<a href="http://www.htmlfivewow.com/demos/terminal/terminal.html"target="_blank">Open the HTML5 Terminal</a>
</figcaption>
</figure>
<h2 id="toc-usecases">Use Cases</h2>
<p>There are several <a href="/tutorials#offline,storage">storage options</a>
available in HTML5, but the FileSystem is different in that it aims to satisfy
client-side storage use cases not well served by databases. Generally, these
are applications that deal with large binary blobs and/or share data with
applications outside of the context of the browser.</p>
<p>The specification lists several use cases:</p>
<ol>
<li>Persistent uploader
<ul>
<li>When a file or directory is selected for upload, it copies the files
into a local sandbox and uploads a chunk at a time.</li>
<li>Uploads can be restarted after browser crashes, network interruptions, etc.</li>
</ul>
</li>
<li>Video game, music, or other app with lots of media assets
<ul>
<li>It downloads one or several large tarballs, and expands them locally
into a directory structure.</li>
<li>The same download works on any operating system.</li>
<li>It can manage prefetching just the next-to-be-needed assets in
the background, so going to the next game level or activating a new
feature doesn't require waiting for a download.</li>
<li>It uses those assets directly from its local cache, by direct
file reads or by handing local URIs to image or video tags, WebGL asset loaders, etc.</li>
<li>The files may be of arbitrary binary format.</li>
<li>On the server side, a compressed tarball will often be much
smaller than a collection of separately-compressed files. Also, 1
tarball instead of 1000 little files will involve fewer seeks, all
else being equal.</li>
</ul>
</li>
<li>Audio/Photo editor with offline access or local cache for speed
<ul>
<li>The data blobs are potentially quite large, and are read-write.</li>
<li>It may want to do partial writes to files (ovewriting just the
ID3/EXIF tags, for example).</li>
<li>The ability to organize project files by creating directories would be useful.</li>
<li>Edited files should be accessable by client-side applications [iTunes, Picasa].
</li></ul>
</li>
<li>Offline video viewer
<ul>
<li>It downloads large files (>1GB) for later viewing.</li>
<li>It needs efficient seek + streaming.</li>
<li>It must be able to hand a URI to the video tag.</li>
<li>It should enable access to partly-downloaded files e.g. to let
you watch the first episode of the DVD even if your download didn't
complete before you got on the plane.</li>
<li>It should be able to pull a single episode out of the middle of
a download and give just that to the video tag.</li>
</ul>
</li>
<li>Offline Web Mail Client
<ul>
<li>Downloads attachments and stores them locally.</li>
<li>Caches user-selected attachments for later upload.</li>
<li>Needs to be able to refer to cached attachments and image
thumbnails for display and upload.</li>
<li>Should be able to trigger the UA's download manager just as if
talking to a server.</li>
<li>Should be able to upload an email with attachments as a
multipart post, rather than sending a file at a time in an XHR.</li>
</ul>
</li>
</ol>
<h2 id="toc-references">Reference specifications</h2>
<ul>
<li><a href="http://dev.w3.org/2009/dap/file-system/pub/FileSystem/">FileSystem</a></li>
<li><a href="http://dev.w3.org/2009/dap/file-system/file-writer.html">FileWriter</a></li>
<li><a href="http://dev.w3.org/2006/webapi/FileAPI/#dfn-filereader">FileReader</a></li>
<li><a href="http://dev.w3.org/2006/webapi/FileAPI/">File</a></li>
<li><a href="http://dev.w3.org/2006/webapi/FileAPI/#dfn-Blob">Blob</a></li>
</ul>
</div>
</section>
</article>
<section class="disqus pattern-bg-lighter">
<div id="disqus" class="container">
<h2>Comments</h2>
<div id="disqus_thread">
<a href="#disqus_thread" class="load-comments" data-disqus-identifier="http://www.html5rocks.com/tutorials/file/filesystem/">0</a>
</div>
</div>
<noscript>
<p class="center">
<strong>
<a href="http://disqus.com/?ref_noscript">Please enable JavaScript to view the comments powered by Disqus.</a>
</strong>
</p>
</noscript>
<script>
var disqus_shortname = 'html5rocks';
var disqus_identifier = 'http://www.html5rocks.com/tutorials/file/filesystem/';
var disqus_url = 'http://www.html5rocks.com/tutorials/file/filesystem/';
var disqus_developer = 0;
var disqus_config = function () {
var funky_language_code_mapping = {
'de': 'de_inf',
'es': 'es_ES',
'pt': 'pt_EU',
'sr': 'sr_CYRL',
'sv': 'sv_SE',
'zh': 'zh_HANT'
};
this.language = funky_language_code_mapping['en'] ||
'en';
this.callbacks.onReady = [ function () {
try {
ga('send', 'event', 'View comments');
} catch(err){}
} ];
this.callbacks.onNewComment = [ function (comment) {
try {
ga('send', 'event', 'Commented');
} catch(err){}
} ];
};
window.addEventListener('load', function(e) {
var c = document.createElement('script');
c.type = 'text/javascript';
c.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
c.async = true;
var s = document.getElementsByTagName('script')[0], sp = s.parentNode;
sp.insertBefore(c, s);
if (window.location.hash === '#disqus_thread')
loadComments();
}, false);
var disqus_loaded = false;
function loadComments() {
if (disqus_loaded)
return;
disqus_loaded = true;
ga('send', 'event', 'Interactions', 'Comments', 'Comments Loaded');
var s = document.getElementsByTagName('script')[0], sp = s.parentNode;
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
var disqusContainer = document.getElementById('disqus');
disqusContainer.classList.add('active');
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
sp.insertBefore(dsq, s);
}
function outgoing(url) {
try {
ga('send', 'event', 'Outbound Links' , url);
} catch(err){}
}
// Open external links (also that don't have a target defined) in a new tab.
var externLinks = document.querySelectorAll('article.tutorial a[href^="http"]:not([target])');
for(var i = 0, a; a = externLinks[i]; ++i) {
a.target = '_blank';
a.addEventListener('click', new Function('outgoing(' + '"' + a.href.replace(/.*?:\/\//g, "") + '"' + ');'));
}
var loadCommentsButtons = document.querySelectorAll('.load-comments');
for(var l = 0; l < loadCommentsButtons.length; l++)
loadCommentsButtons[l].addEventListener('click', loadComments);
</script>
</section>
<footer>
<div class="container">
<h1>Next steps</h2>
<aside class="panel share">
<h2>Share</h2>
<a href="https://twitter.com/share?url=http://www.html5rocks.com/tutorials/file/filesystem/&text=Exploring the FileSystem APIs&lang=en&via=ChromiumDev&related=ChromiumDev" class="twitter" target="_blank">Twitter</a>
<a href="https://www.facebook.com/sharer/sharer.php?u=http://www.html5rocks.com/tutorials/file/filesystem/" class="facebook" target="_blank">Facebook</a>
<a href="https://plus.google.com/share?url=http://www.html5rocks.com/tutorials/file/filesystem/" class="gplus" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;">Google+</a>
</aside>
<aside class="panel rss">
<h2>Subscribe</h2>
<p>Enjoyed this article? Grab the <a href="http://feeds.feedburner.com/html5rocks">RSS feed</a> and stay up-to-date.</p>
</aside>
<p class="licensing">
Except as otherwise <a href="http://code.google.com/policies.html#restrictions">noted</a>, the content of this page is licensed under the <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License</a>, and code samples are licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>.
</p>
</div>
</footer>
<script>
window.isCompatible = function() {
return !!(window.requestFileSystem || window.webkitRequestFileSystem);
};
if (isCompatible() === false) {
document.getElementById('notcompatible').className = '';
}
function _prettyPrint() {
if (typeof customPrettyPrintLanguage != 'undefined') {
customPrettyPrintLanguage();
}
prettyPrint();
}
</script>
<script async src="/static/js/prettify.min.js" onload="_prettyPrint()"></script>
<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-MB3LRF');</script>
<!-- End Google Tag Manager -->
</div>
<script>
(function() {
// Kill feedburner and marketing tracking arguments, but let them register
// before we do it.
setTimeout(function() {
if (/^\?utm_/.test(document.location.search) &&
window.history.replaceState) {
window.history.replaceState(
{}, '', document.location.href.replace(/\?utm_.*/, ''));
}
}, 2000);
var siteHeader = document.getElementById('siteheader');
var navToggle = document.getElementById('navtoggle');
var siteNav = document.getElementById('sitenav');
function toggle(target, forceActive) {
if (typeof toc !== 'undefined') {
// Switch off whichever one is not the
// current target
if (target === toc)
siteNav.classList.remove('active');
else
toc.classList.remove('active');
}
// Toggle if no force parameter is set
if (typeof forceActive === 'undefined') {
target.classList.toggle('active');
} else {
if (forceActive)
target.classList.add('active');
else
target.classList.remove('active');
}
// now find out what the set state ended up being
var isActive = target.classList.contains('active');
if (isActive)
siteHeader.classList.add('expanded');
else
siteHeader.classList.remove('expanded');
}
navToggle.addEventListener('click', function(e) {
toggle(siteNav);
e.preventDefault();
});
var tocToggle = document.getElementById('toctoggle');
var toc = document.getElementById('toc');
var articleMeta = document.getElementById('article-meta');
var articleContent = document.getElementById('article-content');
var articleMetaHeight = 0;
var articleMetaMaxY = 0;
var articleMetaMinY = 0;
var articleContentPadding = 200;
var tocLinks = document.querySelectorAll('.toc a');
for (var t = 0; t < tocLinks.length; t++)
tocLinks[t].addEventListener('click', onTocLinkClick);
tocToggle.addEventListener('click', function(e) {
toggle(toc);
e.preventDefault();
});
toc.addEventListener('click', function(e) {
if (e.target !== siteNav)
toggle(toc, false);
});
function onTocLinkClick() {
ga('send', 'event', 'Interactions', 'TOC', 'TOC Clicked');
}
function setMinScrollYFromMetaY() {
var scrollPosition = window.scrollY;
var articleMetaBounds = articleMeta.getBoundingClientRect();
var articleMetaTop = Math.max(352,
articleMetaBounds.top - 20 + scrollPosition);
articleMetaHeight = articleMetaBounds.bottom - articleMetaBounds.top;
articleMetaMinY = articleMetaTop;
}
function setMaxScrollYFromContentHeight() {
var scrollPosition = window.scrollY;
var articleContentBounds = articleContent.getBoundingClientRect();
var articleContentTop = articleContentBounds.top + scrollPosition;
var articleContentHeight = articleContentBounds.bottom - articleContentBounds.top;
articleMetaMaxY = articleContentTop +
articleContentHeight -
articleMetaHeight -
articleContentPadding;
}
function onScroll(e) {
if (window.scrollY >= articleMetaMinY) {
articleMeta.classList.add('sticky');
var articleMetaTop = 22 - Math.max(0, window.scrollY - articleMetaMaxY);
articleMeta.style.top = articleMetaTop + 'px';
} else {
articleMeta.classList.remove('sticky');
articleMeta.style.top = 'auto';
}
}
if (articleMeta.getBoundingClientRect) {
setMinScrollYFromMetaY();
setMaxScrollYFromContentHeight();
document.addEventListener('scroll', onScroll);
window.addEventListener('load', setMaxScrollYFromContentHeight, false);
}
})();
</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-15028909-1', 'auto');
ga('create', 'UA-49880327-4', 'auto', {'name': 'html5rocks'});
ga('send', 'pageview');
ga('html5rocks.send', 'pageview');
</script>
<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-MB3LRF');</script>
<!-- End Google Tag Manager -->
</body>
</html>
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer