OS.File.DirectoryIterator for the main thread

  • Revision slug: JavaScript_OS.File/OS.File.DirectoryIterator_for_the_main_thread
  • Revision title: OS.File.DirectoryIterator for the main thread
  • Revision id: 447721
  • Created:
  • Creator: kscarfone
  • Is current revision? No
  • Comment Editorial review

Revision Content

This document presents the mechanisms for walking the contents of a directory from the main thread. For other uses of OS.File and OS.File.DirectoryIterator, please see the main document on OS.File.

Using OS.File.DirectoryIterator

Example: Finding the subdirectories of a directory using an iterator (TBD)

The following snippet walks through the content of a directory, selecting subdirectories:

// Open iterator
let iterator = new OS.File.DirectoryIterator(somePath);
let subdirs = [];
// Iterate through the directory
let promise = iterator.forEach(
  function onEntry(entry) {
    if (entry.isDir) {
      subdirs.push(entry);
    }
  }
);

// Finally, close the iterator
promise.then(
  function onSuccess() {
    iterator.close();
    return subdirs;
  },
  function onFailure(reason) {
    iterator.close();
    throw reason;
  }
);

Or a variant using Task.js (or at least the subset already present on mozilla-central):

Task.spawn(function() {
  let iterator = new OS.File.DirectoryIterator(somePath);
  let subdirs = [];
  // Loop through all entries
  // (the loop ends with an exception).
  while (true) {
    let entry = yield iterator.next();
    subdirs.push(entry);
  }
}).then(
  null,
  // Finally, clean up
  function onFailure(reason) {
    iterator.close();
    if (reason != StopIteration) {
      throw reason;
    }
  }
);

Example: Sorting files by last modification date

The following takes advantage of feature detection to minimize file I/O:

let iterator = new OS.File.DirectoryIterator(somePath);
let entries = [];
let promise = iterator.forEach(
  function onEntry(entry) {
    if ("winLastWriteDate" in entry) {
      // Under Windows, additional information allows us to sort files immediately
      // without having to perform additional I/O.
      entries.push({entry: entry, creationDate: entry.winCreationDate});
    } else {
      // Under other OSes, we need to call OS.File.stat
      return OS.File.stat(entry.path).then(
        function onSuccess(info) {
          entries.push({entry:entry, creationDate: info.creationDate});
        }
      );
    }
  }
);
promise.then(
  function onSuccess() {
    // Close the iterator, sort the array, return it
    iterator.close();
    return entries.sort(function compare(a, b) {
      return a.creationDate - b.creationDate;
    });
  },
  function onFailure(reason) {
     // Close the iterator, propagate any error
    iterator.close();
    throw reason;
  }
);

Or a variant using Task.js (or at least the subset already present on mozilla-central):

let iterator = new OS.File.DirectoryIterator(somePath);
let entries = [];
Task.spawn(function(){
  while (true) {
    let entry = yield iterator.next();
    if ("winLastWriteDate" in entry) {
      // Under Windows, additional information allows us to sort files immediately
      // without having to perform additional I/O.
      entries.push({entry: entry, creationDate: entry.winCreationDate});
    } else {
      // Under other OSes, we need to call OS.File.stat
      let info = yield OS.File.stat(entry.path);
      entries.push({entry:entry, creationDate: info.creationDate});
    }
  }
}).then(
  null,
  // Clean up and return
  function onFailure(reason) {
    iterator.close();
    if (reason != StopIteration) {
      throw reason;
    }
    return entries.sort(function compare(a, b) {
      return a.creationDate - b.creationDate;
    });
  }
);

Instances of OS.File.DirectoryIterator

General remark

Instances of OS.File.DirectoryIterator use valuable system resources – typically the same resources as files. There is a limit to the total number of files and directory iterators that can be open at any given time. Therefore, you should make sure that these resources are released as early as possible. To do this, you should use method close().

Constructor

OS.File.DirectoryIterator(
  in string path,
  [optional] in object options
) throws OS.File.Error
Arguments
path
The complete path to a directory.
options
An object that may contain the following fields:
winPattern
(ignored on non-Windows platforms) This option accepts a pattern such as "*.exe" or "*.txt". The iterator will only display items whose name matches this pattern.

Method overview

promise<void> close()
promise<void> forEach(in function callback)
promise<Array> nextBatch([optional] in number length)
promise<Entry> next()

Methods

close()

Close the iterator, releasing the system resources it uses.

promise<void> close()

