OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 class _FileInputStream extends _BaseDataInputStream implements InputStream { | 7 |
8 _FileInputStream(String name) | 8 class _FileStream extends Stream<List<int>> { |
9 : _data = const [], | 9 // Stream controller. |
10 _position = 0, | 10 StreamController<List<int>> _controller; |
11 _filePosition = 0 { | 11 |
12 var file = new File(name); | 12 // Read the file in blocks of size 64k. |
13 var future = file.open(FileMode.READ); | 13 final int _blockSize = 64 * 1024; |
14 future.then(_setupOpenedFile) | 14 |
15 .catchError((e) { | 15 // Information about the underlying file. |
16 _reportError(e.error); | 16 String _name; |
17 }); | 17 RandomAccessFile _openedFile; |
18 } | 18 int _position; |
19 | 19 |
20 _FileInputStream.fromStdio(int fd) | 20 // Has the stream been paused or unsubscribed? |
21 : _data = const [], | 21 bool _paused = false; |
22 _position = 0, | 22 bool _unsubscribed = false; |
23 _filePosition = 0 { | 23 |
24 assert(fd == 0); | 24 // Is there a read currently in progress? |
25 _setupOpenedFile(_File._openStdioSync(fd)); | 25 bool _readInProgress = false; |
26 } | 26 |
27 | 27 // Block read but not yet send because stream is paused. |
28 void _setupOpenedFile(RandomAccessFile openedFile) { | 28 List<int> _currentBlock; |
29 _openedFile = openedFile; | 29 |
30 if (_streamMarkedClosed) { | 30 _FileStream(String this._name) : _position = 0 { |
31 // This input stream has already been closed. | 31 _setupController(); |
32 _fileLength = 0; | 32 } |
| 33 |
| 34 _FileStream.forStdin() : _position = 0 { |
| 35 _setupController(); |
| 36 } |
| 37 |
| 38 StreamSubscription<List<int>> listen(void onData(List<int> event), |
| 39 {void onError(AsyncError error), |
| 40 void onDone(), |
| 41 bool unsubscribeOnError}) { |
| 42 return _controller.stream.listen(onData, |
| 43 onError: onError, |
| 44 onDone: onDone, |
| 45 unsubscribeOnError: unsubscribeOnError); |
| 46 } |
| 47 |
| 48 void _setupController() { |
| 49 _controller = new StreamController<List<int>>( |
| 50 onSubscriptionStateChange: _onSubscriptionStateChange, |
| 51 onPauseStateChange: _onPauseStateChange); |
| 52 } |
| 53 |
| 54 Future _closeFile() { |
| 55 Future closeFuture; |
| 56 if (_openedFile != null) { |
| 57 Future closeFuture = _openedFile.close(); |
| 58 _openedFile = null; |
| 59 return closeFuture; |
| 60 } else { |
| 61 return new Future.immediate(null); |
| 62 } |
| 63 } |
| 64 |
| 65 void _readBlock() { |
| 66 // Don't start a new read if one is already in progress. |
| 67 if (_readInProgress) return; |
| 68 _readInProgress = true; |
| 69 _openedFile.length() |
| 70 .then((length) { |
| 71 if (_position >= length) { |
| 72 _readInProgress = false; |
| 73 if (!_unsubscribed) { |
| 74 _closeFile().then((_) { _controller.close(); }); |
| 75 _unsubscribed = true; |
| 76 } |
| 77 return null; |
| 78 } else { |
| 79 return _openedFile.read(_blockSize); |
| 80 } |
| 81 }) |
| 82 .then((block) { |
| 83 _readInProgress = false; |
| 84 if (block == null || _unsubscribed) { |
| 85 return; |
| 86 } |
| 87 _position += block.length; |
| 88 if (_paused) { |
| 89 _currentBlock = block; |
| 90 } else { |
| 91 _controller.add(block); |
| 92 _readBlock(); |
| 93 } |
| 94 }) |
| 95 .catchError((e) { |
| 96 if (!_unsubscribed) { |
| 97 _controller.signalError(e); |
| 98 _closeFile().then((_) { _controller.close(); }); |
| 99 _unsubscribed = true; |
| 100 } |
| 101 }); |
| 102 } |
| 103 |
| 104 void _start() { |
| 105 Future<RandomAccessFile> openFuture; |
| 106 if (_name != null) { |
| 107 openFuture = new File(_name).open(FileMode.READ); |
| 108 } else { |
| 109 openFuture = new Future.immediate(_File._openStdioSync(0)); |
| 110 } |
| 111 openFuture |
| 112 .then((RandomAccessFile opened) { |
| 113 _openedFile = opened; |
| 114 _readBlock(); |
| 115 }) |
| 116 .catchError((e) { |
| 117 _controller.signalError(e); |
| 118 _controller.close(); |
| 119 }); |
| 120 } |
| 121 |
| 122 void _resume() { |
| 123 _paused = false; |
| 124 if (_currentBlock != null) { |
| 125 _controller.add(_currentBlock); |
| 126 _currentBlock = null; |
| 127 } |
| 128 // Resume reading unless we are already done. |
| 129 if (_openedFile != null) _readBlock(); |
| 130 } |
| 131 |
| 132 void _onSubscriptionStateChange() { |
| 133 if (_controller.hasSubscribers) { |
| 134 _start(); |
| 135 } else { |
| 136 _unsubscribed = true; |
33 _closeFile(); | 137 _closeFile(); |
34 return; | 138 } |
35 } | 139 } |
36 var futureOpen = _openedFile.length(); | 140 |
37 futureOpen | 141 void _onPauseStateChange() { |
38 .then((len) { | 142 if (_controller.isPaused) { |
39 _fileLength = len; | 143 _paused = true; |
40 _fillBuffer(); | 144 } else { |
| 145 _resume(); |
| 146 } |
| 147 } |
| 148 } |
| 149 |
| 150 class _FileStreamConsumer extends StreamConsumer<List<int>, File> { |
| 151 File _file; |
| 152 Future<RandomAccessFile> _openFuture; |
| 153 StreamSubscription _subscription; |
| 154 |
| 155 _FileStreamConsumer(File this._file, FileMode mode) { |
| 156 _openFuture = _file.open(mode); |
| 157 } |
| 158 |
| 159 _FileStreamConsumer.fromStdio(int fd) { |
| 160 assert(1 <= fd && fd <= 2); |
| 161 _openFuture = new Future.immediate(_File._openStdioSync(fd)); |
| 162 } |
| 163 |
| 164 Future<File> consume(Stream<List<int>> stream) { |
| 165 Completer<File> completer = new Completer<File>(); |
| 166 _openFuture |
| 167 .then((openedFile) { |
| 168 _subscription = stream.listen( |
| 169 (d) { |
| 170 _subscription.pause(); |
| 171 openedFile.writeList(d, 0, d.length) |
| 172 .then((_) => _subscription.resume()) |
| 173 .catchError((e) { |
| 174 openedFile.close(); |
| 175 completer.completeError(e); |
| 176 }); |
| 177 }, |
| 178 onDone: () { |
| 179 // Wait for the file to close (and therefore flush) before |
| 180 // completing the future. |
| 181 openedFile.close() |
| 182 .then((_) { |
| 183 completer.complete(_file); |
| 184 }) |
| 185 .catchError((e) { |
| 186 completer.completeError(e); |
| 187 }); |
| 188 }, |
| 189 onError: (e) { |
| 190 openedFile.close(); |
| 191 completer.completeError(e); |
| 192 }, |
| 193 unsubscribeOnError: true); |
41 }) | 194 }) |
42 .catchError((e) { | 195 .catchError((e) { |
43 _reportError(e.error); | 196 completer.completeError(e); |
44 }); | 197 }); |
45 } | 198 return completer.future; |
46 | 199 } |
47 void _closeFile() { | |
48 if (_openedFile == null) { | |
49 _streamMarkedClosed = true; | |
50 return; | |
51 } | |
52 if (available() == 0) _cancelScheduledDataCallback(); | |
53 if (!_openedFile.closed) { | |
54 _openedFile.close().then((ignore) { | |
55 _streamMarkedClosed = true; | |
56 _checkScheduleCallbacks(); | |
57 }); | |
58 } | |
59 } | |
60 | |
61 void _fillBuffer() { | |
62 Expect.equals(_position, _data.length); | |
63 if (_openedFile == null) return; // Called before the file is opened. | |
64 int size = min(_bufferLength, _fileLength - _filePosition); | |
65 if (size == 0) { | |
66 _closeFile(); | |
67 return; | |
68 } | |
69 // If there is currently a _fillBuffer call waiting on read, | |
70 // let it fill the buffer instead of us. | |
71 if (_activeFillBufferCall) return; | |
72 _activeFillBufferCall = true; | |
73 var future = _openedFile.read(size); | |
74 future.then((data) { | |
75 _data = data; | |
76 _position = 0; | |
77 _filePosition += _data.length; | |
78 _activeFillBufferCall = false; | |
79 | |
80 if (_fileLength == _filePosition) { | |
81 _closeFile(); | |
82 } | |
83 _checkScheduleCallbacks(); | |
84 }).catchError((e) { | |
85 _activeFillBufferCall = false; | |
86 _reportError(e.error); | |
87 }); | |
88 } | |
89 | |
90 int available() { | |
91 return closed ? 0 : _data.length - _position; | |
92 } | |
93 | |
94 void pipe(OutputStream output, {bool close: true}) { | |
95 _pipe(this, output, close: close); | |
96 } | |
97 | |
98 void _finishRead() { | |
99 if (_position == _data.length && !_streamMarkedClosed) { | |
100 _fillBuffer(); | |
101 } else { | |
102 _checkScheduleCallbacks(); | |
103 } | |
104 } | |
105 | |
106 List<int> _read(int bytesToRead) { | |
107 List<int> result; | |
108 if (_position == 0 && bytesToRead == _data.length) { | |
109 result = _data; | |
110 _data = const []; | |
111 } else { | |
112 result = new Uint8List(bytesToRead); | |
113 result.setRange(0, bytesToRead, _data, _position); | |
114 _position += bytesToRead; | |
115 } | |
116 _finishRead(); | |
117 return result; | |
118 } | |
119 | |
120 int _readInto(List<int> buffer, int offset, int len) { | |
121 buffer.setRange(offset, len, _data, _position); | |
122 _position += len; | |
123 _finishRead(); | |
124 return len; | |
125 } | |
126 | |
127 void _close() { | |
128 _data = const []; | |
129 _position = 0; | |
130 _filePosition = 0; | |
131 _fileLength = 0; | |
132 _closeFile(); | |
133 } | |
134 | |
135 static const int _bufferLength = 64 * 1024; | |
136 | |
137 RandomAccessFile _openedFile; | |
138 List<int> _data; | |
139 int _position; | |
140 int _filePosition; | |
141 int _fileLength; | |
142 bool _activeFillBufferCall = false; | |
143 } | 200 } |
144 | 201 |
145 | 202 |
146 class _PendingOperation { | |
147 const _PendingOperation(this._id); | |
148 static const _PendingOperation CLOSE = const _PendingOperation(0); | |
149 static const _PendingOperation FLUSH = const _PendingOperation(1); | |
150 final int _id; | |
151 } | |
152 | |
153 | |
154 class _FileOutputStream extends _BaseOutputStream implements OutputStream { | |
155 _FileOutputStream(String name, FileMode mode) { | |
156 _pendingOperations = new List(); | |
157 var f = new File(name); | |
158 var openFuture = f.open(mode); | |
159 openFuture.then((openedFile) { | |
160 _file = openedFile; | |
161 _processPendingOperations(); | |
162 }).catchError((e) { | |
163 _reportError(e.error); | |
164 }); | |
165 } | |
166 | |
167 _FileOutputStream.fromStdio(int fd) { | |
168 assert(1 <= fd && fd <= 2); | |
169 _file = _File._openStdioSync(fd); | |
170 } | |
171 | |
172 bool write(List<int> buffer, [bool copyBuffer = false]) { | |
173 var data = buffer; | |
174 if (copyBuffer) { | |
175 var length = buffer.length; | |
176 data = new Uint8List(length); | |
177 data.setRange(0, length, buffer, 0); | |
178 } | |
179 if (_file == null) { | |
180 _pendingOperations.add(data); | |
181 } else { | |
182 _write(data, 0, data.length); | |
183 } | |
184 return false; | |
185 } | |
186 | |
187 bool writeFrom(List<int> buffer, [int offset = 0, int len]) { | |
188 // A copy is required by the interface. | |
189 var length = buffer.length - offset; | |
190 if (len != null) { | |
191 if (len > length) throw new RangeError.value(len); | |
192 length = len; | |
193 } | |
194 var copy = new Uint8List(length); | |
195 copy.setRange(0, length, buffer, offset); | |
196 return write(copy); | |
197 } | |
198 | |
199 | |
200 void flush() { | |
201 if (_file == null) { | |
202 _pendingOperations.add(_PendingOperation.FLUSH); | |
203 } else { | |
204 _file.flush().then((ignored) => null); | |
205 } | |
206 } | |
207 | |
208 | |
209 void close() { | |
210 _streamMarkedClosed = true; | |
211 if (_file == null) { | |
212 _pendingOperations.add(_PendingOperation.CLOSE); | |
213 } else if (!_closeCallbackScheduled) { | |
214 _file.close().then((ignore) { | |
215 if (_onClosed != null) _onClosed(); | |
216 }); | |
217 _closeCallbackScheduled = true; | |
218 } | |
219 } | |
220 | |
221 void set onNoPendingWrites(void callback()) { | |
222 _onNoPendingWrites = callback; | |
223 if ((_pendingOperations == null || _pendingOperations.length == 0) && | |
224 outstandingWrites == 0 && | |
225 !_streamMarkedClosed && | |
226 _onNoPendingWrites != null) { | |
227 Timer.run(() { | |
228 if (_onNoPendingWrites != null) { | |
229 _onNoPendingWrites(); | |
230 } | |
231 }); | |
232 } | |
233 } | |
234 | |
235 void set onClosed(void callback()) { | |
236 _onClosed = callback; | |
237 } | |
238 | |
239 void _processPendingOperations() { | |
240 _pendingOperations.forEach((buffer) { | |
241 if (buffer is _PendingOperation) { | |
242 if (identical(buffer, _PendingOperation.CLOSE)) { | |
243 close(); | |
244 } else { | |
245 assert(identical(buffer, _PendingOperation.FLUSH)); | |
246 flush(); | |
247 } | |
248 } else { | |
249 write(buffer); | |
250 } | |
251 }); | |
252 _pendingOperations = null; | |
253 } | |
254 | |
255 void _write(List<int> buffer, int offset, int len) { | |
256 outstandingWrites++; | |
257 var writeListFuture = _file.writeList(buffer, offset, len); | |
258 writeListFuture.then((ignore) { | |
259 outstandingWrites--; | |
260 if (outstandingWrites == 0 && | |
261 !_streamMarkedClosed && | |
262 _onNoPendingWrites != null) { | |
263 _onNoPendingWrites(); | |
264 } | |
265 }).catchError((e) { | |
266 outstandingWrites--; | |
267 _reportError(e.error); | |
268 }); | |
269 } | |
270 | |
271 bool get closed => _streamMarkedClosed; | |
272 | |
273 RandomAccessFile _file; | |
274 | |
275 // When this is set to true the stream is marked closed. When a | |
276 // stream is marked closed no more data can be written. | |
277 bool _streamMarkedClosed = false; | |
278 | |
279 // When this is set to true, the close callback has been scheduled and the | |
280 // stream will be fully closed once it's called. | |
281 bool _closeCallbackScheduled = false; | |
282 | |
283 // Number of writes that have not yet completed. | |
284 int outstandingWrites = 0; | |
285 | |
286 // List of pending writes that were issued before the underlying | |
287 // file was successfully opened. | |
288 List _pendingOperations; | |
289 | |
290 Function _onNoPendingWrites; | |
291 Function _onClosed; | |
292 } | |
293 | |
294 const int _EXISTS_REQUEST = 0; | 203 const int _EXISTS_REQUEST = 0; |
295 const int _CREATE_REQUEST = 1; | 204 const int _CREATE_REQUEST = 1; |
296 const int _DELETE_REQUEST = 2; | 205 const int _DELETE_REQUEST = 2; |
297 const int _OPEN_REQUEST = 3; | 206 const int _OPEN_REQUEST = 3; |
298 const int _FULL_PATH_REQUEST = 4; | 207 const int _FULL_PATH_REQUEST = 4; |
299 const int _DIRECTORY_REQUEST = 5; | 208 const int _DIRECTORY_REQUEST = 5; |
300 const int _CLOSE_REQUEST = 6; | 209 const int _CLOSE_REQUEST = 6; |
301 const int _POSITION_REQUEST = 7; | 210 const int _POSITION_REQUEST = 7; |
302 const int _SET_POSITION_REQUEST = 8; | 211 const int _SET_POSITION_REQUEST = 8; |
303 const int _TRUNCATE_REQUEST = 9; | 212 const int _TRUNCATE_REQUEST = 9; |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 } | 457 } |
549 | 458 |
550 external static _fullPath(String name); | 459 external static _fullPath(String name); |
551 | 460 |
552 String fullPathSync() { | 461 String fullPathSync() { |
553 var result = _fullPath(_name); | 462 var result = _fullPath(_name); |
554 throwIfError(result, "Cannot retrieve full path for file '$_name'"); | 463 throwIfError(result, "Cannot retrieve full path for file '$_name'"); |
555 return result; | 464 return result; |
556 } | 465 } |
557 | 466 |
558 InputStream openInputStream() { | 467 Stream<List<int>> openRead() { |
559 return new _FileInputStream(_name); | 468 return new _FileStream(_name); |
560 } | 469 } |
561 | 470 |
562 OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) { | 471 IOSink<File> openWrite([FileMode mode = FileMode.WRITE]) { |
563 if (mode != FileMode.WRITE && | 472 if (mode != FileMode.WRITE && |
564 mode != FileMode.APPEND) { | 473 mode != FileMode.APPEND) { |
565 throw new FileIOException( | 474 throw new FileIOException( |
566 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); | 475 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); |
567 } | 476 } |
568 return new _FileOutputStream(_name, mode); | 477 var consumer = new _FileStreamConsumer(this, mode); |
| 478 return new IOSink<File>(consumer); |
569 } | 479 } |
570 | 480 |
571 Future<List<int>> readAsBytes() { | 481 Future<List<int>> readAsBytes() { |
572 _ensureFileService(); | 482 _ensureFileService(); |
573 Completer<List<int>> completer = new Completer<List<int>>(); | 483 Completer<List<int>> completer = new Completer<List<int>>(); |
574 var chunks = new _BufferList(); | 484 var chunks = new _BufferList(); |
575 var stream = openInputStream(); | 485 openRead().listen( |
576 stream.onClosed = () { | 486 (d) => chunks.add(d), |
577 var result = chunks.readBytes(chunks.length); | 487 onDone: () { |
578 if (result == null) result = <int>[]; | 488 var result = chunks.readBytes(chunks.length); |
579 completer.complete(result); | 489 if (result == null) result = <int>[]; |
580 }; | 490 completer.complete(result); |
581 stream.onData = () { | 491 }, |
582 var chunk = stream.read(); | 492 onError: (e) { |
583 chunks.add(chunk); | 493 completer.completeError(e); |
584 }; | 494 }, |
585 stream.onError = (e) { | 495 unsubscribeOnError: true); |
586 completer.completeError(e); | |
587 }; | |
588 return completer.future; | 496 return completer.future; |
589 } | 497 } |
590 | 498 |
591 List<int> readAsBytesSync() { | 499 List<int> readAsBytesSync() { |
592 var opened = openSync(); | 500 var opened = openSync(); |
593 var length = opened.lengthSync(); | 501 var length = opened.lengthSync(); |
594 var result = new Uint8List(length); | 502 var result = new Uint8List(length); |
595 var read = opened.readListSync(result, 0, length); | 503 var read = opened.readListSync(result, 0, length); |
596 if (read != length) { | 504 if (read != length) { |
597 throw new FileIOException("Failed to read file"); | 505 throw new FileIOException("Failed to read file"); |
598 } | 506 } |
599 opened.closeSync(); | 507 opened.closeSync(); |
600 return result; | 508 return result; |
601 } | 509 } |
602 | 510 |
603 Future<String> readAsString([Encoding encoding = Encoding.UTF_8]) { | 511 Future<String> readAsString([Encoding encoding = Encoding.UTF_8]) { |
604 _ensureFileService(); | 512 _ensureFileService(); |
605 return readAsBytes().then((bytes) { | 513 return readAsBytes().then((bytes) { |
606 if (bytes.length == 0) return ""; | 514 return _decodeString(bytes, encoding); |
607 var decoder = _StringDecoders.decoder(encoding); | |
608 decoder.write(bytes); | |
609 return decoder.decoded(); | |
610 }); | 515 }); |
611 } | 516 } |
612 | 517 |
613 String readAsStringSync([Encoding encoding = Encoding.UTF_8]) { | 518 String readAsStringSync([Encoding encoding = Encoding.UTF_8]) { |
614 var decoder = _StringDecoders.decoder(encoding); | |
615 List<int> bytes = readAsBytesSync(); | 519 List<int> bytes = readAsBytesSync(); |
616 if (bytes.length == 0) return ""; | 520 return _decodeString(bytes, encoding); |
617 decoder.write(bytes); | |
618 return decoder.decoded(); | |
619 } | 521 } |
620 | 522 |
621 List<String> _getDecodedLines(_StringDecoder decoder) { | 523 static List<String> _decodeLines(List<int> bytes, Encoding encoding) { |
622 List<String> result = []; | 524 if (bytes.length == 0) return []; |
623 var line = decoder.decodedLine; | 525 var list = []; |
624 while (line != null) { | 526 var controller = new StreamController(); |
625 result.add(line); | 527 controller.stream |
626 line = decoder.decodedLine; | 528 .transform(new StringDecoder(encoding)) |
627 } | 529 .transform(new LineTransformer()) |
628 // If there is more data with no terminating line break we treat | 530 .listen((line) => list.add(line)); |
629 // it as the last line. | 531 controller.add(bytes); |
630 var data = decoder.decoded(); | 532 controller.close(); |
631 if (data != null) { | 533 return list; |
632 result.add(data); | |
633 } | |
634 return result; | |
635 } | 534 } |
636 | 535 |
637 Future<List<String>> readAsLines([Encoding encoding = Encoding.UTF_8]) { | 536 Future<List<String>> readAsLines([Encoding encoding = Encoding.UTF_8]) { |
638 _ensureFileService(); | 537 _ensureFileService(); |
639 Completer<List<String>> completer = new Completer<List<String>>(); | 538 Completer<List<String>> completer = new Completer<List<String>>(); |
640 return readAsBytes().then((bytes) { | 539 return readAsBytes().then((bytes) { |
641 var decoder = _StringDecoders.decoder(encoding); | 540 return _decodeLines(bytes, encoding); |
642 decoder.write(bytes); | |
643 return _getDecodedLines(decoder); | |
644 }); | 541 }); |
645 } | 542 } |
646 | 543 |
647 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) { | 544 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) { |
648 var decoder = _StringDecoders.decoder(encoding); | 545 return _decodeLines(readAsBytesSync(), encoding); |
649 List<int> bytes = readAsBytesSync(); | |
650 decoder.write(bytes); | |
651 return _getDecodedLines(decoder); | |
652 } | 546 } |
653 | 547 |
654 Future<File> writeAsBytes(List<int> bytes, | 548 Future<File> writeAsBytes(List<int> bytes, |
655 [FileMode mode = FileMode.WRITE]) { | 549 [FileMode mode = FileMode.WRITE]) { |
656 Completer<File> completer = new Completer<File>(); | 550 Completer<File> completer = new Completer<File>(); |
657 try { | 551 try { |
658 var stream = openOutputStream(mode); | 552 var stream = openWrite(mode); |
659 stream.write(bytes); | 553 stream.add(bytes); |
660 stream.close(); | 554 stream.close(); |
661 stream.onClosed = () { | 555 stream.done |
662 completer.complete(this); | 556 .then((_) { |
663 }; | 557 completer.complete(this); |
664 stream.onError = (e) { | 558 }) |
665 completer.completeError(e); | 559 .catchError((e) { |
666 }; | 560 completer.completeError(e); |
| 561 }); |
667 } catch (e) { | 562 } catch (e) { |
668 Timer.run(() => completer.completeError(e)); | 563 Timer.run(() => completer.completeError(e)); |
669 return completer.future; | 564 return completer.future; |
670 } | 565 } |
671 return completer.future; | 566 return completer.future; |
672 } | 567 } |
673 | 568 |
674 void writeAsBytesSync(List<int> bytes, [FileMode mode = FileMode.WRITE]) { | 569 void writeAsBytesSync(List<int> bytes, [FileMode mode = FileMode.WRITE]) { |
675 RandomAccessFile opened = openSync(mode); | 570 RandomAccessFile opened = openSync(mode); |
676 opened.writeListSync(bytes, 0, bytes.length); | 571 opened.writeListSync(bytes, 0, bytes.length); |
677 opened.closeSync(); | 572 opened.closeSync(); |
678 } | 573 } |
679 | 574 |
680 Future<File> writeAsString(String contents, | 575 Future<File> writeAsString(String contents, |
681 {FileMode mode: FileMode.WRITE, | 576 {FileMode mode: FileMode.WRITE, |
682 Encoding encoding: Encoding.UTF_8}) { | 577 Encoding encoding: Encoding.UTF_8}) { |
683 try { | 578 try { |
684 var data = _StringEncoders.encoder(encoding).encodeString(contents); | 579 return writeAsBytes(_encodeString(contents, encoding), mode); |
685 return writeAsBytes(data, mode); | |
686 } catch (e) { | 580 } catch (e) { |
687 var completer = new Completer(); | 581 var completer = new Completer(); |
688 Timer.run(() => completer.completeError(e)); | 582 Timer.run(() => completer.completeError(e)); |
689 return completer.future; | 583 return completer.future; |
690 } | 584 } |
691 } | 585 } |
692 | 586 |
693 void writeAsStringSync(String contents, | 587 void writeAsStringSync(String contents, |
694 {FileMode mode: FileMode.WRITE, | 588 {FileMode mode: FileMode.WRITE, |
695 Encoding encoding: Encoding.UTF_8}) { | 589 Encoding encoding: Encoding.UTF_8}) { |
696 var data = _StringEncoders.encoder(encoding).encodeString(contents); | 590 writeAsBytesSync(_encodeString(contents, encoding), mode); |
697 writeAsBytesSync(data, mode); | |
698 } | 591 } |
699 | 592 |
700 String get name => _name; | 593 String get name => _name; |
701 | 594 |
702 String toString() => "File: '$name'"; | 595 String toString() => "File: '$name'"; |
703 | 596 |
704 void _ensureFileService() { | 597 void _ensureFileService() { |
705 if (_fileService == null) { | 598 if (_fileService == null) { |
706 _fileService = _FileUtils._newServicePort(); | 599 _fileService = _FileUtils._newServicePort(); |
707 } | 600 } |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
980 Future<RandomAccessFile> writeString(String string, | 873 Future<RandomAccessFile> writeString(String string, |
981 [Encoding encoding = Encoding.UTF_8]) { | 874 [Encoding encoding = Encoding.UTF_8]) { |
982 if (encoding is! Encoding) { | 875 if (encoding is! Encoding) { |
983 var completer = new Completer(); | 876 var completer = new Completer(); |
984 Timer.run(() { | 877 Timer.run(() { |
985 completer.completeError(new FileIOException( | 878 completer.completeError(new FileIOException( |
986 "Invalid encoding in writeString: $encoding")); | 879 "Invalid encoding in writeString: $encoding")); |
987 }); | 880 }); |
988 return completer.future; | 881 return completer.future; |
989 } | 882 } |
990 var data = _StringEncoders.encoder(encoding).encodeString(string); | 883 var data = _encodeString(string, encoding); |
991 return writeList(data, 0, data.length); | 884 return writeList(data, 0, data.length); |
992 } | 885 } |
993 | 886 |
994 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) { | 887 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) { |
995 if (encoding is! Encoding) { | 888 if (encoding is! Encoding) { |
996 throw new FileIOException( | 889 throw new FileIOException( |
997 "Invalid encoding in writeStringSync: $encoding"); | 890 "Invalid encoding in writeStringSync: $encoding"); |
998 } | 891 } |
999 var data = _StringEncoders.encoder(encoding).encodeString(string); | 892 var data = _encodeString(string, encoding); |
1000 return writeListSync(data, 0, data.length); | 893 return writeListSync(data, 0, data.length); |
1001 } | 894 } |
1002 | 895 |
1003 Future<int> position() { | 896 Future<int> position() { |
1004 _ensureFileService(); | 897 _ensureFileService(); |
1005 Completer<int> completer = new Completer<int>(); | 898 Completer<int> completer = new Completer<int>(); |
1006 if (closed) return _completeWithClosedException(completer); | 899 if (closed) return _completeWithClosedException(completer); |
1007 List request = new List.fixedLength(2); | 900 List request = new List.fixedLength(2); |
1008 request[0] = _POSITION_REQUEST; | 901 request[0] = _POSITION_REQUEST; |
1009 request[1] = _id; | 902 request[1] = _id; |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 new FileIOException("File closed '$_name'")); | 1049 new FileIOException("File closed '$_name'")); |
1157 }); | 1050 }); |
1158 return completer.future; | 1051 return completer.future; |
1159 } | 1052 } |
1160 | 1053 |
1161 final String _name; | 1054 final String _name; |
1162 int _id; | 1055 int _id; |
1163 | 1056 |
1164 SendPort _fileService; | 1057 SendPort _fileService; |
1165 } | 1058 } |
OLD | NEW |