OLD | NEW |
(Empty) | |
| 1 {{+bindTo:partials.standard_nacl_article}} |
| 2 |
| 3 <section id="file-i-o"> |
| 4 <span id="devguide-coding-fileio"></span><h1 id="file-i-o"><span id="devguide-co
ding-fileio"></span>File I/O</h1> |
| 5 <div class="contents local topic" id="contents"> |
| 6 <ul class="small-gap"> |
| 7 <li><a class="reference internal" href="#introduction" id="id2">Introduction</a>
</li> |
| 8 <li><a class="reference internal" href="#reference-information" id="id3">Referen
ce information</a></li> |
| 9 <li><p class="first"><a class="reference internal" href="#local-file-i-o" id="id
4">Local file I/O</a></p> |
| 10 <ul class="small-gap"> |
| 11 <li><a class="reference internal" href="#enabling-local-file-i-o" id="id5">Enabl
ing local file I/O</a></li> |
| 12 <li><a class="reference internal" href="#testing-local-file-i-o" id="id6">Testin
g local file I/O</a></li> |
| 13 </ul> |
| 14 </li> |
| 15 <li><p class="first"><a class="reference internal" href="#the-file-io-example" i
d="id7">The <code>file_io</code> example</a></p> |
| 16 <ul class="small-gap"> |
| 17 <li><a class="reference internal" href="#file-i-o-overview" id="id8">File I/O ov
erview</a></li> |
| 18 <li><a class="reference internal" href="#creating-and-writing-a-file" id="id9">C
reating and writing a file</a></li> |
| 19 <li><a class="reference internal" href="#opening-and-reading-a-file" id="id10">O
pening and reading a file</a></li> |
| 20 <li><a class="reference internal" href="#deleting-a-file" id="id11">Deleting a f
ile</a></li> |
| 21 <li><a class="reference internal" href="#making-a-directory" id="id12">Making a
directory</a></li> |
| 22 <li><a class="reference internal" href="#listing-the-contents-of-a-directory" id
="id13">Listing the contents of a directory</a></li> |
| 23 </ul> |
| 24 </li> |
| 25 <li><p class="first"><a class="reference internal" href="#file-io-deep-dive" id=
"id14"><code>file_io</code> deep dive</a></p> |
| 26 <ul class="small-gap"> |
| 27 <li><a class="reference internal" href="#opening-a-file-system-and-preparing-for
-file-i-o" id="id15">Opening a file system and preparing for file I/O</a></li> |
| 28 <li><a class="reference internal" href="#handling-messages-from-javascript" id="
id16">Handling messages from JavaScript</a></li> |
| 29 <li><a class="reference internal" href="#saving-a-file" id="id17">Saving a file<
/a></li> |
| 30 <li><a class="reference internal" href="#loading-a-file" id="id18">Loading a fil
e</a></li> |
| 31 <li><a class="reference internal" href="#id1" id="id19">Deleting a file</a></li> |
| 32 <li><a class="reference internal" href="#listing-files-in-a-directory" id="id20"
>Listing files in a directory</a></li> |
| 33 <li><a class="reference internal" href="#making-a-new-directory" id="id21">Makin
g a new directory</a></li> |
| 34 </ul> |
| 35 </li> |
| 36 </ul> |
| 37 </div> |
| 38 <section id="introduction"> |
| 39 <h2 id="introduction">Introduction</h2> |
| 40 <p>This chapter describes how to use the <a class="reference external" href="htt
ps://developers.google.com/native-client/peppercpp/classpp_1_1_file_i_o">FileIO
API</a> |
| 41 to read and write files using a local secure data store.</p> |
| 42 <p>You might use the File IO API with the URL Loading APIs to create an overall |
| 43 data download and caching solution for your NaCl applications. For example:</p> |
| 44 <ol class="arabic simple"> |
| 45 <li>Use the File IO APIs to check the local disk to see if a file exists that |
| 46 your program needs.</li> |
| 47 <li>If the file exists locally, load it into memory using the File IO API. If |
| 48 the file doesn’t exist locally, use the URL Loading API to retrieve the |
| 49 file from the server.</li> |
| 50 <li>Use the File IO API to write the file to disk.</li> |
| 51 <li>Load the file into memory using the File IO API when needed by your |
| 52 application.</li> |
| 53 </ol> |
| 54 <p>The example discussed in this chapter is included in the SDK in the directory |
| 55 <code>examples/api/file_io</code>.</p> |
| 56 </section><section id="reference-information"> |
| 57 <h2 id="reference-information">Reference information</h2> |
| 58 <p>For reference information related to FileIO, see the following documentation:
</p> |
| 59 <ul class="small-gap"> |
| 60 <li><a class="reference external" href="https://developers.google.com/native-cli
ent/peppercpp/file__io_8h">file_io.h</a> - API |
| 61 to create a FileIO object</li> |
| 62 <li><a class="reference external" href="https://developers.google.com/native-cli
ent/peppercpp/file__ref_8h">file_ref.h</a> - API |
| 63 to create a file reference or “weak pointer” to a file in a file sys
tem</li> |
| 64 <li><a class="reference external" href="https://developers.google.com/native-cli
ent/peppercpp/file__system_8h">file_system.h</a> - |
| 65 API to create a file system associated with a file</li> |
| 66 </ul> |
| 67 </section><section id="local-file-i-o"> |
| 68 <h2 id="local-file-i-o">Local file I/O</h2> |
| 69 <p>Chrome provides an obfuscated, restricted area on disk to which a web app can |
| 70 safely <a class="reference external" href="https://developers.google.com/chrome/
whitepapers/storage#persistent">read and write files</a>. The |
| 71 Pepper FileIO, FileRef, and FileSystem APIs (collectively called the File IO |
| 72 APIs) allow you to access this sandboxed local disk so you can read and write |
| 73 files and manage caching yourself. The data is persistent between launches of |
| 74 Chrome, and is not removed unless your application deletes it or the user |
| 75 manually deletes it. There is no limit to the amount of local data you can |
| 76 use, other than the actual space available on the local drive.</p> |
| 77 <section id="enabling-local-file-i-o"> |
| 78 <span id="enabling-file-access"></span><span id="quota-management"></span><h3 id
="enabling-local-file-i-o"><span id="enabling-file-access"></span><span id="quot
a-management"></span>Enabling local file I/O</h3> |
| 79 <p>The easiest way to enable the writing of persistent local data is to include |
| 80 the <a class="reference external" href="http://developer.chrome.com/extensions/d
eclare_permissions.html#unlimitedStorage">unlimitedStorage permission</a> |
| 81 in your Chrome Web Store manifest file. With this permission you can use the |
| 82 Pepper FileIO API without the need to request disk space at run time. When |
| 83 the user installs the app Chrome displays a message announcing that the app |
| 84 writes to the local disk.</p> |
| 85 <p>If you do not use the <code>unlimitedStorage</code> permission you must inclu
de |
| 86 JavaScript code that calls the <a class="reference external" href="http://update
s.html5rocks.com/2011/11/Quota-Management-API-Fast-Facts">HTML5 Quota Management
API</a> to |
| 87 explicitly request local disk space before using the FileIO API. In this case |
| 88 Chrome will prompt the user to accept a requestQuota call every time one is |
| 89 made.</p> |
| 90 </section><section id="testing-local-file-i-o"> |
| 91 <h3 id="testing-local-file-i-o">Testing local file I/O</h3> |
| 92 <p>You should be aware that using the <code>unlimitedStorage</code> manifest per
mission |
| 93 constrains the way you can test your app. Three of the four techniques |
| 94 described in <a class="reference internal" href="/native-client/devguide/devcycl
e/running.html"><em>Running Native Client Applications</em></a> |
| 95 read the Chrome Web Store manifest file and enable the <code>unlimitedStorage</c
ode> |
| 96 permission when it appears, but the first technique (local server) does not. |
| 97 If you want to test the file IO portion of your app with a simple local server, |
| 98 you need to include JavaScript code that calls the HTML5 Quota Management API. |
| 99 When you deliver your application you can replace this code with the |
| 100 <code>unlimitedStorage</code> manifest permission.</p> |
| 101 </section></section><section id="the-file-io-example"> |
| 102 <h2 id="the-file-io-example">The <code>file_io</code> example</h2> |
| 103 <p>The Native Client SDK includes an example, <code>file_io</code>, that demonst
rates how |
| 104 to read and write a local disk file. Since you will probably run the example |
| 105 from a local server without a Chrome Web Store manifest file, the example’
s |
| 106 index file uses JavaScript to perform the Quota Management setup as described |
| 107 above. The example has these primary files:</p> |
| 108 <ul class="small-gap"> |
| 109 <li><code>index.html</code> - The HTML code that launches the Native Client modu
le and |
| 110 displays the user interface.</li> |
| 111 <li><code>example.js</code> - JavaScript code that requests quota (as described
above). It |
| 112 also listens for user interaction with the user interface, and forwards the |
| 113 requests to the Native Client module.</li> |
| 114 <li><code>file_io.cc</code> - The code that sets up and provides an entry point
to the |
| 115 Native Client module.</li> |
| 116 </ul> |
| 117 <p>The remainder of this section covers the code in the <code>file_io.cc</code>
file for |
| 118 reading and writing files.</p> |
| 119 <section id="file-i-o-overview"> |
| 120 <h3 id="file-i-o-overview">File I/O overview</h3> |
| 121 <p>Like many Pepper APIs, the File IO API includes a set of methods that execute |
| 122 asynchronously and that invoke callback functions in your Native Client module. |
| 123 Unlike most other examples, the <code>file_io</code> example also demonstrates h
ow to |
| 124 make Pepper calls synchronously on a worker thread.</p> |
| 125 <p>It is illegal to make blocking calls to Pepper on the module’s main thr
ead. |
| 126 This restriction is lifted when running on a worker thread—this is called |
| 127 “calling Pepper off the main thread”. This often simplifies the logi
c of your |
| 128 code; multiple asynchronous Pepper functions can be called from one function on |
| 129 your worker thread, so you can use the stack and standard control flow |
| 130 structures normally.</p> |
| 131 <p>The high-level flow for the <code>file_io</code> example is described below.
Note that |
| 132 methods in the namespace <code>pp</code> are part of the Pepper C++ API.</p> |
| 133 </section><section id="creating-and-writing-a-file"> |
| 134 <h3 id="creating-and-writing-a-file">Creating and writing a file</h3> |
| 135 <p>Following are the high-level steps involved in creating and writing to a |
| 136 file:</p> |
| 137 <ol class="arabic simple"> |
| 138 <li><code>pp::FileIO::Open</code> is called with the <code>PP_FILEOPEN_FLAG_CREA
TE</code> flag to |
| 139 create a file. Because the callback function is <code>pp::BlockUntilComplete</c
ode>, |
| 140 this thread is blocked until <code>Open</code> succeeds or fails.</li> |
| 141 <li><code>pp::FileIO::Write</code> is called to write the contents. Again, the t
hread is |
| 142 blocked until the call to <code>Write</code> completes. If there is more data to |
| 143 write, <code>Write</code> is called again.</li> |
| 144 <li>When there is no more data to write, call <code>pp::FileIO::Flush</code>.</l
i> |
| 145 </ol> |
| 146 </section><section id="opening-and-reading-a-file"> |
| 147 <h3 id="opening-and-reading-a-file">Opening and reading a file</h3> |
| 148 <p>Following are the high-level steps involved in opening and reading a file:</p
> |
| 149 <ol class="arabic simple"> |
| 150 <li><code>pp::FileIO::Open</code> is called to open the file. Because the callba
ck |
| 151 function is <code>pp::BlockUntilComplete</code>, this thread is blocked until Op
en |
| 152 succeeds or fails.</li> |
| 153 <li><code>pp::FileIO::Query</code> is called to query information about the file
, such as |
| 154 its file size. The thread is blocked until <code>Query</code> completes.</li> |
| 155 <li><code>pp::FileIO::Read</code> is called to read the contents. The thread is
blocked |
| 156 until <code>Read</code> completes. If there is more data to read, <code>Read</co
de> is called |
| 157 again.</li> |
| 158 </ol> |
| 159 </section><section id="deleting-a-file"> |
| 160 <h3 id="deleting-a-file">Deleting a file</h3> |
| 161 <p>Deleting a file is straightforward: call <code>pp::FileRef::Delete</code>. Th
e thread is |
| 162 blocked until <code>Delete</code> completes.</p> |
| 163 </section><section id="making-a-directory"> |
| 164 <h3 id="making-a-directory">Making a directory</h3> |
| 165 <p>Making a directory is also straightforward: call <code>pp::File::MakeDirector
y</code>. |
| 166 The thread is blocked until <code>MakeDirectory</code> completes.</p> |
| 167 </section><section id="listing-the-contents-of-a-directory"> |
| 168 <h3 id="listing-the-contents-of-a-directory">Listing the contents of a directory
</h3> |
| 169 <p>Following are the high-level steps involved in listing a directory:</p> |
| 170 <ol class="arabic simple"> |
| 171 <li><code>pp::FileRef::ReadDirectoryEntries</code> is called, and given a direct
ory entry |
| 172 to list. A callback is given as well; many of the other functions use |
| 173 <code>pp::BlockUntilComplete</code>, but <code>ReadDirectoryEntries</code> retur
ns results in |
| 174 its callback, so it must be specified.</li> |
| 175 <li>When the call to <code>ReadDirectoryEntries</code> completes, it calls |
| 176 <code>ListCallback</code> which packages up the results into a string message, a
nd |
| 177 sends it to JavaScript.</li> |
| 178 </ol> |
| 179 </section></section><section id="file-io-deep-dive"> |
| 180 <h2 id="file-io-deep-dive"><code>file_io</code> deep dive</h2> |
| 181 <p>The <code>file_io</code> example displays a user interface with a couple of f
ields and |
| 182 several buttons. Following is a screenshot of the <code>file_io</code> example:<
/p> |
| 183 <img alt="/native-client/images/fileioexample.png" src="/native-client/images/fi
leioexample.png" /> |
| 184 <p>Each radio button is a file operation you can perform, with some reasonable |
| 185 default values for filenames. Try typing a message in the large input box and |
| 186 clicking <code>Save</code>, then switching to the <code>Load File</code> operati
on, and |
| 187 clicking <code>Load</code>.</p> |
| 188 <p>Let’s take a look at what is going on under the hood.</p> |
| 189 <section id="opening-a-file-system-and-preparing-for-file-i-o"> |
| 190 <h3 id="opening-a-file-system-and-preparing-for-file-i-o">Opening a file system
and preparing for file I/O</h3> |
| 191 <p><code>pp::Instance::Init</code> is called when an instance of a module is cre
ated. In |
| 192 this example, <code>Init</code> starts a new thread (via the <code>pp::SimpleThr
ead</code> |
| 193 class), and tells it to open the filesystem:</p> |
| 194 <pre class="prettyprint"> |
| 195 virtual bool Init(uint32_t /*argc*/, |
| 196 const char * /*argn*/ [], |
| 197 const char * /*argv*/ []) { |
| 198 file_thread_.Start(); |
| 199 // Open the file system on the file_thread_. Since this is the first |
| 200 // operation we perform there, and because we do everything on the |
| 201 // file_thread_ synchronously, this ensures that the FileSystem is open |
| 202 // before any FileIO operations execute. |
| 203 file_thread_.message_loop().PostWork( |
| 204 callback_factory_.NewCallback(&FileIoInstance::OpenFileSystem)); |
| 205 return true; |
| 206 } |
| 207 </pre> |
| 208 <p>When the file thread starts running, it will call <code>OpenFileSystem</code>
. This |
| 209 calls <code>pp::FileSystem::Open</code> and blocks the file thread until the fun
ction |
| 210 returns.</p> |
| 211 <aside class="note"> |
| 212 Note that the call to <code>pp::FileSystem::Open</code> uses |
| 213 <code>pp::BlockUntilComplete</code> as its callback. This is only possible becau
se we |
| 214 are running off the main thread; if you try to make a blocking call from the |
| 215 main thread, the function will return the error |
| 216 <code>PP_ERROR_BLOCKS_MAIN_THREAD</code>. |
| 217 </aside> |
| 218 <pre class="prettyprint"> |
| 219 void OpenFileSystem(int32_t /*result*/) { |
| 220 int32_t rv = file_system_.Open(1024 * 1024, pp::BlockUntilComplete()); |
| 221 if (rv == PP_OK) { |
| 222 file_system_ready_ = true; |
| 223 // Notify the user interface that we're ready |
| 224 PostMessage("READY|"); |
| 225 } else { |
| 226 ShowErrorMessage("Failed to open file system", rv); |
| 227 } |
| 228 } |
| 229 </pre> |
| 230 </section><section id="handling-messages-from-javascript"> |
| 231 <h3 id="handling-messages-from-javascript">Handling messages from JavaScript</h3
> |
| 232 <p>When you click the <code>Save</code> button, JavaScript posts a message to th
e NaCl |
| 233 module with the file operation to perform sent as a string (See <a class="refere
nce internal" href="/native-client/devguide/coding/message-system.html"><em>Mess
aging |
| 234 System</em></a> for more details on message passing). The string is |
| 235 parsed by <code>HandleMessage</code>, and new work is added to the file thread:<
/p> |
| 236 <pre class="prettyprint"> |
| 237 virtual void HandleMessage(const pp::Var& var_message) { |
| 238 if (!var_message.is_string()) |
| 239 return; |
| 240 |
| 241 // Parse message into: instruction file_name_length file_name [file_text] |
| 242 std::string message = var_message.AsString(); |
| 243 std::string instruction; |
| 244 std::string file_name; |
| 245 std::stringstream reader(message); |
| 246 int file_name_length; |
| 247 |
| 248 reader >> instruction >> file_name_length; |
| 249 file_name.resize(file_name_length); |
| 250 reader.ignore(1); // Eat the delimiter |
| 251 reader.read(&file_name[0], file_name_length); |
| 252 |
| 253 ... |
| 254 |
| 255 // Dispatch the instruction |
| 256 if (instruction == kLoadPrefix) { |
| 257 file_thread_.message_loop().PostWork( |
| 258 callback_factory_.NewCallback(&FileIoInstance::Load, file_name)); |
| 259 } else if (instruction == kSavePrefix) { |
| 260 ... |
| 261 } |
| 262 } |
| 263 </pre> |
| 264 </section><section id="saving-a-file"> |
| 265 <h3 id="saving-a-file">Saving a file</h3> |
| 266 <p><code>FileIoInstance::Save</code> is called when the <code>Save</code> button
is pressed. First, |
| 267 it checks to see that the FileSystem has been successfully opened:</p> |
| 268 <pre class="prettyprint"> |
| 269 if (!file_system_ready_) { |
| 270 ShowErrorMessage("File system is not open", PP_ERROR_FAILED); |
| 271 return; |
| 272 } |
| 273 </pre> |
| 274 <p>It then creates a <code>pp::FileRef</code> resource with the name of the file
. A |
| 275 <code>FileRef</code> resource is a weak reference to a file in the FileSystem; t
hat is, |
| 276 a file can still be deleted even if there are outstanding <code>FileRef</code> |
| 277 resources.</p> |
| 278 <pre class="prettyprint"> |
| 279 pp::FileRef ref(file_system_, file_name.c_str()); |
| 280 </pre> |
| 281 <p>Next, a <code>pp::FileIO</code> resource is created and opened. The call to |
| 282 <code>pp::FileIO::Open</code> passes <code>PP_FILEOPEFLAG_WRITE</code> to open t
he file for |
| 283 writing, <code>PP_FILEOPENFLAG_CREATE</code> to create a new file if it doesn
217;t already |
| 284 exist and <code>PP_FILEOPENFLAG_TRUNCATE</code> to clear the file of any previou
s |
| 285 content:</p> |
| 286 <pre class="prettyprint"> |
| 287 pp::FileIO file(this); |
| 288 |
| 289 int32_t open_result = |
| 290 file.Open(ref, |
| 291 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | |
| 292 PP_FILEOPENFLAG_TRUNCATE, |
| 293 pp::BlockUntilComplete()); |
| 294 if (open_result != PP_OK) { |
| 295 ShowErrorMessage("File open for write failed", open_result); |
| 296 return; |
| 297 } |
| 298 </pre> |
| 299 <p>Now that the file is opened, it is written to in chunks. In an asynchronous |
| 300 model, this would require writing a separate function, storing the current |
| 301 state on the free store and a chain of callbacks. Because this function is |
| 302 called off the main thread, <code>pp::FileIO::Write</code> can be called synchro
nously |
| 303 and a conventional do/while loop can be used:</p> |
| 304 <pre class="prettyprint"> |
| 305 int64_t offset = 0; |
| 306 int32_t bytes_written = 0; |
| 307 do { |
| 308 bytes_written = file.Write(offset, |
| 309 file_contents.data() + offset, |
| 310 file_contents.length(), |
| 311 pp::BlockUntilComplete()); |
| 312 if (bytes_written > 0) { |
| 313 offset += bytes_written; |
| 314 } else { |
| 315 ShowErrorMessage("File write failed", bytes_written); |
| 316 return; |
| 317 } |
| 318 } while (bytes_written < static_cast<int64_t>(file_contents.length())); |
| 319 </pre> |
| 320 <p>Finally, the file is flushed to push all changes to disk:</p> |
| 321 <pre class="prettyprint"> |
| 322 int32_t flush_result = file.Flush(pp::BlockUntilComplete()); |
| 323 if (flush_result != PP_OK) { |
| 324 ShowErrorMessage("File fail to flush", flush_result); |
| 325 return; |
| 326 } |
| 327 </pre> |
| 328 </section><section id="loading-a-file"> |
| 329 <h3 id="loading-a-file">Loading a file</h3> |
| 330 <p><code>FileIoInstance::Load</code> is called when the <code>Load</code> button
is pressed. Like |
| 331 the <code>Save</code> function, <code>Load</code> first checks to see if the Fil
eSystem has been |
| 332 successfully opened, and creates a new <code>FileRef</code>:</p> |
| 333 <pre class="prettyprint"> |
| 334 if (!file_system_ready_) { |
| 335 ShowErrorMessage("File system is not open", PP_ERROR_FAILED); |
| 336 return; |
| 337 } |
| 338 pp::FileRef ref(file_system_, file_name.c_str()); |
| 339 </pre> |
| 340 <p>Next, <code>Load</code> creates and opens a new <code>FileIO</code> resource,
passing |
| 341 <code>PP_FILEOPENFLAG_READ</code> to open the file for reading. The result is co
mpared |
| 342 to <code>PP_ERROR_FILENOTFOUND</code> to give a better error message when the fi
le |
| 343 doesn’t exist:</p> |
| 344 <pre class="prettyprint"> |
| 345 int32_t open_result = |
| 346 file.Open(ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete()); |
| 347 if (open_result == PP_ERROR_FILENOTFOUND) { |
| 348 ShowErrorMessage("File not found", open_result); |
| 349 return; |
| 350 } else if (open_result != PP_OK) { |
| 351 ShowErrorMessage("File open for read failed", open_result); |
| 352 return; |
| 353 } |
| 354 </pre> |
| 355 <p>Then <code>Load</code> calls <code>pp::FileIO::Query</code> to get metadata a
bout the file, such |
| 356 as its size. This is used to allocate a <code>std::vector</code> buffer that hol
ds the |
| 357 data from the file in memory:</p> |
| 358 <pre class="prettyprint"> |
| 359 int32_t query_result = file.Query(&info, pp::BlockUntilComplete()); |
| 360 if (query_result != PP_OK) { |
| 361 ShowErrorMessage("File query failed", query_result); |
| 362 return; |
| 363 } |
| 364 |
| 365 ... |
| 366 |
| 367 std::vector<char> data(info.size); |
| 368 </pre> |
| 369 <p>Similar to <code>Save</code>, a conventional while loop is used to read the f
ile into |
| 370 the newly allocated buffer:</p> |
| 371 <pre class="prettyprint"> |
| 372 int64_t offset = 0; |
| 373 int32_t bytes_read = 0; |
| 374 int32_t bytes_to_read = info.size; |
| 375 while (bytes_to_read > 0) { |
| 376 bytes_read = file.Read(offset, |
| 377 &data[offset], |
| 378 data.size() - offset, |
| 379 pp::BlockUntilComplete()); |
| 380 if (bytes_read > 0) { |
| 381 offset += bytes_read; |
| 382 bytes_to_read -= bytes_read; |
| 383 } else if (bytes_read < 0) { |
| 384 // If bytes_read < PP_OK then it indicates the error code. |
| 385 ShowErrorMessage("File read failed", bytes_read); |
| 386 return; |
| 387 } |
| 388 } |
| 389 </pre> |
| 390 <p>Finally, the contents of the file are sent back to JavaScript, to be displaye
d |
| 391 on the page. This example uses “<code>DISP|</code>” as a prefix comm
and for display |
| 392 information:</p> |
| 393 <pre class="prettyprint"> |
| 394 std::string string_data(data.begin(), data.end()); |
| 395 PostMessage("DISP|" + string_data); |
| 396 ShowStatusMessage("Load success"); |
| 397 </pre> |
| 398 </section><section id="id1"> |
| 399 <h3 id="id1">Deleting a file</h3> |
| 400 <p><code>FileIoInstance::Delete</code> is called when the <code>Delete</code> bu
tton is pressed. |
| 401 First, it checks whether the FileSystem has been opened, and creates a new |
| 402 <code>FileRef</code>:</p> |
| 403 <pre class="prettyprint"> |
| 404 if (!file_system_ready_) { |
| 405 ShowErrorMessage("File system is not open", PP_ERROR_FAILED); |
| 406 return; |
| 407 } |
| 408 pp::FileRef ref(file_system_, file_name.c_str()); |
| 409 </pre> |
| 410 <p>Unlike <code>Save</code> and <code>Load</code>, <code>Delete</code> is called
on the <code>FileRef</code> resource, |
| 411 not a <code>FileIO</code> resource. Note that the result is checked for |
| 412 <code>PP_ERROR_FILENOTFOUND</code> to give a better error message when trying to
delete |
| 413 a non-existent file:</p> |
| 414 <pre class="prettyprint"> |
| 415 int32_t result = ref.Delete(pp::BlockUntilComplete()); |
| 416 if (result == PP_ERROR_FILENOTFOUND) { |
| 417 ShowStatusMessage("File/Directory not found"); |
| 418 return; |
| 419 } else if (result != PP_OK) { |
| 420 ShowErrorMessage("Deletion failed", result); |
| 421 return; |
| 422 } |
| 423 </pre> |
| 424 </section><section id="listing-files-in-a-directory"> |
| 425 <h3 id="listing-files-in-a-directory">Listing files in a directory</h3> |
| 426 <p><code>FileIoInstance::List</code> is called when the <code>List Directory</co
de> button is |
| 427 pressed. Like all other operations, it checks whether the FileSystem has been |
| 428 opened and creates a new <code>FileRef</code>:</p> |
| 429 <pre class="prettyprint"> |
| 430 if (!file_system_ready_) { |
| 431 ShowErrorMessage("File system is not open", PP_ERROR_FAILED); |
| 432 return; |
| 433 } |
| 434 |
| 435 pp::FileRef ref(file_system_, dir_name.c_str()); |
| 436 </pre> |
| 437 <p>Unlike the other operations, it does not make a blocking call to |
| 438 <code>pp::FileRef::ReadDirectoryEntries</code>. Since <code>ReadDirectoryEntries
</code> returns |
| 439 the resulting directory entries in its callback, a new callback object is |
| 440 created pointing to <code>FileIoInstance::ListCallback</code>.</p> |
| 441 <p>The <code>pp::CompletionCallbackFactory</code> template class is used to inst
antiate a |
| 442 new callback. Notice that the <code>FileRef</code> resource is passed as a param
eter; |
| 443 this will add a reference count to the callback object, to keep the <code>FileRe
f</code> |
| 444 resource from being destroyed when the function finishes.</p> |
| 445 <pre class="prettyprint"> |
| 446 // Pass ref along to keep it alive. |
| 447 ref.ReadDirectoryEntries(callback_factory_.NewCallbackWithOutput( |
| 448 &FileIoInstance::ListCallback, ref)); |
| 449 </pre> |
| 450 <p><code>FileIoInstance::ListCallback</code> then gets the results passed as a |
| 451 <code>std::vector</code> of <code>pp::DirectoryEntry</code> objects, and sends t
hem to |
| 452 JavaScript:</p> |
| 453 <pre class="prettyprint"> |
| 454 void ListCallback(int32_t result, |
| 455 const std::vector<pp::DirectoryEntry>& entries, |
| 456 pp::FileRef /*unused_ref*/) { |
| 457 if (result != PP_OK) { |
| 458 ShowErrorMessage("List failed", result); |
| 459 return; |
| 460 } |
| 461 |
| 462 std::stringstream ss; |
| 463 ss << "LIST"; |
| 464 for (size_t i = 0; i < entries.size(); ++i) { |
| 465 pp::Var name = entries[i].file_ref().GetName(); |
| 466 if (name.is_string()) { |
| 467 ss << "|" << name.AsString(); |
| 468 } |
| 469 } |
| 470 PostMessage(ss.str()); |
| 471 ShowStatusMessage("List success"); |
| 472 } |
| 473 </pre> |
| 474 </section><section id="making-a-new-directory"> |
| 475 <h3 id="making-a-new-directory">Making a new directory</h3> |
| 476 <p><code>FileIoInstance::MakeDir</code> is called when the <code>Make Directory<
/code> button is |
| 477 pressed. Like all other operations, it checks whether the FileSystem has been |
| 478 opened and creates a new <code>FileRef</code>:</p> |
| 479 <pre class="prettyprint"> |
| 480 if (!file_system_ready_) { |
| 481 ShowErrorMessage("File system is not open", PP_ERROR_FAILED); |
| 482 return; |
| 483 } |
| 484 pp::FileRef ref(file_system_, dir_name.c_str()); |
| 485 </pre> |
| 486 <p>Then the <code>pp::FileRef::MakeDirectory</code> function is called.</p> |
| 487 <pre class="prettyprint"> |
| 488 int32_t result = ref.MakeDirectory( |
| 489 PP_MAKEDIRECTORYFLAG_NONE, pp::BlockUntilComplete()); |
| 490 if (result != PP_OK) { |
| 491 ShowErrorMessage("Make directory failed", result); |
| 492 return; |
| 493 } |
| 494 ShowStatusMessage("Make directory success"); |
| 495 </pre> |
| 496 </section></section></section> |
| 497 |
| 498 {{/partials.standard_nacl_article}} |
OLD | NEW |