You should always call this method once you are done with an iterator. Calling this method several times is harmless. Calling this method while iterating through the directory is harmless but will stop the iteration.

Promise resolves to

Nothing – once the resources have been released.

forEach()

Walk through the iterator

promise<void> forEach(
  in function callback
)
Arguments
Promise resolves to

Nothing - once the loop is complete

Promise rejects to

 

Promise-based loop

Iteration takes place sequentially: the callback is called with the first file, then once the callback is complete with the second file, etc.

It is often quite useful to be able to return a promise. If the callback returns a promise, the loop continues only once the callback is resolved.

If any of the callbacks throws an error or rejects a promise, the loop is stopped and rejects with the same error.
callback
A function. It will be applied to each entry in the directory successively, with the following arguments:
entry
An instance of OS.File.DirectoryIterator.Entry.
index
The index of the entry in the enumeration.
iterator
The iterator itself. You may stop the iteration by calling iterator.close().
OS.File.Error
In case of I/O error.
Anything else
In case one of the callbacks throws an error or rejects.

nextBatch()

Return several entries at once.

promise<array> nextBatch(
  [optional] in number entries
)
Arguments
entries
The number of entries to return at once. If unspecified, all entries.
Promise resolves to

An array containing entries entries, or less if there are not enough entries left in the directory. Once iteration is complete, calls to nextBatch return the empty array.

Performance note

In some circumstances, you may wish to use this method instead of forEach or next for performance reasons, as it limits the number of synchronizations between threads.

next()

Return the next entry in the directory.

promise<Entry> next()
Promise resolves to

The next entry in the directory.

Promise rejects to
OS.File.Error
In case of file error.
StopIteration
If the method is called after the last entry has been returned. Note that this is the constant StopIteration, not a constructor.

Revision Source

<p>This document presents the mechanisms for walking the contents of a directory <em>from the main thread</em>. For other uses of OS.File and OS.File.DirectoryIterator, please see the <a href="/en-US/docs/JavaScript_OS.File" title="/en-US/docs/JavaScript_OS.File">main document on OS.File</a>.</p>
<h2 id="Using_OS.File.DirectoryIterator">Using OS.File.DirectoryIterator</h2>
<h3 id="Example.3A_Finding_the_subdirectories_of_a_directory_using_an_iterator_(TBD)">Example: Finding the subdirectories of a directory using an iterator (TBD)</h3>
<p>The following snippet walks through the content of a directory, selecting subdirectories:</p>
<pre>
// Open iterator
let iterator = new OS.File.DirectoryIterator(somePath);
let subdirs = [];
// Iterate through the directory
let promise = iterator.forEach(
  function onEntry(entry) {
    if (entry.isDir) {
      subdirs.push(entry);
    }
  }
);

// Finally, close the iterator
promise.then(
  function onSuccess() {
    iterator.close();
    return subdirs;
  },
  function onFailure(reason) {
    iterator.close();
    throw reason;
  }
);
</pre>
<p>Or a variant using <a href="http://taskjs.org/" title="http://taskjs.org/">Task.js</a> (or at least <a href="http://dxr.mozilla.org/mozilla-central/toolkit/content/Task.jsm.html" title="http://dxr.mozilla.org/mozilla-central/toolkit/content/Task.jsm.html">the subset already present on mozilla-central</a>):</p>
<pre class="brush: js">
Task.spawn(function() {
  let iterator = new OS.File.DirectoryIterator(somePath);
  let subdirs = [];
  // Loop through all entries
  // (the loop ends with an exception).
  while (true) {
    let entry = yield iterator.next();
    subdirs.push(entry);
  }
}).then(
  null,
  // Finally, clean up
  function onFailure(reason) {
    iterator.close();
    if (reason != StopIteration) {
      throw reason;
    }
  }
);
</pre>
<h3 id="Example.3A_Sorting_files_by_last_modification_date">Example: Sorting files by last modification date</h3>
<p>The following takes advantage of feature detection to minimize file I/O:</p>
<pre class="brush: js">
let iterator = new OS.File.DirectoryIterator(somePath);
let entries = [];
let promise = iterator.forEach(
  function onEntry(entry) {
    if ("winLastWriteDate" in entry) {
      // Under Windows, additional information allows us to sort files immediately
      // without having to perform additional I/O.
      entries.push({entry: entry, creationDate: entry.winCreationDate});
    } else {
      // Under other OSes, we need to call OS.File.stat
      return OS.File.stat(entry.path).then(
        function onSuccess(info) {
          entries.push({entry:entry, creationDate: info.creationDate});
        }
      );
    }
  }
);
promise.then(
  function onSuccess() {
    // Close the iterator, sort the array, return it
    iterator.close();
    return entries.sort(function compare(a, b) {
      return a.creationDate - b.creationDate;
    });
  },
  function onFailure(reason) {
     // Close the iterator, propagate any error
    iterator.close();
    throw reason;
  }
);

