OLD | NEW |
---|---|
(Empty) | |
1 --- | |
2 layout: default | |
3 title: "Write Command-Line Apps" | |
4 description: "Basics for command-line apps" | |
5 has-permalinks: true | |
6 tutorial: | |
7 id: dart-io | |
8 next: fetchdata/ | |
9 next-title: "Fetch Data Dynamically" | |
10 prev: futures/ | |
11 prev-title: "Use Future-Based APIs" | |
12 --- | |
13 | |
14 {% capture whats_the_point %} | |
sethladd
2014/01/03 00:57:28
Global: I'd like to see some advice for when to us
sethladd
2014/01/03 00:57:28
Global: I couldn't find it, can you link to the pr
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
There's only one place where synchronous is used a
| |
15 | |
16 * Server-side applications need to do input and output. | |
sethladd
2014/01/03 00:57:28
the tutorial says "command-line" but here you say
mem
2014/01/03 17:38:02
Done.
| |
17 * The dart:io library provides I/O functionality. | |
18 * The args package helps define and parse command-line arguments. | |
19 * Most input and output requires the use of Streams. | |
20 * Streams provide a series of asynchronous data events. | |
21 * To handle asynchronous data, you need to use Futures. | |
22 | |
23 {% endcapture %} | |
24 | |
25 {% capture sample_links %} | |
26 | |
27 <p> This tutorial features these examples:</p> | |
28 * helloworld42 | |
29 * dcat | |
30 * dgrep | |
31 | |
32 <p> | |
33 Don't have the source code? | |
sethladd
2014/01/03 00:57:28
the source for the examples above?
mem
2014/01/03 17:38:02
this is consistent with all of the other tutorials
| |
34 <a href="https://github.com/dart-lang/dart-tutorials-samples/archive/master.zip" > | |
35 Download it. | |
36 </a> | |
37 | |
38 {% endcapture %} | |
39 | |
40 {% capture content %} | |
41 | |
42 <div class="tute-target-title"> | |
43 <h1>{{page.title}}</h1> | |
44 <h3>An introduction to standalone apps</h3> | |
sethladd
2014/01/03 00:57:28
and here we use standalone (instead of command-lin
mem
2014/01/03 17:38:02
we use standalone here otherwise we use the exact
| |
45 </div> | |
46 | |
47 <div id="under-construction" markdown="1"> | |
48 <h3> <i class="icon-wrench"> </i> Under construction </h3> | |
49 | |
50 This is a draft under construction. | |
51 Your kindly worded | |
52 <a | |
53 href="http://code.google.com/p/dart/issues/entry?template=Tutorial%20feedback" | |
54 target="_blank"> | |
55 comments and suggestions | |
56 </a> | |
57 are appreciated. | |
58 Thank you for your patience. | |
59 </div> | |
60 | |
61 This tutorial looks at a few small command-line applications. | |
sethladd
2014/01/03 00:57:28
opinion: this tutorial teaches you how to build co
mem
2014/01/03 17:38:02
Done.
| |
62 These programs use resources that most command-line applications need, | |
63 including the standard output, error, and input streams, | |
64 command-line arguments, files and directories, and more. | |
65 | |
66 * [Run an app with the standalone Dart VM](#run-the-first-app) | |
67 * [Check out the dcat example](#dcat-code) | |
68 * [Parsing command-line arguments](#cmd-line-args) | |
69 * [Reading and writing with stdin, stdout, and stderr](#std-in-out-err) | |
70 * [Getting info about a file](#filesystementity) | |
71 * [Reading a file](#reading-a-file) | |
72 * [Writing a file](#writing-a-file) | |
73 * [Getting environment information](#env-var) | |
74 * [Setting exit codes](#exit-codes) | |
75 * [Check out the code for another example](#dgrep-code) | |
76 * [Summary](#summary) | |
77 * [Other resources](#other-resources) | |
78 * [What next?](#what-next) | |
79 | |
80 ## Run an app with the standalone Dart VM {#run-the-first-app} | |
sethladd
2014/01/03 00:57:28
other headers are "-ing" like "reading" or "writin
mem
2014/01/03 17:38:02
Done.
| |
81 | |
82 To run a command-line app, you need the Dart VM (`dart`), | |
83 which comes with the Dart Editor (in the Dart download) | |
sethladd
2014/01/03 00:57:28
use a link for "Dart download" ?
mem
2014/01/03 17:38:02
Done.
| |
84 or in the [Dart SDK](/tools/sdk/) download. | |
85 If you install the Dart download in a directory called `~/myDartDownload`, | |
86 you can find `dart` | |
87 in `~/myDartDownload/dart-sdk/bin`. | |
88 | |
89 <div markdown="1"> | |
90 | |
91  | |
92 | |
93 </div> | |
94 | |
95 By putting this directory in your PATH | |
96 you can refer to the `dart` command and other commands, | |
97 such as the dart analyzer, by name. | |
98 | |
99 Let's run a small program. | |
100 | |
101 <ol> | |
102 <li markdown="1"> | |
103 Create a file called `helloworld42.dart` that contains this code: | |
104 | |
105 {% prettify dart %} | |
106 void main() { | |
107 int fortyTwo = 'Hello, World'; // Type mismatch. | |
sethladd
2014/01/03 00:57:28
I think teaching the optional types here, and how
mem
2014/01/03 17:38:02
Done.
| |
108 print(fortyTwo); | |
109 } | |
110 {% endprettify %} | |
111 </li> | |
112 | |
113 <li markdown="1"> | |
114 In the directory that contains the file you just created, | |
115 run the program with the command as shown by the highlighted text. | |
116 | |
117 {% prettify bash %} | |
118 % [[highlight]]dart helloworld42.dart[[/highlight]] | |
119 Hello, World! | |
120 % | |
121 {% endprettify %} | |
122 | |
123 The program runs cleanly in spite | |
124 of the type mismatch in the source code. | |
125 Types are optional in Dart and by default the Dart VM | |
126 does not do type-checking. | |
127 </li> | |
128 | |
129 <li markdown="1"> | |
130 Run the `helloworld42.dart` program using the `--checked` flag: | |
131 | |
132 {% prettify bash %} | |
133 % [[highlight]]dart --checked helloworld42.dart[[/highlight]] | |
134 Unhandled exception: | |
135 type 'String' is not a subtype of type 'int' of 'fortyTwo'. | |
136 ... | |
137 % | |
138 {% endprettify %} | |
139 | |
140 The program fails because the program assigns a string to an integer. | |
141 | |
142 The `--checked` option enables | |
143 assertion and type checks (checked mode). | |
144 Checked mode is useful during development for finding errors | |
145 related to types and for testing `assert` statements. | |
146 We recommend running your programs in checked mode during prototyping | |
147 and development, and turning it off for production. | |
148 | |
149 Note that the flags and options passed to the Dart VM go before the name | |
150 of the Dart file to run. | |
151 </li> | |
152 </ol> | |
153 | |
154 ## Check out the dcat example {#dcat-code} | |
sethladd
2014/01/03 00:57:28
Can you make it more clear that you'll go into mor
mem
2014/01/03 17:38:02
Done.
| |
155 | |
156 Take a quick look at the code for a small sample called `dcat`, | |
157 which is a simplified implementation of the Unix cat utility. | |
sethladd
2014/01/03 00:57:28
explain what the Unix cat utility is. 80% of our u
mem
2014/01/03 17:38:02
Done.
| |
158 This program uses various classes, functions, and properties | |
159 available to command-line apps. | |
160 Hover over the highlighted code below for explanations. | |
161 | |
162 <pre class="prettyprint lang-dart"> | |
163 import 'dart:async'; | |
164 import 'dart:convert'; | |
165 import 'dart:io'; | |
166 | |
167 import 'package:args/args.dart'; | |
168 | |
169 const LINE_NUMBER = 'line-number'; | |
170 var NEWLINE = '\n'; | |
171 | |
172 ArgResults argResults; | |
173 | |
174 void main(<a href="#" class="dart-popover" data-toggle="popover" title="Command- line arguments" data-html="true" data-trigger="hover focus" data-content="Comman d-line arguments are passed in by the system when the program starts.">List<S tring> arguments</a>) { | |
175 exitCode = 0; // Presume success. | |
sethladd
2014/01/03 00:57:28
I'm left wondering where exitCode came from?
mem
2014/01/03 17:38:02
Done.
| |
176 final parser = new ArgParser() | |
177 ..addFlag(LINE_NUMBER, negatable: false, abbr: 'n'); | |
178 | |
179 <a href="#" class="dart-popover" data-toggle="popover" title="Arguments parser " data-html="true" data-trigger="hover focus" data-content="The ArgParser class provides help with parsing command-line arguments.">argResults = parser.parse(ar guments);</a> | |
180 List<String> paths = argResults.rest; | |
181 | |
182 dcat(paths, argResults[LINE_NUMBER]); | |
183 } | |
184 | |
185 Future dcat(List<String> paths, bool showLineNumbers) { | |
186 if (paths.isEmpty) { | |
187 // No files provided as arguments. Read from stdin and print each line. | |
188 return <a href="#" class="dart-popover" data-toggle="popover" title="Standar d I/O streams" data-html="true" data-trigger="hover focus" data-content="This co de reads from the standard input stream and pipes the data to the standard outpu t stream.">stdin.pipe(stdout);</a> | |
189 } else { | |
190 return Future.forEach(paths, (path) { | |
191 int lineNumber = 1; | |
192 <a href="#" class="dart-popover" data-toggle="popover" title="Open a file for reading" data-html="true" data-trigger="hover focus" data-content="Use the F ile class to represent a file on the native file system.">Stream<List<int& gt;> stream = new File(path).openRead();</a> | |
193 return stream | |
194 <a href="#" class="dart-popover" data-toggle="popover" title="Data con verters" data-html="true" data-trigger="hover focus" data-content="Convert data as it becomes available on a stream.">.transform(UTF8.decoder)</a> | |
195 .transform(const LineSplitter()) | |
196 <a href="#" class="dart-popover" data-toggle="popover" title="Get data from a stream" data-html="true" data-trigger="hover focus" data-content="Listen to a stream to get data when it becomes available.">.listen((line)</a> { | |
197 if (showLineNumbers) { | |
198 stdout.write('${lineNumber++} '); | |
199 } | |
200 stdout.writeln(line); | |
201 }).asFuture().catchError((_) => _handleError(path)); | |
202 }); | |
203 } | |
204 } | |
205 | |
206 _handleError(String path) { | |
207 <a href="#" class="dart-popover" data-toggle="popover" title="Test a path" dat a-html="true" data-trigger="hover focus" data-content="You can get information a bout the file system on which your program is running.">FileSystemEntity.isDirec tory(path)</a>.then((isDir) { | |
208 if (isDir) { | |
209 print('error: $path is a directory'); | |
210 } else { | |
211 print('error: $path not found'); | |
212 } | |
213 }); | |
214 <a href="#" class="dart-popover" data-toggle="popover" title="Exit code" data- html="true" data-trigger="hover focus" data-content="A well-behaved command-line app sets an exit code to indicate whether the program was successful.">exitCode = 2;</a> | |
215 } | |
216 | |
217 </pre> | |
218 | |
219 ## Parsing command-line arguments {#cmd-line-args} | |
220 | |
221 The | |
222 <a href="https://api.dartlang.org/args.html" target="_blank">args</a> | |
223 package provides | |
sethladd
2014/01/03 00:57:28
Are they going to know what a package is?
mem
2014/01/03 17:38:02
Done.
| |
224 parser support for transforming raw command-line arguments | |
225 into a set of options, flags, and additional values. | |
226 Import the library as follows: | |
227 | |
228 {% prettify dart %} | |
229 import 'package:args/args.dart'; | |
230 {% endprettify %} | |
231 | |
232 The args library contains two classes: | |
233 | |
234 | Library | Description | | |
235 |---|---| | |
236 | <a href="https://api.dartlang.org/args/ArgParser" target="_blank">ArgParser</a > | A class that parses command-line arguments | | |
237 | <a href="https://api.dartlang.org/args/ArgResults" target="_blank">ArgResults< /a> | The result of parsing command-line arguments using ArgParser. | | |
238 {: .table } | |
239 | |
240 Let's take a look at the `dcat` sample, | |
241 which uses ArgParser and ArgResults to parse and store its command-line argument s. | |
242 | |
243 <ol> | |
244 <li markdown="1"> | |
245 Copy the sample file from the github repo: | |
246 <a href="https://github.com/dart-lang/dart-tutorials-samples/blob/master/bin/dca t.dart">dcat.dart</a>. | |
247 </li> | |
248 | |
249 <li markdown="1"> | |
250 Run the program from the command line as shown by the highlighted text. | |
251 | |
252 {% prettify bash %} | |
253 $ [[highlight]]dart dcat.dart -n quotes.txt[[/highlight]] | |
254 1 Be yourself. Everyone else is taken. -Oscar Wilde | |
255 2 Don't cry because it's over, smile because it happened. -Dr. Seuss | |
256 3 You only live once, but if you do it right, once is enough. -Mae West | |
257 ... | |
258 {% endprettify %} | |
259 | |
260 The program displays the contents of the source code file and | |
261 preceeds each line with a line number. | |
262 </li> | |
263 | |
264 </ol> | |
265 | |
266 The following diagram shows how the `dcat` command line used above | |
267 is parsed into the `ArgResults` object. | |
268 | |
269  | |
270 | |
271 You can access flags and options by name, | |
272 treating the ArgResults object like a Map. | |
273 You can access other values with properties such as `rest`. | |
274 | |
275 Here's the code from `dcat` that deals with command-line arguments: | |
276 | |
277 <pre class="prettyprint lang-dart"> | |
278 | |
279 ... | |
280 <a href="#" class="dart-popover" data-toggle="popover" title="Parsed arguments" data-html="true" data-trigger="hover focus" data-content="This object contains p arsed options and flags.">ArgResults argResults;</a> | |
281 | |
282 void main(<a href="#" class="dart-popover" data-toggle="popover" title="Command- line arguments" data-html="true" data-trigger="hover focus" data-content="The sy stem passes command-line arguments into the program in a list of strings.">List& lt;String> arguments</a>) { | |
283 final parser = new ArgParser() | |
284 <a href="#" class="dart-popover" data-toggle="popover" title="Define a val id flag" data-html="true" data-trigger="hover focus" data-content="Add a flag de finition to the command-line argument parser. This code defines the flag -n, whi ch when used displays line numbers.">..addFlag(LINE_NUMBER, negatable: false, ab br: 'n')</a>; | |
285 | |
286 argResults = parser.<a href="#" class="dart-popover" data-toggle="popover" tit le="Parse the arguments" data-html="true" data-trigger="hover focus" data-conten t="Parse the arguments that were passed into the main() function. The parser sto ps parsing if it finds an undefined option or flag.">parse(arguments)</a>; | |
287 List<String> paths = <a href="#" class="dart-popover" data-toggle="popov er" title="Remaining arguments" data-html="true" data-trigger="hover focus" data -content="To get the arguments that remain after parsing all of the valid option s and flags, use the rest property.">argResults.rest</a>; | |
288 | |
289 dcat(paths, <a href="#" class="dart-popover" data-toggle="popover" title="Refe r to options and flags by name" data-html="true" data-trigger="hover focus" data -content="You can refer to an option or flag by name treating the ArgResults obj ect like a Map.">argResults[LINE_NUMBER])</a>; | |
290 } | |
291 ... | |
292 </pre> | |
293 | |
294 The | |
295 <a href="https://api.dartlang.org/args.html" target="_blank">API docs</a> | |
296 for the args library | |
297 provide detailed information | |
298 to help you use ArgsParser and ArgResults classes. | |
299 | |
300 ## Reading and writing with stdin, stdout, and stderr {#std-in-out-err} | |
301 | |
302 Like other languages, | |
303 Dart has standard output, standard error, and standard input streams. | |
304 The standard I/O streams are defined at the top level of the dart:io library, | |
305 which you import as follows: | |
306 | |
307 {% prettify dart %} | |
308 import 'dart:io'; | |
309 {% endprettify %} | |
310 | |
311 Only command-line applications, not web applications, | |
312 can use the dart:io library. | |
313 | |
314 Standard output and standard error are | |
315 <a href="https://api.dartlang.org/dart_io/IOSink.html" target="_blank">IOSink</a >s | |
316 rather than streams, but can be bound to a stream. | |
sethladd
2014/01/03 00:57:28
what is a stream?
mem
2014/01/03 17:38:02
Done.
| |
317 Standard input is a | |
318 <a href="https://api.dartlang.org/dart_async/Stream.html" target="_blank">Stream </a>. | |
319 That is, the | |
320 <a href="https://api.dartlang.org/dart_io/Stdin.html" target="_blank">Stdin</a> class | |
321 is a subclass of the Stream class. | |
322 | |
323 | Stream | Description | | |
324 |---|---| | |
325 | <a href="https://api.dartlang.org/dart_io.html#stdout" target="_blank">stdout< /a> | The standard output | | |
326 | <a href="https://api.dartlang.org/dart_io.html#stderr" target="_blank">stderr< /a> | The standard error | | |
327 | <a href="https://api.dartlang.org/dart_io.html#stdin" target="_blank">stdin</a > | The standard input | | |
328 {: .table } | |
329 | |
330 ### stdout | |
sethladd
2014/01/03 00:57:28
maybe add an aside about print(), and when to use
mem
2014/01/03 17:38:02
Done.
| |
331 | |
332 Here's the code from the `dcat` program that writes the line number to the `stdo ut` | |
333 (if the -n flag is set) followed by the line from the file. | |
334 | |
335 {% prettify dart %} | |
336 if (showLineNumbers) { | |
337 [[highlight]]stdout.write('${lineNumber++} ');[[/highlight]] | |
338 } | |
339 | |
340 [[highlight]]stdout.writeln(line);[[/highlight]] | |
341 {% endprettify %} | |
342 | |
343 The `write()` and `writeln()` methods take an object of any type, | |
344 convert it to a string, and print it. The `writeln()` method | |
345 also prints a newline character. | |
346 `dcat` uses the `write()` method to print the line number so the | |
347 line number and the text appear on the same line. | |
348 | |
349 You can also use the `writeAll()` method to print a list of objects, | |
350 or use `addStream()` to asynchronously print all of the elements from a stream. | |
351 | |
352 ### stderr | |
353 | |
354 Use `stderr` to write error messages to the console. | |
355 The standard error stream has the same methods as `stdout`, | |
356 and you use it in the same way. | |
357 Although both `stdout` and `stderr` print to the console | |
358 their output is separate | |
359 and can be redirected or piped at the command line | |
360 or programmatically to different destinations. | |
361 | |
362 This code from `dcat` prints an error message if the user | |
363 tries to list a directory or if the file is not found. | |
364 | |
365 {% prettify dart %} | |
366 if (isDir) { | |
367 [[highlight]]stderr.writeln('error: $path is a directory');[[/highlight]] | |
368 } else { | |
369 [[highlight]]stderr.writeln('error: $path not found');[[/highlight]] | |
370 } | |
371 {% endprettify %} | |
372 | |
373 ### stdin | |
sethladd
2014/01/03 00:57:28
I think it would be nice to bring these sub-sectio
mem
2014/01/03 17:38:02
Done.
| |
374 | |
375 The standard input stream typically | |
376 reads data synchronously from the keyboard, | |
377 although it can read asynchronously | |
378 and it can get input piped in from the standard | |
379 output of another program. | |
380 | |
381 Here's a small program that reads a single line from `stdin`: | |
382 | |
383 {% prettify dart %} | |
384 import 'dart:io'; | |
385 | |
386 void main() { | |
387 stdout.writeln('Type something'); | |
388 String input = stdin.readLineSync(); | |
389 stdout.writeln('You typed: $input'); | |
390 } | |
391 {% endprettify %} | |
392 | |
393 The `readLineSync()` method reads text from the standard input stream, | |
394 blocking until the user types in text and presses return. | |
395 This little program prints out the typed text. | |
396 | |
397 In the `dcat` program, | |
398 if the user does not provide a filename on the command line, | |
399 the program instead reads synchronously from stdin | |
400 using the `pipe()` method. | |
401 | |
402 {% prettify dart %} | |
403 return [[highlight]]stdin[[/highlight]].pipe(stdout); | |
404 {% endprettify %} | |
405 | |
406 In this case, | |
407 the user types in lines of text and the program copies them to stdout. | |
408 The user signals the end of input by typing <ctl-d>. | |
409 | |
410 {% prettify bash %} | |
411 $ [[highlight]]dart dcat.dart[[/highlight]] | |
412 [[highlight]]The quick brown fox jumped over the lazy dog.[[/highlight]] | |
413 The quick brown fox jumped over the lazy dog. | |
414 ... | |
415 {% endprettify %} | |
416 | |
417 ## Getting info about a file {#filesystementity} | |
418 | |
419 The | |
420 <a href="https://api.dartlang.org/dart_io/FileSystemEntity.html" target="_blank" >FileSystemEntity</a> | |
421 class in the dart:io library provides | |
422 properties and static methods that help you inspect and manipulate the file syst em. | |
423 | |
424 For example, if you have a path, | |
425 you can determine whether the path is a file, a directory, a link, or not found | |
426 by using the `type()` method from the `FileSystemEntity` class. | |
427 Because the `type()` method accesses the file system, | |
428 it performs the check asynchronously within a Future. | |
429 | |
430 The following code from | |
431 the `dcat` example uses `FileSystemEntity` to determine if the path provided | |
432 on the command line is a directory. | |
433 The Future returns a boolean that indicates | |
434 if the path is a directory or not. | |
435 | |
436 {% prettify dart %} | |
437 [[highlight]]FileSystemEntity.isDirectory(path)[[/highlight]].then((isDir) { | |
438 if (isDir) { | |
439 stderr.writeln('error: $path is a directory'); | |
440 } else { | |
441 stderr.writeln('error: $path not found'); | |
442 } | |
443 exit(2); | |
444 }); | |
445 {% endprettify %} | |
446 | |
447 Other interesting methods in the `FileSystemEntity` class | |
448 include `isFile()`, `exists()`, `stat()`, `delete()`, | |
449 and `rename()`, | |
450 all of which also use a Future to return a value. | |
451 | |
452 FileSystemEntity is the superclass for the File, Directory, and Link classes. | |
453 | |
454 ## Reading a file {#reading-a-file} | |
455 | |
456 `dcat` opens each file listed on the command line | |
457 with the `openRead()` method, | |
458 which returns a stream. | |
459 The `listen()` method registers a callback function that runs | |
460 when data becomes available on the stream. | |
461 The callback function writes that data to stdout. | |
462 | |
463 {% prettify dart %} | |
464 return Future.forEach(paths, (path) { | |
465 int lineNumber = 1; | |
466 Stream<List<int>> stream = new File(path).openRead(); | |
467 | |
468 return stream | |
469 ... | |
470 [[highlight]].listen((line) { | |
471 if (showLineNumbers) { | |
472 stdout.write('${lineNumber++} '); | |
473 } | |
474 stdout.writeln(line); | |
475 })[[/highlight]].asFuture() | |
476 .then((_) { exitCode = 1; }) | |
477 .catchError((_) => _handleError(path)); | |
478 }); | |
479 {% endprettify %} | |
480 | |
481 This code uses two decoders that transform the data before the | |
482 `listen()` callback function runs. | |
483 The UTF8 decoder converts the data into Dart strings. | |
484 `LineSplitter` splits the data at newlines. | |
485 | |
486 {% prettify dart %} | |
487 return Future.forEach(paths, (path) { | |
488 int lineNumber = 1; | |
489 Stream<List<int>> stream = new File(path).openRead(); | |
490 | |
491 return stream | |
492 [[highlight]].transform(UTF8.decoder) | |
493 .transform(const LineSplitter())[[/highlight]] | |
494 .listen((line) { | |
495 if (showLineNumbers) { | |
496 stdout.write('${lineNumber++} '); | |
497 } | |
498 stdout.writeln(line); | |
499 }).asFuture() | |
500 .then((_) { exitCode = 1; }) | |
501 .catchError((_) => _handleError(path)); | |
502 }); | |
503 {% endprettify %} | |
504 | |
505 The dart:convert library contains these and other data converters, including | |
506 one for JSON. | |
507 To use these converters you need to import the dart:convert library: | |
508 | |
509 {% prettify dart %} | |
510 import 'dart:convert'; | |
511 {% endprettify %} | |
512 | |
513 ## Writing a file {#writing-a-file} | |
514 | |
515 The easiest way to write text to a file is to | |
516 create a | |
517 <a href="https://api.dartlang.org/dart_io/File.html" target="_blank">File</a> | |
518 object and use the `writeAsString()` method: | |
519 | |
520 {% prettify dart %} | |
521 File quotesFile = new File('quotes.txt'); | |
522 String stronger = 'That which does not kill us makes us stronger. -Nietzsche'; | |
523 | |
524 quotesFile.writeAsString(stronger, mode: FileMode.APPEND) | |
525 .then((_) { print('Data written.'); }); | |
526 {% endprettify %} | |
527 | |
528 The `writeAsString()` method writes the data asynchronously via a Future. | |
529 It opens the file before writing and closes the file when done. | |
530 To append data to an existing file, you can use the optional | |
531 parameter `mode` and set its value to `FileMode.APPEND`. | |
532 Otherwise, the mode is `FileMode.WRITE` and the previous contents of the file, | |
533 if any, are overwritten. | |
534 | |
535 If you want to write more data, you can open the file for writing. | |
536 The `openWrite()` method returns an IOSink (the same type as stdin and stderr). | |
537 You can continue to write to the file until done, | |
538 at which time, you must close the file. | |
539 The `close()` method is asynchronous and returns a Future. | |
540 | |
541 {% prettify dart %} | |
542 IOSink quotes = new File('quotes.txt').openWrite(mode: FileMode.APPEND); | |
543 | |
544 quotes.write('A woman is like a tea bag; '); | |
545 quotes.write("you never know how strong it is until it's in hot water."); | |
546 quotes.writeln(" -Eleanor Roosevelt"); | |
547 quotes.close().then((_) { print('done'); } ); | |
548 {% endprettify %} | |
549 | |
550 ## Getting environment information {#env-var} | |
551 | |
552 Use the | |
553 <a href="https://api.dartlang.org/dart_io/Platform.html" target="_blank">Platfor m</a> | |
554 class | |
555 to get information about the machine and OS that the program is running on. | |
556 Note: Use the Platform class from the dart:io library, | |
557 not from the dart:html library. | |
558 | |
559 The `environment` property returns a Map that contains all | |
560 the environment variables currently set. | |
561 | |
562 {% prettify dart %} | |
563 Map environmentVars = Platform.environment; | |
564 | |
565 print('PWD = ${environmentVars["PWD"]}'); | |
566 print('LOGNAME = ${environmentVars["LOGNAME"]}'); | |
567 print('PATH = ${environmentVars["PATH"]}'); | |
568 | |
569 environmentVars['MEANINGOFLIFE'] = 42; // Not persistent. | |
570 | |
571 print('MEANINGOFLIFE = ${environmentVars["MEANINGOFLIFE"]}'); | |
572 {% endprettify %} | |
573 | |
574 As you can see from the code, you can change values | |
575 in the Map. However, these do not persist. If you refer to | |
sethladd
2014/01/03 00:57:28
persist is a bit overloaded. I think this is a bug
mem
2014/01/03 17:38:02
Done.
| |
576 `Platform.environment` again, your changes will not be there. | |
577 | |
578 `Platform` provides other useful properties that give | |
579 information about the machine, OS, and currently | |
580 running program. | |
581 For example: | |
582 | |
583 * `Platform.isMacOS()` | |
584 * `Platform.numberOfProcessors` | |
585 * Platform.script.path | |
586 | |
587 ## Setting exit codes {#exit-codes} | |
588 | |
589 The dart:io library defines a top-level property, | |
590 `exitCode`, that you can change to set the exit code for | |
sethladd
2014/01/03 00:57:28
define what an exit code is
mem
2014/01/03 17:38:02
Done.
| |
591 the current invocation of the Dart VM. | |
592 | |
593 The `dcat` example sets the program's exit code | |
594 in two different places. | |
595 First, at the very beginning of `main()`, | |
596 the program sets the exit code to 0. | |
597 | |
598 {% prettify dart %} | |
599 ... | |
600 void main(List<String> arguments) { | |
601 exitCode = 0; // Presume success. | |
sethladd
2014/01/03 00:57:28
weird that it sets it to zero at the beginning.
mem
2014/01/03 17:38:02
Done.
| |
602 ... | |
603 } | |
604 ... | |
605 {% endprettify %} | |
606 | |
607 The last assignment to `exitCode` provides the final exit code for the program. | |
608 So, if the `dcat` program does not set the exit code again, | |
609 it exits with a code of 0, which indicates success. | |
610 | |
611 Second, the program sets the error code | |
612 in the `_handleError()` function. | |
613 | |
614 {% prettify dart %} | |
615 _handleError(String path) { | |
616 FileSystemEntity.isDirectory(path).then((isDir) { | |
617 if (isDir) { | |
618 stderr.writeln('error: $path is a directory'); | |
619 } else { | |
620 stderr.writeln('error: $path not found'); | |
621 } | |
622 [[highlight]]exitCode = 2;[[/highlight]] | |
623 }); | |
624 } | |
625 {% endprettify %} | |
626 | |
627 An exit code of 2 indicates that the program encountered an error. | |
628 | |
629 An alternative to using `exitCode` is to use the top-level `exit()` function, | |
630 which sets the exit code and quits the program immediately. | |
631 For example, the `_handleError()` function could call `exit(2) | |
sethladd
2014/01/03 00:57:28
missing a closing `
mem
2014/01/03 17:38:02
Done.
| |
632 instead of setting `exitCode` to 2. | |
633 Generally speaking, you are better off using the `exitCode` property, | |
sethladd
2014/01/03 00:57:28
make this bolder, more obvious. Do we have a "Mary
mem
2014/01/03 17:38:02
Done.
| |
634 which sets the exit code but allows the program to continue through to its | |
635 natural completion. | |
636 | |
637 Although you can use any number for an exit code, | |
638 by convention, the codes in the table below have the following meanings: | |
639 | |
640 | Code | Meaning | | |
641 |---|---| | |
642 | 0 | Success | | |
643 | 1 | Warnings | | |
644 | 2 | Errors | | |
645 {: .table } | |
646 | |
647 ### Another example: dgrep {#dgrep-code} | |
sethladd
2014/01/03 00:57:28
I think this is the wrong header level? Too low.
sethladd
2014/01/03 00:57:28
Consider dropping this section. It doesn't provide
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
Done.
| |
648 | |
649 Here's the code for `dgrep`, a simplified version of the Unix utility grep | |
sethladd
2014/01/03 00:57:28
Again, what is grep?
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
Done.
| |
650 called `dgrep`. | |
651 This program makes use of some additional APIs that don't | |
sethladd
2014/01/03 00:57:28
instead of "additional APIs", how about enumeratin
mem
2014/01/03 17:38:02
Done.
| |
652 appear in the `dcat` example. | |
653 | |
654 <pre class="prettyprint lang-dart"> | |
655 import 'dart:io'; | |
656 import 'package:args/args.dart'; | |
657 | |
658 const USAGE = 'usage: dart dgrep.dart [-rnS] patterns file_or_directory'; | |
659 const RECURSIVE = 'recursive'; | |
660 const LINE_NUMBER = 'line-number'; | |
661 const FOLLOW_LINKS = 'follow-links'; | |
662 | |
663 ArgResults argResults; | |
664 | |
665 void main(List<String> arguments) { | |
666 final parser = new ArgParser() | |
667 ..addFlag(RECURSIVE, negatable: false, abbr: 'r') | |
668 ..addFlag(LINE_NUMBER, negatable: false, abbr: 'n') | |
669 ..addFlag(FOLLOW_LINKS, negatable: false, abbr: 'S'); | |
670 | |
671 argResults = parser.parse(arguments); | |
672 | |
673 if (argResults.rest.length < 2) { | |
674 print(USAGE); | |
675 exit(1); | |
676 } | |
677 | |
678 final searchPath = <a href="#" class="dart-popover" data-toggle="popover" titl e="The rest property is a List." data-html="true" data-trigger="hover focus" dat a-content="ArgResults.rest is a list. Use the last property to get the last comm and-line argument.">argResults.rest.last;</a> | |
sethladd
2014/01/03 00:57:28
not that interesting, consider dropping (it's not
mem
2014/01/03 17:38:02
Done.
| |
679 final searchTerms = argResults.rest.sublist(0, argResults.rest.length - 1); | |
680 | |
681 FileSystemEntity.isDirectory(searchPath).then((isDir) { | |
682 if (isDir) { | |
683 final startingDir = <a href="#" class="dart-popover" data-toggle="popover" title="Create a Directory" data-html="true" data-trigger="hover focus" data-con tent="Create a new Directory object at the specified path.">new Directory(search Path);</a> | |
684 <a href="#" class="dart-popover" data-toggle="popover" title="Recursive di rectory search" data-html="true" data-trigger="hover focus" data-content="List a directory's subdirectories recursively and process each file within.">startingD ir.list(recursive: argResults[RECURSIVE], | |
685 followLinks: argResults[FOLLOW_LINKS]).listen((entity)</a > { | |
686 if (entity is File) { | |
687 searchFile(entity, searchTerms); | |
688 } | |
689 }); | |
690 } else { | |
691 searchFile(<a href="#" class="dart-popover" data-toggle="popover" title="C reate a File" data-html="true" data-trigger="hover focus" data-content="Create a new file at the specified path.">new File(searchPath)</a>, searchTerms); | |
sethladd
2014/01/03 00:57:28
This doesn't actually create a new file. I don't t
mem
2014/01/03 17:38:02
Done.
| |
692 } | |
693 }); | |
694 } | |
695 | |
696 | |
697 void printMatch(File file, List lines, int i) { | |
698 StringBuffer sb = new StringBuffer(); | |
699 if (argResults[RECURSIVE]) sb.write('${file.path}:'); | |
700 if (argResults[LINE_NUMBER]) sb.write('${i + 1}:'); | |
701 sb.write(lines[i]); | |
702 print(sb.toString()); | |
703 } | |
704 | |
705 searchFile(File file, searchTerms) { | |
706 <a href="#" class="dart-popover" data-toggle="popover" title="Read a file as l ines" data-html="true" data-trigger="hover focus" data-content="Read a file as a list of strings that contains each line separately.">file.readAsLines()</a>.the n((lines) { | |
707 for (var i = 0; i < lines.length; i++) { | |
708 bool found = false; | |
709 for (var j = 0; j < searchTerms.length && !found; j++) { | |
710 if (lines[i].contains(searchTerms[j])) { | |
711 printMatch(file, lines, i); | |
712 found = true; | |
713 } | |
714 } | |
715 } | |
716 }).catchError(print); | |
717 } | |
718 | |
719 </pre> | |
720 | |
721 ## Summary {#summary} | |
722 | |
723 This tutorial described some basic API found in these classes from the dart:io l ibrary: | |
724 | |
725 | API | Description | | |
726 |---|---| | |
727 | <a href="https://api.dartlang.org/dart_io/IOSink.html" target="_blank">IOSink< /a> | Helper class for objects that consume data from streams. | | |
728 | <a href="https://api.dartlang.org/dart_io/File.html" target="_blank">File</a> | Represents a file on the native file system | | |
729 | <a href="https://api.dartlang.org/dart_io/Directory.html" target="_blank">Dire ctory</a> | Represents a directory on the native file system | | |
730 | <a href="https://api.dartlang.org/dart_io/FileSystemEntity.html" target="_blan k">FileSystemEntity</a> | Superclass for File and Directory | | |
731 | <a href="https://api.dartlang.org/dart_io/Platform.html" target="_blank">Platf orm</a> | Provides information about the machine and operating system | | |
732 | <a href="https://api.dartlang.org/dart_io.html#stdout" target="_blank">stdout< /a> | The standard output | | |
733 | <a href="https://api.dartlang.org/dart_io.html#stderr" target="_blank">stderr< /a> | The standard error | | |
734 | <a href="https://api.dartlang.org/dart_io.html#stdin" target="_blank">stdin</a > | The standard input | | |
735 | <a href="https://api.dartlang.org/dart_io.html#exitCode" target="_blank">exitC ode</a> | Sets the exit code | | |
736 | <a href="https://api.dartlang.org/dart_io.html#exit" target="_blank">exit()</a > | Sets the exit code and quits | | |
737 {: .table } | |
738 | |
739 In addition, this tutorial covers two classes that help with command-line argume nts: | |
740 | |
741 | Class | Description | | |
742 |---|---| | |
743 | <a href="https://api.dartlang.org/args/ArgParser" target="_blank">ArgParser</a > | A class that transforms a list of raw arguments and into a set of options, f lags, and remaining values. | | |
744 | <a href="https://api.dartlang.org/args/ArgResults" target="_blank">ArgResults< /a> | The result of parsing raw command line arguments using ArgParser. | | |
745 {: .table } | |
746 | |
747 ## Other resources {#other-resources} | |
748 | |
749 See the | |
750 [Dartiverse Search walkthrough](/docs/dart-up-and-running/contents/ch05.html) | |
751 for an example of another kind of command-line app: an HTTP server. | |
752 | |
753 Refer to the API docs for <a href="https://api.dartlang.org/dart_io.html" target ="_blank">dart:io</a>, | |
754 <a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async</a >, | |
755 <a href="https://api.dartlang.org/dart_convert.html" target="_blank">dart:conver t</a>, | |
756 and the | |
757 <a href="https://api.dartlang.org/dart_args.html" target="_blank">args</a> | |
758 package for more classes, functions, and properties. | |
759 | |
760 ## What next? {#what-next} | |
761 | |
762 The [Get Input from a Form](/docs/tutorials/forms/) tutorial | |
763 features a client-server. | |
764 The code for the server, which uses CORS headers and handles | |
765 POST requests, is explained in detail. | |
766 | |
767 {% endcapture %} | |
768 | |
769 {% include tutorial.html %} | |
OLD | NEW |