> [!CAUTION]
> **Important:** Chrome will be removing support for Chrome Apps on all platforms. Chrome browser and the Chrome Web Store will continue to support extensions. [**Read the announcement**](https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html) and learn more about [**migrating your app**](https://developer.chrome.com/apps/migration).

> [!NOTE]
> **Note:** **Want to start fresh from here?** Find the previous step's code in the [reference code zip](https://github.com/mangini/io13-codelab/archive/master.zip) under ***cheat_code \> solution_for_step5***.

In this step, you will learn:

- How to get a reference to a file in the external filesystem.
- How to write to the filesystem.

*Estimated time to complete this step: 20 minutes.*   

To preview what you will complete in this step, [jump down to the bottom of this page ↓](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#launch).

## Export todos

This step adds an export button to the app. When clicked, the current todo items are saved to a text
file selected by the user. If the file exists, it's replaced. Otherwise, a new file gets created.

### Update permissions

File system permissions can be requested as a string for read-only access, or an Object with
additional properties. For example:

```javascript
// Read only
"permissions": ["fileSystem"]

// Read and write
"permissions": [{"fileSystem": ["write"]}]

// Read, write, autocomplate previous input, and select folder directories instead of files
"permissions": [{"fileSystem": ["write", "retainEntries", "directory"]}]
```

You need read and write access. In *manifest.json* , request the `{fileSystem: [ "write" ] }`
permission:

    "permissions": [
      "storage", 
      "alarms", 
      "notifications", 
      "webview",
      "<all_urls>", 
      { "fileSystem": ["write"] } 
    ],

### Update HTML view

In *index.html* , add an **Export to disk** button and a `div` where the app shows a status message:

    <footer id="info">
      <button id="toggleAlarm">Activate alarm</button>
      <button id="exportToDisk">Export to disk</button>
      <div id="status"></div>
      ...
    </footer>

Also in *index.html* , load the *export.js* script:

    ...
    <script src="js/alarms.js"></script>
    <script src="js/export.js"></script>

### Create export script

Create a new JavaScript file named *export.js* using the code below. Save it in the *js* folder.

```javascript
(function() {

  var dbName = 'todos-vanillajs';

  var savedFileEntry, fileDisplayPath;

  function getTodosAsText(callback) {
  }

  function exportToFileEntry(fileEntry) {
  }

  function doExportToDisk() {
  }

  document.getElementById('exportToDisk').addEventListener('click', doExportToDisk);

})();
```

Right now, *export.js* only contains a click listener on the **Export to disk** button and stubs for
`getTodosAsText()`, `exportToFileEntry`, and `doExportToDisk()`.

### Get todo items as text

Update `getTodosAsText()` so that it reads todos from `chrome.storage.local` and generates a textual
representation of them:

```javascript
function getTodosAsText(callback) {
  chrome.storage.local.get(dbName, function(storedData) {
    var text = '';

    if ( storedData[dbName].todos ) {
      storedData[dbName].todos.forEach(function(todo) {
          text += '- ';
          if ( todo.completed ) {
            text += '[DONE] ';
          }
          text += todo.title;
          text += '\n';
        }, '');
    }

    callback(text);

  }.bind(this));
}
```

### Choose a file

Update `doExportToDisk()` with [`chrome.fileSystem.chooseEntry()`](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-chooseEntry) to allow the user to choose a
file:

```javascript
function doExportToDisk() {

  if (savedFileEntry) {

    exportToFileEntry(savedFileEntry);

  } else {

    chrome.fileSystem.chooseEntry( {
      type: 'saveFile',
      suggestedName: 'todos.txt',
      accepts: [ { description: 'Text files (*.txt)',
                   extensions: ['txt']} ],
      acceptsAllTypes: true
    }, exportToFileEntry);

  }
}
```

The first parameter of `chrome.fileSystem.chooseEntry()` is an object of options. The second
parameter is a callback method.

If there's already a saved `FileEntry`, use that instead when calling `exportToFileEntry()`. File
references exist for the lifetime of the object representing the `FileEntry`. This example ties
`FileEntry` to the app window so the JavaScript code can write to the selected file without any user
interaction as long as the app window remains open.

### Use FileEntry to write todos items to disk

Update `exportToFileEntry()` to save the todos as text via the `FileEntry` Web API:

```javascript
function exportToFileEntry(fileEntry) {
  savedFileEntry = fileEntry;

  var status = document.getElementById('status');

  // Use this to get a file path appropriate for displaying
  chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
    fileDisplayPath = path;
    status.innerText = 'Exporting to '+path;
  });

  getTodosAsText( function(contents) {

    fileEntry.createWriter(function(fileWriter) {

      var truncated = false;
      var blob = new Blob([contents]);

      fileWriter.onwriteend = function(e) {
        if (!truncated) {
          truncated = true;
          // You need to explicitly set the file size to truncate
          // any content that might have been there before
          this.truncate(blob.size);
          return;
        }
        status.innerText = 'Export to '+fileDisplayPath+' completed';
      };

      fileWriter.onerror = function(e) {
        status.innerText = 'Export failed: '+e.toString();
      };

      fileWriter.write(blob);

    });
  });
}
```

[`chrome.fileSystem.getDisplayPath()`](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-getDisplayPath) gets a displayable file path that outputs to the status
`div`.

Use `fileEntry.createWriter()` to create a `FileWriter` object. `fileWriter.write()` can then write
a [Blob](https://developer.mozilla.org/docs/Web/API/Blob) to the filesystem. Use `fileWriter.onwriteend()` and `fileWriter.onerror()` to update
the status `div`.

For more information about `FileEntry`, read [*Exploring the FileSystem APIs*](http://www.html5rocks.com/en/tutorials/file/filesystem/) on HTML5Rocks, or
refer to the [`FileEntry docs`](https://developer.mozilla.org/docs/Web/API/FileEntry) on MDN.

### Persist FileEntry objects

**Advanced** : `FileEntry` objects cannot be persisted indefinitely. Your app needs to ask the user
to choose a file every time the app is launched. If your app was forced to restart due to a runtime
crash or update, [restoreEntry()](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-restoreEntry) is an option to restore a `FileEntry`.

If you wish, experiment by saving the ID returned by [retainEntry()](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-retainEntry) and restoring it on app
restart. (Hint: Add a listener to the `onRestarted` event in the background page.)

## Launch your finished Todo app

You are done Step 6! Reload your app and add some todos. Click **Export to disk** to export your
todos to a .txt file.

![The Todo app with exported todos](https://developer.chrome.com/static/docs/apps/app_codelab_filesystem/image/the-todo-app-exported-to-efd98a15ffaf8.png)

## For more information

For more detailed information about some of the APIs introduced in this step, refer to:

- [Using the Chrome Filesystem API](https://developer.chrome.com/docs/apps/app_storage.md.txt#filesystem "Read 'Using the Chrome Filesystem API' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#export-todos "This feature mentioned in 'Export todos'")
- [Declare Permissions](https://developer.chrome.com/apps/declare_permissions "Read 'Declare Permissions' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#update-permissions "This feature mentioned in 'Update permissions'")
- [chrome.storage.local.get()](https://developer.chrome.com/apps/storage#method-StorageArea-get "Read 'chrome.storage.local.get()' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#get-todos-as-text "This feature mentioned in 'Get todo items as text'")
- [chrome.fileSystem.chooseEntry()](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-chooseEntry "Read 'chrome.fileSystem.chooseEntry()' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#choose-file "This feature mentioned in 'Choose a file'")
- [chrome.fileSystem.getDisplayPath()](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-getDisplayPath "Read 'chrome.fileSystem.getDisplayPath()' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#use-fileentry "This feature mentioned in 'Use FileEntry to write todos items to disk'")
- [chrome.fileSystem.restoreEntry()](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-restoreEntry "Read 'chrome.fileSystem.restoreEntry()' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#persistance "This feature mentioned in 'Persist FileEntry objects'")
- [chrome.fileSystem.retainEntry()](https://developer.chrome.com/docs/apps/reference/fileSystem.md.txt#method-retainEntry "Read 'chrome.fileSystem.retainEntry()' in the Chrome developer docs") [↑](https://developer.chrome.com/docs/apps/app_codelab_filesystem.md.txt#persistance "This feature mentioned in 'Persist FileEntry objects'")

Ready to continue onto the next step? Go to [Step 7 - Publish your app \>\>](https://developer.chrome.com/docs/app_codelab_publish)