</pre>
<p>Or a variant using <a href="http://taskjs.org/" title="http://taskjs.org/">Task.js</a> (or at least <a href="http://dxr.mozilla.org/mozilla-central/toolkit/content/Task.jsm.html" title="http://dxr.mozilla.org/mozilla-central/toolkit/content/Task.jsm.html">the subset already present on mozilla-central</a>):</p>
<pre class="brush: js">
let iterator = new OS.File.DirectoryIterator(somePath);
let entries = [];
Task.spawn(function(){
  while (true) {
    let entry = yield iterator.next();
    if ("winLastWriteDate" in entry) {
      // Under Windows, additional information allows us to sort files immediately
      // without having to perform additional I/O.
      entries.push({entry: entry, creationDate: entry.winCreationDate});
    } else {
      // Under other OSes, we need to call OS.File.stat
      let info = yield OS.File.stat(entry.path);
      entries.push({entry:entry, creationDate: info.creationDate});
    }
  }
}).then(
  null,
  // Clean up and return
  function onFailure(reason) {
    iterator.close();
    if (reason != StopIteration) {
      throw reason;
    }
    return entries.sort(function compare(a, b) {
      return a.creationDate - b.creationDate;
    });
  }
);
</pre>
<h2 id="Instances_of_OS.File.DirectoryIterator">Instances of OS.File.DirectoryIterator</h2>
<h3 id="General_remark">General remark</h3>
<div class="warning">
  <p>Instances of OS.File.DirectoryIterator use valuable system resources – typically the same resources as files. There is a limit to the total number of files and directory iterators that can be open at any given time. Therefore, you should make sure that these resources are released as early as possible. To do this, you should use method <a href="#OS.File.DirectoryIterator.prototype.close" title="#OS.File.DirectoryIterator.prototype.close">close</a>().</p>
</div>
<h3 id="Constructor">Constructor</h3>
<pre class="brush: js">
OS.File.DirectoryIterator(
  in string path,
  [optional] in object options
) throws <a href="/en-US/docs/JavaScript_OS.File/OS.File.Error" title="/en-US/docs/JavaScript_OS.File/OS.File.Error">OS.File.Error</a>
</pre>
<h5 id="Arguments">Arguments</h5>
<dl>
  <dt>
    path</dt>
  <dd>
    The complete path to a directory.</dd>
  <dt>
    options</dt>
  <dd>
    An object that may contain the following fields:</dd>
  <dt style="margin-left: 40px;">
    winPattern</dt>
  <dd style="margin-left: 40px;">
    (ignored on non-Windows platforms) This option accepts a pattern such as <code>"*.exe"</code> or <code>"*.txt"</code>. The iterator will only display items whose name matches this pattern.</dd>
</dl>
<h3 id="Method_overview">Method overview</h3>
<table>
  <tbody>
    <tr>
      <td>promise&lt;void&gt; <a href="#OS.File.DirectoryIterator.prototype.close" title="#OS.File.DirectoryIterator.prototype.close">close</a>()</td>
    </tr>
    <tr>
      <td>promise&lt;void&gt; <a href="#OS.File.DirectoryIterator.prototype.forEach" title="#OS.File.DirectoryIterator.prototype.forEach">forEach</a>(in function callback)</td>
    </tr>
    <tr>
      <td>promise&lt;Array&gt; <a href="#OS.File.DirectoryIterator.prototype.nextBatch" title="#OS.File.DirectoryIterator.prototype.nextBatch">nextBatch</a>([optional] in number length)</td>
    </tr>
    <tr>
      <td>promise&lt;Entry&gt; <a href="#OS.File.DirectoryIterator.prototype.next" title="#OS.File.DirectoryIterator.prototype.next">next</a>()</td>
    </tr>
  </tbody>
