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 %} | |
15 | |
16 * Server-side applications need to do input and output. | |
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? | |
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 command-line apps</h3> | |
Kathy Walrath
2013/12/20 23:12:16
change "command-line apps" to something else. (not
mem
2013/12/30 22:17:13
Done.
| |
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. | |
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 code](#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 * [Other resources](#other-resources) | |
77 * [What next?](#what-next) | |
78 | |
79 ## Run an app with the standalone Dart VM {#run-the-first-app} | |
80 | |
81 To run a command-line app, you need the Dart VM, | |
Kathy Walrath
2013/12/20 23:12:16
VM, -> VM (`dart`),
mem
2013/12/30 22:17:13
Done.
| |
82 which comes with the Dart Editor or the Dart SDK download. | |
Kathy Walrath
2013/12/20 23:12:16
-> which comes with the Dart Editor (in the Dart d
mem
2013/12/30 22:17:13
Done.
| |
83 For example, | |
84 suppose you installed the Dart download in a directory called `~/myDartDownload` , | |
Kathy Walrath
2013/12/20 23:12:16
For example, suppose you installed -> If you insta
mem
2013/12/30 22:17:13
Done.
| |
85 you can find the Dart VM, called `dart`, | |
Kathy Walrath
2013/12/20 23:12:16
the Dart VM, called `dart`, -> `dart`
mem
2013/12/30 22:17:13
Done.
| |
86 in `~/myDartDownload/dart-sdk/bin`. | |
87 | |
88 <div markdown="1"> | |
89 | |
90  | |
91 | |
92 </div> | |
93 | |
94 By putting this directory in your PATH | |
95 you can refer to the `dart` command and other commands, | |
96 such as the dart analyzer, by name. | |
97 | |
98 Let's run a small program. | |
99 | |
100 <ol> | |
101 <li markdown="1"> | |
102 Create a file called `helloworld.dart` that contains this code: | |
103 | |
104 {% prettify dart %} | |
105 void main() { | |
106 int fortyTwo = 'Hello, World'; // Type mis-match | |
Kathy Walrath
2013/12/20 23:12:16
mis-match -> mismatch
(GLOBAL)
mem
2013/12/30 22:17:13
Done.
| |
107 print(fortyTwo); | |
108 } | |
109 {% endprettify %} | |
110 </li> | |
111 | |
112 <li markdown="1"> | |
113 In the directory that contains the file you just created, | |
114 run the program with the command as shown by the highlighted text. | |
115 | |
116 {% prettify bash %} | |
117 % [[highlight]]dart helloworld.dart[[/highlight]] | |
118 Hello, World! | |
119 % | |
120 {% endprettify %} | |
121 | |
122 The program runs cleanly in spite | |
123 of the type mis-match in the source code. | |
124 Types are optional in Dart and by default the Dart VM | |
125 does not do type-checking. | |
126 </li> | |
127 | |
128 <li markdown="1"> | |
129 Run the `helloworld.dart` program using the `--checked` flag: | |
130 | |
131 {% prettify bash %} | |
132 % [[highlight]]dart --checked helloworld.dart[[/highlight]] | |
133 Unhandled exception: | |
134 type 'String' is not a subtype of type 'int' of 'fortyTwo'. | |
135 ... | |
136 % | |
137 {% endprettify %} | |
138 | |
139 The program fails because the program assigns a string to an integer. | |
140 | |
141 The `--checked` option enables | |
142 assertion and type checks (checked mode). | |
143 Checked mode is useful during production for finding errors | |
Kathy Walrath
2013/12/20 23:12:16
production -> development
mem
2013/12/30 22:17:13
Done.
| |
144 related to types and for testing `assert` statements. | |
145 We recommend running your programs in checked mode during prototyping | |
146 and development and turning it off for production. | |
147 | |
148 Note that the flags and options passed to the Dart VM go before the name | |
149 of the Dart file to run. | |
150 </li> | |
151 </ol> | |
152 | |
153 ## Check out the dcat code {#dcat-code} | |
154 | |
155 Take a quick look at the code for a small sample called `dcat`, | |
156 which is a simplified implementation of the Unix cat utility. | |
157 This program uses various classes, functions, and properties | |
158 available to command-line apps, which this tutorial explains. | |
Kathy Walrath
2013/12/20 23:12:16
delete ", which this..."
Maybe tell people to hov
mem
2013/12/30 22:17:13
Done.
| |
159 | |
160 <pre class="prettyprint lang-dart"> | |
161 import 'dart:async'; | |
162 import 'dart:convert'; | |
163 import 'dart:io'; | |
164 | |
165 import 'package:args/args.dart'; | |
166 | |
167 const LINE_NUMBER = 'line-number'; | |
168 var NEWLINE = '\n'; | |
169 | |
170 ArgResults argResults; | |
171 | |
172 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>) { | |
173 exitCode = 0; //presume success. | |
174 final parser = new ArgParser() | |
175 ..addFlag(LINE_NUMBER, negatable: false, abbr: 'n'); | |
176 | |
177 <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> | |
178 List<String> paths = argResults.rest; | |
179 | |
180 dcat(paths, argResults[LINE_NUMBER]); | |
181 } | |
182 | |
183 Future dcat(List<String> paths, bool showLineNumbers) { | |
184 if (paths.isEmpty) { | |
185 // No files provided as arguments. Read from stdin and print each line. | |
186 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> | |
187 } else { | |
188 return Future.forEach(paths, (path) { | |
189 int lineNumber = 1; | |
190 <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> | |
191 return stream | |
192 <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> | |
193 .transform(const LineSplitter()) | |
194 <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> { | |
195 if (showLineNumbers) { | |
196 stdout.write('${lineNumber++} '); | |
197 } | |
198 stdout.writeln(line); | |
199 }).asFuture().catchError((_) => _handleError(path)); | |
200 }); | |
201 } | |
202 } | |
203 | |
204 _handleError(String path) { | |
205 <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) {if (isDir) { | |
Kathy Walrath
2013/12/20 23:12:16
if (isDir) {
should be on its own line, right?
mem
2013/12/30 22:17:13
Done.
| |
206 print('error: $path is a directory'); | |
207 } else { | |
208 print('error: $path not found'); | |
209 } | |
210 }); | |
211 <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> | |
212 } | |
213 | |
214 </pre> | |
215 | |
216 ## Parsing command-line arguments {#cmd-line-args} | |
217 | |
218 The | |
219 <a href="https://api.dartlang.org/args.html" target="_blank">args</a> | |
220 package provides | |
221 parser support for transforming raw command-line arguments | |
222 into a set of options, flags, and additional values. | |
223 Import the library as follows: | |
224 | |
225 {% prettify dart %} | |
226 import 'package:args/args.dart'; | |
227 {% endprettify %} | |
228 | |
229 The args library contains two classes: | |
230 | |
231 | Library | Description | | |
232 |---|---| | |
233 | <a href="https://api.dartlang.org/args/ArgParser" target="_blank">ArgParser</a > | A class that parses command-line arguments | | |
234 | <a href="https://api.dartlang.org/args/ArgResults" target="_blank">ArgResults< /a> | The result of parsing command-line arguments using ArgParser. | | |
235 {: .table } | |
236 | |
237 Let's take a look at the `dcat` sample | |
Kathy Walrath
2013/12/20 23:12:16
sample -> sample,
mem
2013/12/30 22:17:13
Done.
| |
238 which uses ArgParser and ArgResults to parse and store its command-line argument s. | |
239 | |
240 <ol> | |
241 <li markdown="1"> | |
242 Copy the sample file from the github repo: | |
243 <a href="https://github.com/dart-lang/dart-tutorials-samples/blob/master/bin/dca t.dart">dcat.dart</a>. | |
244 </li> | |
245 | |
246 <li markdown="1"> | |
247 Run the program from the command-line as shown by the highlighted text. | |
Kathy Walrath
2013/12/20 23:12:16
command-line -> command line
(since it's not an a
mem
2013/12/30 22:17:13
Done.
| |
248 | |
249 {% prettify bash %} | |
Kathy Walrath
2013/12/20 23:12:16
Weirdly, this highlights seemingly random words, s
| |
250 $ [[highlight]]dart dcat.dart -n dcat.dart[[/highlight]] | |
Kathy Walrath
2013/12/20 23:12:16
I found the -n dcat.dart confusing, since dcat.dar
mem
2013/12/30 22:17:13
Done.
| |
251 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
252 2 // for details. All rights reserved. Use of this source code is governed by a | |
253 3 // BSD-style license that can be found in the LICENSE file. | |
254 ... | |
255 {% endprettify %} | |
256 | |
257 The program displays the contents of the source code file and | |
258 preceeds each line with a line number. | |
259 </li> | |
260 | |
261 </ol> | |
262 | |
263 The following diagram shows how the `dcat` command line used above | |
264 is parsed into the `ArgResults` object. | |
265 | |
266  | |
267 | |
268 You can access flags and options by name, | |
269 treating the ArgResults object like a Map. | |
270 You can access other values with properties such as `rest`. | |
271 | |
272 Here's the code from `dcat` that deals with command-line arguments: | |
273 | |
274 <pre class="prettyprint lang-dart"> | |
275 | |
276 ... | |
277 <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> | |
278 | |
279 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>) { | |
Kathy Walrath
2013/12/20 23:12:16
command line -> command-line
:)
mem
2013/12/30 22:17:13
Done.
| |
280 final parser = new ArgParser() | |
281 <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>; | |
282 | |
283 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>; | |
284 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>; | |
285 | |
286 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>; | |
287 } | |
288 ... | |
289 </pre> | |
290 | |
291 The API docs for the | |
292 <a href="https://api.dartlang.org/args.html" target="_blank">args</a> library | |
Kathy Walrath
2013/12/20 23:12:16
This link should be on API docs (and why isn't it
mem
2013/12/30 22:17:13
it's not in markdown because I want to use target=
| |
293 provides very detailed information | |
Kathy Walrath
2013/12/20 23:12:16
provides very -> provide
mem
2013/12/30 22:17:13
Done.
| |
294 about the use of the ArgsParser and ArgResults classes. | |
Kathy Walrath
2013/12/20 23:12:16
about the use of
->
to help you use
OR
about using
mem
2013/12/30 22:17:13
Done.
| |
295 | |
296 ## Reading and writing with stdin, stdout, and stderr {#std-in-out-err} | |
297 | |
298 Like other languages, | |
299 Dart has standard output, standard error, and standard input streams. | |
300 The standard I/O streams are defined at the top-level of the dart:io library, | |
Kathy Walrath
2013/12/20 23:12:16
top-level -> top level
mem
2013/12/30 22:17:13
Done.
| |
301 which you import as follows: | |
302 | |
303 {% prettify dart %} | |
304 import 'dart:io'; | |
305 {% endprettify %} | |
306 | |
307 Only command-line applications, not web applications, | |
308 can use the dart:io library. | |
309 | |
310 Standard output and standard error are | |
311 <a href="https://api.dartlang.org/dart_io/IOSink.html" target="_blank">IOSink</a >s | |
312 rather than streams, but can be bound to a stream. | |
313 Standard input is a | |
314 <a href="https://api.dartlang.org/dart_async/Stream.html" target="_blank">Stream </a>. | |
315 That is, the | |
316 <a href="https://api.dartlang.org/dart_io/Stdin.html" target="_blank">Stdin</a> class | |
317 is a subclass of the Stream class. | |
318 | |
319 | Library | Description | | |
Kathy Walrath
2013/12/20 23:12:16
Library -> Object?
mem
2013/12/30 22:17:13
Done.
| |
320 |---|---| | |
321 | <a href="https://api.dartlang.org/dart_io.html#stdout" target="_blank">stdout< /a> | The standard output | | |
322 | <a href="https://api.dartlang.org/dart_io.html#stderr" target="_blank">stderr< /a> | The standard error | | |
323 | <a href="https://api.dartlang.org/dart_io.html#stdin" target="_blank">stdin</a > | The standard input | | |
324 {: .table } | |
325 | |
326 ### stdout | |
327 | |
328 Here's the code from the `dcat` program that writes the line number to the `stdo ut` | |
329 (if the -n flag is set) followed by the line from the file. | |
330 | |
331 {% prettify dart %} | |
332 if (showLineNumbers) { | |
333 [[highlight]]stdout.write('${lineNumber++} ');[[/highlight]] | |
334 } | |
335 | |
336 [[highlight]]stdout.writeln(line);[[/highlight]] | |
337 {% endprettify %} | |
338 | |
339 The `write()` and `writeln()` methods take an object of any type, | |
340 convert it to a string, and print it. The `writelin()` method | |
Kathy Walrath
2013/12/20 23:12:16
lin -> ln
mem
2013/12/30 22:17:13
Done.
mem
2013/12/30 22:17:13
Done.
| |
341 also prints a newline character. | |
342 `dcat` uses the `write()` method to print the line number so the | |
343 line number and the text appear on the same line. | |
344 | |
345 You can also use the `writeAll()` method to print a list of objects, | |
346 or use `addStream()` to asynchronously print all of the elements from a stream. | |
347 | |
348 ### stderr | |
349 | |
350 Use `stderr` to write error messages to the console. | |
351 The standard error stream has the same methods as `stdout`, | |
352 and you use it in the same way. | |
353 Although both `stdout` and `stderr` print to the console | |
354 their output is separate | |
355 and can be redirected or piped at the command-line to different destinations. | |
Kathy Walrath
2013/12/20 23:12:16
no - in command-line here!
mem
2013/12/30 22:17:13
Done.
| |
356 | |
357 This code from `dcat` prints an error message if the user | |
358 tries to list a directory or if the file is not found. | |
359 | |
360 {% prettify dart %} | |
361 if (isDir) { | |
362 [[highlight]]stderr.writeln('error: $path is a directory');[[/highlight]] | |
363 } else { | |
364 [[highlight]]stderr.writeln('error: $path not found');[[/highlight]] | |
365 } | |
366 {% endprettify %} | |
367 | |
368 ### stdin | |
369 | |
370 The standard input stream typically | |
371 reads data synchronously from the keyboard, | |
372 although it can read asynchronously | |
373 and it can get input piped in from the standard | |
374 output of another program. | |
375 | |
376 Here's a small program that reads a single line from `stdin`: | |
377 | |
378 {% prettify dart %} | |
379 import 'dart:io'; | |
380 import 'dart:async'; | |
381 | |
382 void main() { | |
383 stdout.writeln('What's in a name?'); | |
Kathy Walrath
2013/12/20 23:12:16
's => \'s? (This doesn't work as written, right?)
mem
2013/12/30 22:17:13
Done.
| |
384 [[highlight]]String path = stdin.readLineSync();[[/highlight]] | |
385 | |
386 FileSystemEntity.type(path).then((type) { | |
387 print(type); | |
388 }); | |
389 } | |
390 {% endprettify %} | |
391 | |
392 The `readLineSync()` method reads text from the standard input stream | |
Kathy Walrath
2013/12/20 23:12:16
stream -> stream,
mem
2013/12/30 22:17:13
Done.
| |
393 blocking until the user types in text and presses return. | |
394 This little program assumes the input is a pathname and prints out what | |
395 type of file system entity the path points to. | |
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 [[highlight]]ctl-d[[/highlight]] | |
Kathy Walrath
2013/12/20 23:12:16
ctl-d -> <ctl-d>
?
(so it'll match the descriptio
mem
2013/12/30 22:17:13
the < and gt& signs don't work with highlight.
| |
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 methods that help you inspect and manipulate the file system. | |
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. | |
Kathy Walrath
2013/12/20 23:12:16
It's a little weird that we've already seen this.
mem
2013/12/30 22:17:13
Done.
| |
426 As you saw in the previous example, | |
427 you can use the `type()` method from the `FileSystemEntity` class. | |
Kathy Walrath
2013/12/20 23:12:16
This is linked to the previous example, but not to
mem
2013/12/30 22:17:13
Done.
| |
428 Because the `type` method accesses the file system, | |
Kathy Walrath
2013/12/20 23:12:16
type or type()?
mem
2013/12/30 22:17:13
Done.
| |
429 it performs the check asynchronously within a Future. | |
430 | |
431 The following code from | |
432 the `dcat` example uses `FileSystemEntity` to determine if the path provided | |
433 on the command-line is a directory. | |
Kathy Walrath
2013/12/20 23:12:16
command-line -> command line
mem
2013/12/30 22:17:13
Done.
| |
434 The Future returns a boolean to the `then()` method that indicates | |
Kathy Walrath
2013/12/20 23:12:16
It's not actually returned to the then() method. I
mem
2013/12/30 22:17:13
Done.
| |
435 if the path is a directory or not. | |
436 | |
437 {% prettify dart %} | |
438 [[highlight]]FileSystemEntity.isDirectory(path)[[/highlight]].then((isDir) { | |
439 if (isDir) { | |
440 stderr.writeln('error: $path is a directory'); | |
441 } else { | |
442 stderr.writeln('error: $path not found'); | |
443 } | |
444 exit(2); | |
445 }); | |
446 {% endprettify %} | |
447 | |
448 Other interesting methods in the `FileSystemEntity` class | |
449 include `isFile()`, `exists()`, `stat()` and `parent`, | |
Kathy Walrath
2013/12/20 23:12:16
and -> , and
mem
2013/12/30 22:17:13
Done.
| |
450 all of which also use a Future to return a value. | |
451 `FileSystemEntity` also provides methods for deleting a file | |
452 and renaming a file. | |
Kathy Walrath
2013/12/20 23:12:16
Do they not return Futures? Or are there multiple
mem
2013/12/30 22:17:13
Done.
| |
453 | |
454 ## Reading a file {#reading-a-file} | |
455 | |
456 For each file listed on the command-line `dcat` opens it for reading | |
Kathy Walrath
2013/12/20 23:12:16
This sentence needs a little work, grammatically.
mem
2013/12/30 22:17:13
Done.
mem
2013/12/30 22:17:13
Done.
| |
457 with the `openRead()` method. | |
458 This returns a stream. | |
Kathy Walrath
2013/12/20 23:12:16
Seems awkward. Combine with previous sentence?
mem
2013/12/30 22:17:13
Done.
| |
459 The `listen()` method registers a callback function that runs | |
460 when data becomes available on the stream. | |
461 | |
462 The callback function provided by `dcat` writes the data to stdout. | |
Kathy Walrath
2013/12/20 23:12:16
This is a little disjointed. It's unclear why it's
mem
2013/12/30 22:17:13
Done.
| |
463 | |
464 {% prettify dart %} | |
465 return Future.forEach(paths, (path) { | |
466 int lineNumber = 1; | |
467 Stream<List<int>> stream = new File(path).openRead(); | |
468 | |
469 return stream | |
470 ... | |
471 [[highlight]].listen((line)[[/highlight]] { | |
472 if (showLineNumbers) { | |
473 stdout.write('${lineNumber++} '); | |
474 } | |
475 stdout.writeln(line); | |
476 }).asFuture().then((_) { exitCode = 1; }).catchError((_) => _handleError(p ath)); | |
Kathy Walrath
2013/12/20 23:12:16
reduce the line length here
mem
2013/12/30 22:17:13
Done.
| |
477 }); | |
478 {% endprettify %} | |
479 | |
480 This code uses two decoders that transform the data before the | |
481 `listen()` callback function runs. | |
482 The UTF8 decoder converts the data into Dart strings. | |
483 `LineSplitter` splits the data at newlines. | |
484 | |
485 {% prettify dart %} | |
486 return Future.forEach(paths, (path) { | |
487 int lineNumber = 1; | |
488 Stream<List<int>> stream = new File(path).openRead(); | |
489 | |
490 return stream | |
491 [[highlight]].transform(UTF8.decoder) | |
492 .transform(const LineSplitter())[[/highlight]] | |
493 .listen((line) { | |
494 if (showLineNumbers) { | |
495 stdout.write('${lineNumber++} '); | |
496 } | |
497 stdout.writeln(line); | |
498 }).asFuture().then((_) { exitCode = 1; }).catchError((_) => _handleError(p ath)); | |
Kathy Walrath
2013/12/20 23:12:16
another too-long line
mem
2013/12/30 22:17:13
Done.
| |
499 }); | |
500 {% endprettify %} | |
501 | |
Kathy Walrath
2013/12/20 23:12:16
including -> , including
mem
2013/12/30 22:17:13
Done.
| |
502 The dart:convert library contains these and other data converters including | |
503 one for JSON. | |
504 To use these converters you need to import the dart:convert library: | |
505 | |
506 {% prettify dart %} | |
507 import 'dart:convert'; | |
508 {% endprettify %} | |
509 | |
510 ## Writing a file {#writing-a-file} | |
511 | |
512 The easiest way to write text to a file is to | |
513 create a | |
514 <a href="https://api.dartlang.org/dart_io/File.html" target="_blank"> | |
515 File | |
Kathy Walrath
2013/12/20 23:12:16
remove newline after File
mem
2013/12/30 22:17:13
Done.
| |
516 </a> | |
517 object and use the `writeAsString()` method: | |
518 | |
519 {% prettify dart %} | |
520 File quotesFile = new File('quotes.txt'); | |
521 String stronger = 'That which does not kill us makes us stronger. -Friedrich Nie tzsche'; | |
Kathy Walrath
2013/12/20 23:12:16
long line
mem
2013/12/30 22:17:13
Done.
| |
522 | |
523 quotesFile.writeAsString(stronger, mode: FileMode.APPEND) | |
524 .then((_) { print('Data written.'); }); | |
525 {% endprettify %} | |
526 | |
527 The `writeAsString()` method writes the data asynchronously via a Future. | |
528 It opens the file before writing and closes the file when done. | |
529 To append data to an existing file you can use the optional | |
Kathy Walrath
2013/12/20 23:12:16
long sentence, no commas!
mem
2013/12/30 22:17:13
Done.
| |
530 parameter `mode` and set its value to `FileMode.APPEND` as we've done here. | |
531 Otherwise, the mode is `FileMode.WRITE` and the previous contents of the file, | |
532 if there is any, gets overwritten. | |
Kathy Walrath
2013/12/20 23:12:16
delete "there is"
gets -> are
mem
2013/12/30 22:17:13
Done.
| |
533 | |
534 If you want to write more data, you can open the file for writing. | |
535 The `openWrite()` method returns an IOSink (the same type as stdin and stderr). | |
536 You can continue to write to the file until done. | |
Kathy Walrath
2013/12/20 23:12:16
Combine this with the following sentence, to make
mem
2013/12/30 22:17:13
Done.
| |
537 Then you must close the file. | |
538 The `close()` method is asynchronous and returns a Future. | |
539 | |
540 {% prettify dart %} | |
541 IOSink quotes = new File('quotes.txt').openWrite(mode: FileMode.APPEND); | |
542 | |
543 quotes.write('A woman is like a tea bag; '); | |
544 quotes.write("you never know how strong it is until it's in hot water."); | |
545 quotes.writeln(" -Eleanor Roosevelt"); | |
546 quotes.close().then((_) { print('done'); } ); | |
547 {% endprettify %} | |
548 | |
549 ## Getting environment information {#env-var} | |
550 | |
551 Use the | |
552 <a href="https://api.dartlang.org/dart_io/Platform.html" target="_blank"> | |
553 Platform | |
Kathy Walrath
2013/12/20 23:12:16
remove newline after Platform
mem
2013/12/30 22:17:13
Done.
| |
554 </a> | |
555 class (from the dart:io library, not from the dart:html library) | |
Kathy Walrath
2013/12/20 23:12:16
make this io vs. html aside a note, so it doesn't
mem
2013/12/30 22:17:13
Done.
mem
2013/12/30 22:17:13
Done.
| |
556 to get information about the machine and OS that the program is running on. | |
557 | |
558 The `environmont` property returns a Map that contains all | |
Kathy Walrath
2013/12/20 23:12:16
environmOnt?
mem
2013/12/30 22:17:13
Done.
| |
559 the environment variables currently set. | |
560 | |
561 {% prettify dart %} | |
562 Map environmentVars = Platform.environment; | |
563 | |
564 print('PWD = ${environmentVars["PWD"]}'); | |
565 print('LOGNAME = ${environmentVars["LOGNAME"]}'); | |
566 print('PATH = ${environmentVars["PATH"]}'); | |
567 | |
568 environmentVars['MEANINGOFLIFE'] = 42; // Not persistent. | |
569 | |
570 print('MEANINGOFLIFE = ${environmentVars["MEANINGOFLIFE"]}'); | |
571 {% endprettify %} | |
572 | |
573 As you can see from the code, you can change values | |
574 in the Map, but these do not persist and if you refer to | |
Kathy Walrath
2013/12/20 23:12:16
, but -> However,
persist and -> persist. If
(Yo
mem
2013/12/30 22:17:13
Done.
| |
575 `Platform.environment` again, your changes will not be there. | |
576 | |
577 `Platform` provides other useful properties that give | |
578 information about the machine and OS: | |
Kathy Walrath
2013/12/20 23:12:16
Are the following all of the properties? If so, re
mem
2013/12/30 22:17:13
Done.
| |
579 | |
580 {% prettify dart %} | |
581 Platform.isMacOS() | |
582 Platform.isLinux() | |
Kathy Walrath
2013/12/20 23:12:16
usually we don't use a <pre> section for non-runni
mem
2013/12/30 22:17:13
Done.
| |
583 Platform.isWindows() | |
584 {% endprettify %} | |
585 | |
586 Get the path of the currently running program with: | |
587 | |
588 {% prettify dart %} | |
Kathy Walrath
2013/12/20 23:12:16
This seems a little weird; it's not code you'd use
mem
2013/12/30 22:17:13
Done.
| |
589 Platform.script.path; | |
590 {% endprettify %} | |
591 | |
592 ## Setting exit codes {#exit-codes} | |
593 | |
594 The dart:io library defines a top-level property | |
Kathy Walrath
2013/12/20 23:12:16
property -> property,
mem
2013/12/30 22:17:13
Done.
| |
595 `exitCode`, that you can change to set the exit code for | |
596 the current invocation of the Dart VM. | |
597 | |
598 The `dcat` example sets the program's exit code | |
599 in two different places. | |
600 First, at the very beginning of `main()`, | |
601 the program sets the exit code to 0. | |
602 | |
603 {% prettify dart %} | |
604 ... | |
605 void main(List<String> arguments) { | |
606 exitCode = 0; //presume success. | |
Kathy Walrath
2013/12/20 23:12:16
hmmm... I just noticed that comment format is diff
mem
2013/12/30 22:17:13
Done.
| |
607 ... | |
608 } | |
609 ... | |
610 {% endprettify %} | |
611 | |
612 The last assignment to `exitCode` provides the final exit code for the program. | |
613 So, if the `dcat` program does not set the exit code again, | |
614 it exits with a code of 0, which indicates success. | |
615 | |
616 Second, the program sets the error code | |
617 in the `_handleError()` function. | |
618 | |
619 {% prettify dart %} | |
620 _handleError(String path) { | |
621 FileSystemEntity.isDirectory(path).then((isDir) { | |
622 if (isDir) { | |
623 stderr.writeln('error: $path is a directory'); | |
624 } else { | |
625 stderr.writeln('error: $path not found'); | |
626 } | |
627 [[highlight]]exitCode = 2;[[/highlight]] | |
628 }); | |
629 } | |
630 {% endprettify %} | |
631 | |
632 An exit code of 2 indicates that the program encountered an error. | |
633 | |
634 An alternative to using `exitCode` is to use the top-level `exit()` function, | |
635 which sets the exit code and quits the program immediately. | |
636 For example, the `_handleError` function could use this code | |
Kathy Walrath
2013/12/20 23:12:16
_handleError -> _handleError()
mem
2013/12/30 22:17:13
Done.
mem
2013/12/30 22:17:13
Done.
| |
637 instead: | |
638 | |
639 {% prettify dart %} | |
640 _handleError(String path) { | |
Kathy Walrath
2013/12/20 23:12:16
I might just put this inline, since you don't enco
mem
2013/12/30 22:17:13
Done.
| |
641 FileSystemEntity.isDirectory(path).then((isDir) { | |
642 if (isDir) { | |
643 stderr.writeln('error: $path is a directory'); | |
644 } else { | |
645 stderr.writeln('error: $path not found'); | |
646 } | |
647 [[highlight]]exit(2);[[/highlight]] | |
648 }); | |
649 } | |
650 {% endprettify %} | |
651 | |
652 Generally speaking, you are better off using the `exitCode` property, | |
653 which sets the exit code but allows the program to continue through to its | |
654 natural completion. | |
655 | |
656 Although you can use any number for an exit code, | |
657 these are defined by convention: | |
Kathy Walrath
2013/12/20 23:12:16
I don't like "these" (or "are defined"). Rewrite i
mem
2013/12/30 22:17:13
Done.
| |
658 | |
659 | Code | Meaning | | |
660 |---|---| | |
661 | 0 | Success | | |
662 | 1 | Warnings | | |
663 | 2 | Errors | | |
664 {: .table } | |
665 | |
666 ## Check out the code for another example {#dgrep-code} | |
Kathy Walrath
2013/12/20 23:12:16
Maybe just:
## Another example: dgrep {#dgrep-cod
mem
2013/12/30 22:17:13
Done.
| |
667 | |
668 Here's the code for a simplified version of the Unix utility grep | |
Kathy Walrath
2013/12/20 23:12:16
for a... -> for `dgrep`, a ....
mem
2013/12/30 22:17:13
Done.
| |
669 called `dgrep`. | |
670 This program makes use of some additional APIs that do not | |
Kathy Walrath
2013/12/20 23:12:16
do not -> don't
mem
2013/12/30 22:17:13
Done.
| |
671 appear in the `dcat` example. | |
672 | |
673 <pre class="prettyprint lang-dart"> | |
Kathy Walrath
2013/12/20 23:12:16
why use a <pre> here instead of {% prettify... %}?
mem
2013/12/30 22:17:13
it's necessary for the popups.
| |
674 import 'dart:io'; | |
675 import 'package:args/args.dart'; | |
676 | |
677 const USAGE = 'usage: dart dgrep.dart [-rnS] patterns file_or_directory'; | |
678 const RECURSIVE = 'recursive'; | |
679 const LINE_NUMBER = 'line-number'; | |
680 const FOLLOW_LINKS = 'follow-links'; | |
681 | |
682 ArgResults argResults; | |
683 | |
684 void main(List<String> arguments) { | |
685 final parser = new ArgParser() | |
686 ..addFlag(RECURSIVE, negatable: false, abbr: 'r') | |
687 ..addFlag(LINE_NUMBER, negatable: false, abbr: 'n') | |
688 ..addFlag(FOLLOW_LINKS, negatable: false, abbr: 'S'); | |
689 | |
690 argResults = parser.parse(arguments); | |
691 | |
692 if (argResults.rest.length < 2) { | |
693 print(USAGE); | |
694 exit(1); | |
695 } | |
696 | |
697 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> | |
698 final searchTerms = argResults.rest.sublist(0, argResults.rest.length - 1); | |
699 | |
700 FileSystemEntity.isDirectory(searchPath).then((isDir) { | |
701 if (isDir) { | |
702 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 with a pathname.">new Directory(searchPath); </a> | |
Kathy Walrath
2013/12/20 23:12:16
What does "with a pathname" mean? How does it diff
mem
2013/12/30 22:17:13
Done.
| |
703 <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], | |
704 followLinks: argResults[FOLLOW_LINKS]).listen((entity)</a > { | |
705 if (entity is File) { | |
706 searchFile(entity, searchTerms); | |
707 } | |
708 }); | |
709 } else { | |
710 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 with a path">new File(searchPath)</a>, searchTerms); | |
Kathy Walrath
2013/12/20 23:12:16
path -> path.
maybe: with a path -> at the specif
mem
2013/12/30 22:17:13
Done.
| |
711 } | |
712 }); | |
713 } | |
714 | |
715 | |
716 void printMatch(File file, List lines, int i) { | |
717 StringBuffer sb = new StringBuffer(); | |
718 if (argResults[RECURSIVE]) sb.write('${file.path}:'); | |
719 if (argResults[LINE_NUMBER]) sb.write('${i + 1}:'); | |
720 sb.write(lines[i]); | |
721 print(sb.toString()); | |
722 } | |
723 | |
724 searchFile(File file, searchTerms) { | |
725 <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) { | |
726 for (var i = 0; i < lines.length; i++) { | |
727 bool found = false; | |
728 for (var j = 0; j < searchTerms.length && !found; j++) { | |
729 if (lines[i].contains(searchTerms[j])) { | |
730 printMatch(file, lines, i); | |
731 found = true; | |
732 } | |
733 } | |
734 } | |
735 }).catchError(print); | |
736 } | |
737 | |
738 </pre> | |
739 | |
740 ## Other resources {#other-resources} | |
741 | |
742 One kind of command-line app that you can write is an HTTP server. | |
Kathy Walrath
2013/12/20 23:12:16
I'd lead with the link, instead of the discussion.
| |
743 Check out the | |
744 <a href="https://code.google.com/p/dart/source/browse/branches/bleeding_edge/dar t/samples/dartiverse_search/readme.txt">dartiverse_search</a> | |
745 example to see a search app that uses HttpServer and WebSockets. | |
746 | |
747 This tutorial described some basic API found in these classes from the dart:io l ibrary: | |
Kathy Walrath
2013/12/20 23:12:16
This intro makes this sound like a summary of the
mem
2013/12/30 22:17:13
Done.
| |
748 | |
749 | Class | Description | | |
Kathy Walrath
2013/12/20 23:12:16
Class -> API?
mem
2013/12/30 22:17:13
Done.
| |
750 |---|---| | |
751 | <a href="https://api.dartlang.org/dart_io/IOSink.html" target="_blank">IOSink< /a> | Helper class for objects that consume data from streams. | | |
752 | <a href="https://api.dartlang.org/dart_io/File.html" target="_blank">File</a> | Represents a file on the native file system | | |
753 | <a href="https://api.dartlang.org/dart_io/Directory.html" target="_blank">Dire ctory</a> | Represents a directory on the native file system | | |
754 | <a href="https://api.dartlang.org/dart_io/FileSystemEntity.html" target="_blan k">FileSystemEntity</a> | Superclass for File and Directory | | |
755 | <a href="https://api.dartlang.org/dart_io/Platform.html" target="_blank">Platf orm</a> | Provides information about the machine and operating system | | |
756 | <a href="https://api.dartlang.org/dart_io.html#stdout" target="_blank">stdout< /a> | The standard output | | |
757 | <a href="https://api.dartlang.org/dart_io.html#stderr" target="_blank">stderr< /a> | The standard error | | |
758 | <a href="https://api.dartlang.org/dart_io.html#stdin" target="_blank">stdin</a > | The standard input | | |
759 | <a href="https://api.dartlang.org/dart_io.html#exitCode" target="_blank">exitC ode</a> | Sets the exit code | | |
760 | <a href="https://api.dartlang.org/dart_io.html#exit" target="_blank">exit()</a > | Sets the exit code and quits | | |
761 {: .table } | |
762 | |
763 In addition, this tutorial covers two classes that help with command-line argume nts: | |
Kathy Walrath
2013/12/20 23:12:16
This, too, is more "Summary" than "Other resources
mem
2013/12/30 22:17:13
Done.
| |
764 | |
765 | Class | Description | | |
766 |---|---| | |
767 | <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. | | |
768 | <a href="https://api.dartlang.org/args/ArgResults" target="_blank">ArgResults< /a> | The result of parsing raw command line arguments using ArgParser. | | |
769 {: .table } | |
770 | |
771 Refer to the API docs for <a href="https://api.dartlang.org/dart_io.html" target ="_blank">dart:io</a>, | |
Kathy Walrath
2013/12/20 23:12:16
This seems like genuine "Other resources" material
mem
2013/12/30 22:17:13
Done.
| |
772 <a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async</a >, | |
773 <a href="https://api.dartlang.org/dart_convert.html" target="_blank">dart:conver t</a>, | |
774 and the | |
775 <a href="https://api.dartlang.org/dart_args.html" target="_blank">args</a> | |
776 package for more classes, functions, and properties. | |
777 | |
778 ## What next? {#what-next} | |
779 | |
780 The [Get Input from a Form](/docs/tutorials/forms/) tutorial features a client-s erver example, | |
781 in which the server is an HttpServer. | |
Kathy Walrath
2013/12/20 23:12:16
Maybe delete this line, ending the sentence at "ex
mem
2013/12/30 22:17:13
Done.
| |
782 The code for the server, which uses CORS headers and handles | |
783 POST requests, is explained in detail. | |
784 | |
785 {% endcapture %} | |
786 | |
787 {% include tutorial.html %} | |
OLD | NEW |