| 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 |