</table>
<h3 id="Methods">Methods</h3>
<h4 id="close()">close()<a name="OS.File.DirectoryIterator.prototype.close"></a></h4>
<p>Close the iterator, releasing the system resources it uses.</p>
<pre class="brush: js">
promise&lt;void&gt; close()</pre>
<p>You should always call this method once you are done with an iterator. Calling this method several times is harmless. Calling this method while iterating through the directory is harmless but will stop the iteration.</p>
<h5 id="Promise_resolves_to">Promise resolves to</h5>
<p>Nothing – once the resources have been released.</p>
<h4 id="forEach()">forEach()<a name="OS.File.DirectoryIterator.prototype.forEach"></a></h4>
<p>Walk through the iterator</p>
<pre class="brush: js">
promise&lt;void&gt; forEach(
  in function callback
)</pre>
<h5 id="Arguments">Arguments</h5>
<h5 class="note" id="Promise_resolves_to">Promise resolves to</h5>
<p class="note">Nothing - once the loop is complete</p>
<h5 class="note" id="Promise_rejects_to">Promise rejects to</h5>
<p class="note">&nbsp;</p>
<div class="note">
  <p><strong>Promise-based loop</strong></p>
  <p>Iteration takes place sequentially: the callback is called with the first file, then once the callback is complete with the second file, etc.</p>
  <p>It is often quite useful to be able to return a promise. If the callback returns a promise, the loop continues only once the callback is resolved.</p>
  If any of the callbacks throws an error or rejects a promise, the loop is stopped and rejects with the same error.</div>
<dl>
  <dt>
    callback</dt>
  <dd>
    A function. It will be applied to each entry in the directory successively, with the following arguments:</dd>
  <dt style="margin-left: 40px;">
    entry</dt>
  <dd style="margin-left: 40px;">
    An instance of <a href="/en-US/docs/JavaScript_OS.File/OS.File.DirectoryIterator.Entry" title="/en-US/docs/JavaScript_OS.File/OS.File.DirectoryIterator.Entry">OS.File.DirectoryIterator.Entry</a>.</dd>
  <dt style="margin-left: 40px;">
    index</dt>
  <dd style="margin-left: 40px;">
    The index of the entry in the enumeration.</dd>
  <dt style="margin-left: 40px;">
    iterator</dt>
  <dd style="margin-left: 40px;">
    The iterator itself. You may stop the iteration by calling <code>iterator.close()</code>.</dd>
  <dt class="note">
    OS.File.Error</dt>
  <dd>
    In case of I/O error.</dd>
  <dt>
    Anything else</dt>
  <dd>
    In case one of the callbacks throws an error or rejects.</dd>
</dl>
<h4 id="nextBatch()">nextBatch()<a name="OS.File.DirectoryIterator.prototype.nextBatch"></a></h4>
<p>Return several entries at once.</p>
<pre class="brush: js">
promise&lt;array&gt; nextBatch(
  [optional] in number entries
)</pre>
<h5 id="Arguments">Arguments</h5>
<dl>
  <dt>
    entries</dt>
  <dd>
    The number of entries to return at once. If unspecified, all entries.</dd>
</dl>
<h5 id="Promise_resolves_to">Promise resolves to</h5>
<p>An array containing <code>entries</code> entries, or less if there are not enough entries left in the directory. Once iteration is complete, calls to <code>nextBatch</code> return the empty array.</p>
<div class="note">
  <p><strong>Performance note</strong></p>
  <p>In some circumstances, you may wish to use this method instead of <a href="#OS.File.DirectoryIterator.prototype.forEach" title="#OS.File.DirectoryIterator.prototype.forEach">forEach</a> or <a href="#OS.File.DirectoryIterator.prototype.next" title="#OS.File.DirectoryIterator.prototype.next">next</a> for performance reasons, as it limits the number of synchronizations between threads.</p>
</div>
<h4 id="next()">next()<a name="OS.File.DirectoryIterator.prototype.next"></a></h4>
<p>Return the next entry in the directory.</p>
<pre class="brush: js">
promise&lt;<a href="https://developer.mozilla.org/en-US/docs/JavaScript_OS.File/OS.File.DirectoryIterator.Entry" title="https://developer.mozilla.org/en-US/docs/JavaScript_OS.File/OS.File.DirectoryIterator.Entry">Entry</a>&gt; next()</pre>
<h5 id="Promise_resolves_to">Promise resolves to</h5>
<p>The next entry in the directory.</p>
<h5 id="Promise_rejects_to">Promise rejects to</h5>
<dl>
  <dt>
    OS.File.Error</dt>
  <dd>
    In case of file error.</dd>
  <dt>
    StopIteration</dt>
  <dd>
    If the method is called after the last entry has been returned. Note that this is the constant <code>StopIteration</code>, not a constructor.</dd>
</dl>
Revert to this revision