|  | // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | part of dart.io; | 
|  |  | 
|  | // Read the file in blocks of size 64k. | 
|  | const int _blockSize = 64 * 1024; | 
|  |  | 
|  | // The maximum number of bytes to read in a single call to `read`. | 
|  | // | 
|  | // On Windows and macOS, it is an error to call | 
|  | // `read/_read(fildes, buf, nbyte)` with `nbyte >= INT_MAX`. | 
|  | // | 
|  | // The POSIX specification states that the behavior of `read` is | 
|  | // implementation-defined if `nbyte > SSIZE_MAX`. On Linux, the `read` will | 
|  | // transfer at most 0x7ffff000 bytes and return the number of bytes actually. | 
|  | // transfered. | 
|  | // | 
|  | // A smaller value has the advantage of: | 
|  | // 1. making vm-service clients (e.g. debugger) more responsive | 
|  | // 2. reducing memory overhead (since `readInto` copies memory) | 
|  | // | 
|  | // A bigger value reduces the number of system calls. | 
|  | const int _maxReadSize = 16 * 1024 * 1024; // 16MB. | 
|  |  | 
|  | class _FileStream extends Stream<List<int>> { | 
|  | // Stream controller. | 
|  | late StreamController<Uint8List> _controller; | 
|  |  | 
|  | // Information about the underlying file. | 
|  | String? _path; | 
|  | RandomAccessFile? _openedFile; | 
|  | int _position; | 
|  | int? _end; | 
|  | final Completer _closeCompleter = new Completer(); | 
|  |  | 
|  | // Has the stream been paused or unsubscribed? | 
|  | bool _unsubscribed = false; | 
|  |  | 
|  | // Is there a read currently in progress? | 
|  | bool _readInProgress = true; | 
|  | bool _closed = false; | 
|  |  | 
|  | bool _atEnd = false; | 
|  |  | 
|  | _FileStream(this._path, int? position, this._end) : _position = position ?? 0; | 
|  |  | 
|  | _FileStream.forStdin() : _position = 0; | 
|  |  | 
|  | _FileStream.forRandomAccessFile(RandomAccessFile f) | 
|  | : _position = 0, | 
|  | _openedFile = f; | 
|  |  | 
|  | StreamSubscription<Uint8List> listen( | 
|  | void onData(Uint8List event)?, { | 
|  | Function? onError, | 
|  | void onDone()?, | 
|  | bool? cancelOnError, | 
|  | }) { | 
|  | _controller = new StreamController<Uint8List>( | 
|  | sync: true, | 
|  | onListen: _start, | 
|  | onResume: _readBlock, | 
|  | onCancel: () { | 
|  | _unsubscribed = true; | 
|  | return _closeFile(); | 
|  | }, | 
|  | ); | 
|  | return _controller.stream.listen( | 
|  | onData, | 
|  | onError: onError, | 
|  | onDone: onDone, | 
|  | cancelOnError: cancelOnError, | 
|  | ); | 
|  | } | 
|  |  | 
|  | Future _closeFile() { | 
|  | if (_readInProgress || _closed) { | 
|  | return _closeCompleter.future; | 
|  | } | 
|  | _closed = true; | 
|  |  | 
|  | void done() { | 
|  | _closeCompleter.complete(); | 
|  | _controller.close(); | 
|  | } | 
|  |  | 
|  | _openedFile!.close().catchError(_controller.addError).whenComplete(done); | 
|  | return _closeCompleter.future; | 
|  | } | 
|  |  | 
|  | void _readBlock() { | 
|  | // Don't start a new read if one is already in progress. | 
|  | if (_readInProgress) return; | 
|  | if (_atEnd) { | 
|  | _closeFile(); | 
|  | return; | 
|  | } | 
|  | _readInProgress = true; | 
|  | int readBytes = _blockSize; | 
|  | final end = _end; | 
|  | if (end != null) { | 
|  | readBytes = min(readBytes, end - _position); | 
|  | if (readBytes < 0) { | 
|  | _readInProgress = false; | 
|  | if (!_unsubscribed) { | 
|  | _controller.addError(new RangeError("Bad end position: $end")); | 
|  | _closeFile(); | 
|  | _unsubscribed = true; | 
|  | } | 
|  | return; | 
|  | } | 
|  | } | 
|  | _openedFile! | 
|  | .read(readBytes) | 
|  | .then((block) { | 
|  | _readInProgress = false; | 
|  | if (_unsubscribed) { | 
|  | _closeFile(); | 
|  | return; | 
|  | } | 
|  | _position += block.length; | 
|  | // read() may return less than `readBytes` if `_openFile` is a pipe or | 
|  | // terminal or if a signal is received. Only a empty return indicates | 
|  | // that the write side of the pipe is closed or that we are at the end | 
|  | // of a file. | 
|  | // See https://man7.org/linux/man-pages/man2/read.2.html | 
|  | if (block.length == 0 || (_end != null && _position == _end)) { | 
|  | _atEnd = true; | 
|  | } | 
|  | if (!_atEnd && !_controller.isPaused) { | 
|  | _readBlock(); | 
|  | } | 
|  | if (block.length > 0) { | 
|  | _controller.add(block); | 
|  | } | 
|  | if (_atEnd) { | 
|  | _closeFile(); | 
|  | } | 
|  | }) | 
|  | .catchError((e, s) { | 
|  | if (!_unsubscribed) { | 
|  | _controller.addError(e, s); | 
|  | _closeFile(); | 
|  | _unsubscribed = true; | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | void _start() { | 
|  | if (_position < 0) { | 
|  | _controller.addError(new RangeError("Bad start position: $_position")); | 
|  | _controller.close(); | 
|  | _closeCompleter.complete(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | void onReady(RandomAccessFile file) { | 
|  | _openedFile = file; | 
|  | _readInProgress = false; | 
|  | _readBlock(); | 
|  | } | 
|  |  | 
|  | void onOpenFile(RandomAccessFile file) { | 
|  | if (_position > 0) { | 
|  | file | 
|  | .setPosition(_position) | 
|  | .then( | 
|  | onReady, | 
|  | onError: (e, s) { | 
|  | _controller.addError(e, s); | 
|  | _readInProgress = false; | 
|  | _closeFile(); | 
|  | }, | 
|  | ); | 
|  | } else { | 
|  | onReady(file); | 
|  | } | 
|  | } | 
|  |  | 
|  | void openFailed(error, stackTrace) { | 
|  | _controller.addError(error, stackTrace); | 
|  | _controller.close(); | 
|  | _closeCompleter.complete(); | 
|  | } | 
|  |  | 
|  | final path = _path; | 
|  | final openedFile = _openedFile; | 
|  | if (openedFile != null) { | 
|  | onOpenFile(openedFile); | 
|  | } else if (path != null) { | 
|  | new File( | 
|  | path, | 
|  | ).open(mode: FileMode.read).then(onOpenFile, onError: openFailed); | 
|  | } else { | 
|  | try { | 
|  | onOpenFile(_File._openStdioSync(0)); | 
|  | } catch (e, s) { | 
|  | openFailed(e, s); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | class _FileStreamConsumer implements StreamConsumer<List<int>> { | 
|  | File? _file; | 
|  | Future<RandomAccessFile> _openFuture; | 
|  |  | 
|  | _FileStreamConsumer(File file, FileMode mode) | 
|  | : _file = file, | 
|  | _openFuture = file.open(mode: mode); | 
|  |  | 
|  | _FileStreamConsumer.fromStdio(int fd) | 
|  | : _openFuture = new Future.value(_File._openStdioSync(fd)); | 
|  |  | 
|  | _FileStreamConsumer.fromRandomAccessFile(RandomAccessFile f) | 
|  | : _openFuture = Future.value(f); | 
|  |  | 
|  | Future<File?> addStream(Stream<List<int>> stream) { | 
|  | Completer<File?> completer = new Completer<File?>.sync(); | 
|  | _openFuture | 
|  | .then((openedFile) { | 
|  | late StreamSubscription<List<int>> _subscription; | 
|  | void error(e, StackTrace stackTrace) { | 
|  | _subscription.cancel(); | 
|  | openedFile.close(); | 
|  | completer.completeError(e, stackTrace); | 
|  | } | 
|  |  | 
|  | _subscription = stream.listen( | 
|  | (d) { | 
|  | _subscription.pause(); | 
|  | try { | 
|  | openedFile | 
|  | .writeFrom(d, 0, d.length) | 
|  | .then((_) => _subscription.resume(), onError: error); | 
|  | } catch (e, stackTrace) { | 
|  | error(e, stackTrace); | 
|  | } | 
|  | }, | 
|  | onDone: () { | 
|  | completer.complete(_file); | 
|  | }, | 
|  | onError: error, | 
|  | cancelOnError: true, | 
|  | ); | 
|  | }) | 
|  | .catchError(completer.completeError); | 
|  | return completer.future; | 
|  | } | 
|  |  | 
|  | Future<File?> close() => | 
|  | _openFuture.then((openedFile) => openedFile.close()).then((_) => _file); | 
|  | } | 
|  |  | 
|  | // Class for encapsulating the native implementation of files. | 
|  | class _File extends FileSystemEntity implements File { | 
|  | final String _path; | 
|  | final Uint8List _rawPath; | 
|  |  | 
|  | _File(String path) | 
|  | : _path = _checkNotNull(path, "path"), | 
|  | _rawPath = FileSystemEntity._toUtf8Array(path); | 
|  |  | 
|  | _File.fromRawPath(Uint8List rawPath) | 
|  | : _rawPath = FileSystemEntity._toNullTerminatedUtf8Array( | 
|  | _checkNotNull(rawPath, "rawPath"), | 
|  | ), | 
|  | _path = FileSystemEntity._toStringFromUtf8Array(rawPath); | 
|  |  | 
|  | String get path => _path; | 
|  |  | 
|  | // WARNING: | 
|  | // Calling this function will increase the reference count on the native | 
|  | // namespace object. It should only be called to pass the pointer to the | 
|  | // IOService, which will decrement the reference count when it is finished | 
|  | // with it. | 
|  | static int _namespacePointer() => _Namespace._namespacePointer; | 
|  |  | 
|  | static Future<Object?> _dispatchWithNamespace(int request, List data) { | 
|  | data[0] = _namespacePointer(); | 
|  | return _IOService._dispatch(request, data); | 
|  | } | 
|  |  | 
|  | Future<bool> exists() { | 
|  | return _dispatchWithNamespace(_IOService.fileExists, [null, _rawPath]).then( | 
|  | (response) { | 
|  | _checkForErrorResponse(response, "Cannot check existence", path); | 
|  | return response as bool; | 
|  | }, | 
|  | ); | 
|  | } | 
|  |  | 
|  | external static _exists(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | bool existsSync() { | 
|  | var result = _exists(_Namespace._namespace, _rawPath); | 
|  | throwIfError(result, "Cannot check existence of file", path); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | File get absolute => new File(_absolutePath); | 
|  |  | 
|  | Future<File> create({bool recursive = false, bool exclusive = false}) { | 
|  | var result = | 
|  | recursive ? parent.create(recursive: true) : new Future.value(null); | 
|  | return result | 
|  | .then( | 
|  | (_) => _dispatchWithNamespace(_IOService.fileCreate, [ | 
|  | null, | 
|  | _rawPath, | 
|  | exclusive, | 
|  | ]), | 
|  | ) | 
|  | .then((response) { | 
|  | _checkForErrorResponse(response, "Cannot create file", path); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _create( | 
|  | _Namespace namespace, | 
|  | Uint8List rawPath, | 
|  | bool exclusive, | 
|  | ); | 
|  |  | 
|  | external static _createLink( | 
|  | _Namespace namespace, | 
|  | Uint8List rawPath, | 
|  | String target, | 
|  | ); | 
|  |  | 
|  | external static List<dynamic> _createPipe(_Namespace namespace); | 
|  |  | 
|  | external static _linkTarget(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | void createSync({bool recursive = false, bool exclusive = false}) { | 
|  | if (recursive) { | 
|  | parent.createSync(recursive: true); | 
|  | } | 
|  | var result = _create(_Namespace._namespace, _rawPath, exclusive); | 
|  | throwIfError(result, "Cannot create file", path); | 
|  | } | 
|  |  | 
|  | Future<File> _delete({bool recursive = false}) { | 
|  | if (recursive) { | 
|  | return new Directory(path).delete(recursive: true).then((_) => this); | 
|  | } | 
|  | return _dispatchWithNamespace(_IOService.fileDelete, [null, _rawPath]).then( | 
|  | (response) { | 
|  | _checkForErrorResponse(response, "Cannot delete file", path); | 
|  | return this; | 
|  | }, | 
|  | ); | 
|  | } | 
|  |  | 
|  | external static _deleteNative(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | external static _deleteLinkNative(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | void _deleteSync({bool recursive = false}) { | 
|  | if (recursive) { | 
|  | return new Directory.fromRawPath(_rawPath).deleteSync(recursive: true); | 
|  | } | 
|  | var result = _deleteNative(_Namespace._namespace, _rawPath); | 
|  | throwIfError(result, "Cannot delete file", path); | 
|  | } | 
|  |  | 
|  | Future<File> rename(String newPath) { | 
|  | return _dispatchWithNamespace(_IOService.fileRename, [ | 
|  | null, | 
|  | _rawPath, | 
|  | newPath, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse( | 
|  | response, | 
|  | "Cannot rename file to '$newPath'", | 
|  | path, | 
|  | ); | 
|  | return new File(newPath); | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _rename( | 
|  | _Namespace namespace, | 
|  | Uint8List oldPath, | 
|  | String newPath, | 
|  | ); | 
|  |  | 
|  | external static _renameLink( | 
|  | _Namespace namespace, | 
|  | Uint8List oldPath, | 
|  | String newPath, | 
|  | ); | 
|  |  | 
|  | File renameSync(String newPath) { | 
|  | var result = _rename(_Namespace._namespace, _rawPath, newPath); | 
|  | throwIfError(result, "Cannot rename file to '$newPath'", path); | 
|  | return new File(newPath); | 
|  | } | 
|  |  | 
|  | Future<File> copy(String newPath) { | 
|  | return _dispatchWithNamespace(_IOService.fileCopy, [ | 
|  | null, | 
|  | _rawPath, | 
|  | newPath, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse(response, "Cannot copy file to '$newPath'", path); | 
|  | return new File(newPath); | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _copy( | 
|  | _Namespace namespace, | 
|  | Uint8List oldPath, | 
|  | String newPath, | 
|  | ); | 
|  |  | 
|  | File copySync(String newPath) { | 
|  | var result = _copy(_Namespace._namespace, _rawPath, newPath); | 
|  | throwIfError(result, "Cannot copy file to '$newPath'", path); | 
|  | return new File(newPath); | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> open({FileMode mode = FileMode.read}) { | 
|  | if (mode != FileMode.read && | 
|  | mode != FileMode.write && | 
|  | mode != FileMode.append && | 
|  | mode != FileMode.writeOnly && | 
|  | mode != FileMode.writeOnlyAppend) { | 
|  | return new Future.error( | 
|  | new ArgumentError('Invalid file mode for this operation'), | 
|  | ); | 
|  | } | 
|  | return _dispatchWithNamespace(_IOService.fileOpen, [ | 
|  | null, | 
|  | _rawPath, | 
|  | mode._mode, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse(response, "Cannot open file", path); | 
|  | return _RandomAccessFile(response as int, path); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future<int> length() { | 
|  | return _dispatchWithNamespace(_IOService.fileLengthFromPath, [ | 
|  | null, | 
|  | _rawPath, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse(response, "Cannot retrieve length of file", path); | 
|  | return response as int; | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _lengthFromPath(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | int lengthSync() { | 
|  | var result = _lengthFromPath(_Namespace._namespace, _rawPath); | 
|  | throwIfError(result, "Cannot retrieve length of file", path); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<DateTime> lastAccessed() { | 
|  | return _dispatchWithNamespace(_IOService.fileLastAccessed, [ | 
|  | null, | 
|  | _rawPath, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse(response, "Cannot retrieve access time", path); | 
|  | return DateTime.fromMillisecondsSinceEpoch(response as int); | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _lastAccessed(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | DateTime lastAccessedSync() { | 
|  | var ms = _lastAccessed(_Namespace._namespace, _rawPath); | 
|  | throwIfError(ms, "Cannot retrieve access time", path); | 
|  | return new DateTime.fromMillisecondsSinceEpoch(ms); | 
|  | } | 
|  |  | 
|  | Future setLastAccessed(DateTime time) { | 
|  | int millis = time.millisecondsSinceEpoch; | 
|  | return _dispatchWithNamespace(_IOService.fileSetLastAccessed, [ | 
|  | null, | 
|  | _rawPath, | 
|  | millis, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse(response, "Cannot set access time", path); | 
|  | return null; | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _setLastAccessed( | 
|  | _Namespace namespace, | 
|  | Uint8List rawPath, | 
|  | int millis, | 
|  | ); | 
|  |  | 
|  | void setLastAccessedSync(DateTime time) { | 
|  | int millis = time.millisecondsSinceEpoch; | 
|  | var result = _setLastAccessed(_Namespace._namespace, _rawPath, millis); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException( | 
|  | "Failed to set file access time", | 
|  | path, | 
|  | result, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<DateTime> lastModified() { | 
|  | return _dispatchWithNamespace(_IOService.fileLastModified, [ | 
|  | null, | 
|  | _rawPath, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse( | 
|  | response, | 
|  | "Cannot retrieve modification time", | 
|  | path, | 
|  | ); | 
|  | return DateTime.fromMillisecondsSinceEpoch(response as int); | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _lastModified(_Namespace namespace, Uint8List rawPath); | 
|  |  | 
|  | DateTime lastModifiedSync() { | 
|  | var ms = _lastModified(_Namespace._namespace, _rawPath); | 
|  | throwIfError(ms, "Cannot retrieve modification time", path); | 
|  | return new DateTime.fromMillisecondsSinceEpoch(ms); | 
|  | } | 
|  |  | 
|  | Future setLastModified(DateTime time) { | 
|  | int millis = time.millisecondsSinceEpoch; | 
|  | return _dispatchWithNamespace(_IOService.fileSetLastModified, [ | 
|  | null, | 
|  | _rawPath, | 
|  | millis, | 
|  | ]).then((response) { | 
|  | _checkForErrorResponse(response, "Cannot set modification time", path); | 
|  | return null; | 
|  | }); | 
|  | } | 
|  |  | 
|  | external static _setLastModified( | 
|  | _Namespace namespace, | 
|  | Uint8List rawPath, | 
|  | int millis, | 
|  | ); | 
|  |  | 
|  | void setLastModifiedSync(DateTime time) { | 
|  | int millis = time.millisecondsSinceEpoch; | 
|  | var result = _setLastModified(_Namespace._namespace, _rawPath, millis); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException( | 
|  | "Failed to set file modification time", | 
|  | path, | 
|  | result, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | external static _open(_Namespace namespace, Uint8List rawPath, int mode); | 
|  |  | 
|  | RandomAccessFile openSync({FileMode mode = FileMode.read}) { | 
|  | if (mode != FileMode.read && | 
|  | mode != FileMode.write && | 
|  | mode != FileMode.append && | 
|  | mode != FileMode.writeOnly && | 
|  | mode != FileMode.writeOnlyAppend) { | 
|  | throw new ArgumentError('Invalid file mode for this operation'); | 
|  | } | 
|  | var id = _open(_Namespace._namespace, _rawPath, mode._mode); | 
|  | throwIfError(id, "Cannot open file", path); | 
|  | return new _RandomAccessFile(id, _path); | 
|  | } | 
|  |  | 
|  | external static int _openStdio(int fd); | 
|  |  | 
|  | static RandomAccessFile _openStdioSync(int fd) { | 
|  | var id = _openStdio(fd); | 
|  | if (id == 0) { | 
|  | throw new FileSystemException("Cannot open stdio file for: $fd"); | 
|  | } | 
|  | return new _RandomAccessFile(id, ""); | 
|  | } | 
|  |  | 
|  | Stream<List<int>> openRead([int? start, int? end]) { | 
|  | return new _FileStream(path, start, end); | 
|  | } | 
|  |  | 
|  | IOSink openWrite({FileMode mode = FileMode.write, Encoding encoding = utf8}) { | 
|  | if (mode != FileMode.write && | 
|  | mode != FileMode.append && | 
|  | mode != FileMode.writeOnly && | 
|  | mode != FileMode.writeOnlyAppend) { | 
|  | throw new ArgumentError('Invalid file mode for this operation'); | 
|  | } | 
|  | var consumer = new _FileStreamConsumer(this, mode); | 
|  | return new IOSink(consumer, encoding: encoding); | 
|  | } | 
|  |  | 
|  | Future<Uint8List> readAsBytes() { | 
|  | Future<Uint8List> readUnsized(RandomAccessFile file) { | 
|  | var builder = new BytesBuilder(copy: false); | 
|  | var completer = new Completer<Uint8List>(); | 
|  | void read() { | 
|  | file.read(_blockSize).then((data) { | 
|  | if (data.length > 0) { | 
|  | builder.add(data); | 
|  | read(); | 
|  | } else { | 
|  | completer.complete(builder.takeBytes()); | 
|  | } | 
|  | }, onError: completer.completeError); | 
|  | } | 
|  |  | 
|  | read(); | 
|  | return completer.future; | 
|  | } | 
|  |  | 
|  | Future<Uint8List> readSized(RandomAccessFile file, int length) { | 
|  | var data = Uint8List(length); | 
|  | var offset = 0; | 
|  | var completer = new Completer<Uint8List>(); | 
|  | void read() { | 
|  | file.readInto(data, offset, min(offset + _maxReadSize, length)).then(( | 
|  | readSize, | 
|  | ) { | 
|  | if (readSize > 0) { | 
|  | offset += readSize; | 
|  | read(); | 
|  | } else { | 
|  | assert(readSize == 0); | 
|  | if (offset < length) { | 
|  | data = Uint8List.sublistView(data, 0, offset); | 
|  | } | 
|  | completer.complete(data); | 
|  | } | 
|  | }, onError: completer.completeError); | 
|  | } | 
|  |  | 
|  | read(); | 
|  | return completer.future; | 
|  | } | 
|  |  | 
|  | return open().then((file) { | 
|  | return file | 
|  | .length() | 
|  | .then((length) { | 
|  | if (length == 0) { | 
|  | // May be character device, try to read it in chunks. | 
|  | return readUnsized(file); | 
|  | } | 
|  | return readSized(file, length); | 
|  | }) | 
|  | .whenComplete(file.close); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Uint8List readAsBytesSync() { | 
|  | var opened = openSync(); | 
|  | try { | 
|  | Uint8List data; | 
|  | var length = opened.lengthSync(); | 
|  | if (length == 0) { | 
|  | // May be character device, try to read it in chunks. | 
|  | var builder = new BytesBuilder(copy: false); | 
|  | do { | 
|  | data = opened.readSync(_blockSize); | 
|  | if (data.length > 0) { | 
|  | builder.add(data); | 
|  | } | 
|  | } while (data.length > 0); | 
|  | data = builder.takeBytes(); | 
|  | } else { | 
|  | data = Uint8List(length); | 
|  | var offset = 0; | 
|  |  | 
|  | while (offset < length) { | 
|  | final readSize = opened.readIntoSync( | 
|  | data, | 
|  | offset, | 
|  | min(offset + _maxReadSize, length), | 
|  | ); | 
|  | if (readSize == 0) { | 
|  | break; | 
|  | } | 
|  | offset += readSize; | 
|  | } | 
|  |  | 
|  | if (offset < length) { | 
|  | data = Uint8List.view(data.buffer, 0, offset); | 
|  | } | 
|  | } | 
|  | return data; | 
|  | } finally { | 
|  | opened.closeSync(); | 
|  | } | 
|  | } | 
|  |  | 
|  | String _tryDecode(List<int> bytes, Encoding encoding) { | 
|  | try { | 
|  | return encoding.decode(bytes); | 
|  | } catch (_) { | 
|  | throw new FileSystemException( | 
|  | "Failed to decode data using encoding '${encoding.name}'", | 
|  | path, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<String> readAsString({Encoding encoding = utf8}) async => | 
|  | _tryDecode(await readAsBytes(), encoding); | 
|  |  | 
|  | String readAsStringSync({Encoding encoding = utf8}) => | 
|  | _tryDecode(readAsBytesSync(), encoding); | 
|  |  | 
|  | Future<List<String>> readAsLines({Encoding encoding = utf8}) => | 
|  | readAsString(encoding: encoding).then(const LineSplitter().convert); | 
|  |  | 
|  | List<String> readAsLinesSync({Encoding encoding = utf8}) => | 
|  | const LineSplitter().convert(readAsStringSync(encoding: encoding)); | 
|  |  | 
|  | Future<File> writeAsBytes( | 
|  | List<int> bytes, { | 
|  | FileMode mode = FileMode.write, | 
|  | bool flush = false, | 
|  | }) { | 
|  | return open(mode: mode).then((file) { | 
|  | return file | 
|  | .writeFrom(bytes, 0, bytes.length) | 
|  | .then<File>((_) { | 
|  | if (flush) return file.flush().then((_) => this); | 
|  | return this; | 
|  | }) | 
|  | .whenComplete(file.close); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void writeAsBytesSync( | 
|  | List<int> bytes, { | 
|  | FileMode mode = FileMode.write, | 
|  | bool flush = false, | 
|  | }) { | 
|  | RandomAccessFile opened = openSync(mode: mode); | 
|  | try { | 
|  | opened.writeFromSync(bytes, 0, bytes.length); | 
|  | if (flush) opened.flushSync(); | 
|  | } finally { | 
|  | opened.closeSync(); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<File> writeAsString( | 
|  | String contents, { | 
|  | FileMode mode = FileMode.write, | 
|  | Encoding encoding = utf8, | 
|  | bool flush = false, | 
|  | }) { | 
|  | try { | 
|  | return writeAsBytes(encoding.encode(contents), mode: mode, flush: flush); | 
|  | } catch (e) { | 
|  | return new Future.error(e); | 
|  | } | 
|  | } | 
|  |  | 
|  | void writeAsStringSync( | 
|  | String contents, { | 
|  | FileMode mode = FileMode.write, | 
|  | Encoding encoding = utf8, | 
|  | bool flush = false, | 
|  | }) { | 
|  | writeAsBytesSync(encoding.encode(contents), mode: mode, flush: flush); | 
|  | } | 
|  |  | 
|  | String toString() => "File: '$path'"; | 
|  |  | 
|  | static throwIfError(Object result, String msg, String path) { | 
|  | if (result is OSError) { | 
|  | throw FileSystemException._fromOSError(result, msg, path); | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | static T _checkNotNull<T>(T t, String name) { | 
|  | ArgumentError.checkNotNull(t, name); | 
|  | return t; | 
|  | } | 
|  | } | 
|  |  | 
|  | abstract class _RandomAccessFileOps { | 
|  | external factory _RandomAccessFileOps(int pointer); | 
|  |  | 
|  | int getPointer(); | 
|  | int get fd; | 
|  | int close(); | 
|  | readByte(); | 
|  | read(int bytes); | 
|  | readInto(List<int> buffer, int start, int? end); | 
|  | writeByte(int value); | 
|  | writeFrom(List<int> buffer, int start, int? end); | 
|  | position(); | 
|  | setPosition(int position); | 
|  | truncate(int length); | 
|  | length(); | 
|  | flush(); | 
|  | lock(int lock, int start, int end); | 
|  | } | 
|  |  | 
|  | @pragma("vm:entry-point") | 
|  | class _RandomAccessFile implements RandomAccessFile { | 
|  | static bool _connectedResourceHandler = false; | 
|  |  | 
|  | final String path; | 
|  |  | 
|  | bool _asyncDispatched = false; | 
|  |  | 
|  | late _FileResourceInfo _resourceInfo; | 
|  | _RandomAccessFileOps _ops; | 
|  |  | 
|  | @pragma("vm:entry-point") | 
|  | _RandomAccessFile(int pointer, this.path) | 
|  | : _ops = new _RandomAccessFileOps(pointer) { | 
|  | _resourceInfo = new _FileResourceInfo(this); | 
|  | _maybeConnectHandler(); | 
|  | } | 
|  |  | 
|  | void _maybePerformCleanup() { | 
|  | if (closed) { | 
|  | _FileResourceInfo.fileClosed(_resourceInfo); | 
|  | } | 
|  | } | 
|  |  | 
|  | _maybeConnectHandler() { | 
|  | if (!const bool.fromEnvironment("dart.vm.product") && | 
|  | !_connectedResourceHandler) { | 
|  | // TODO(ricow): We probably need to set these in some initialization code. | 
|  | // We need to make sure that these are always available from the | 
|  | // observatory even if no files (or sockets for the socket ones) are | 
|  | // open. | 
|  | registerExtension( | 
|  | 'ext.dart.io.getOpenFiles', | 
|  | _FileResourceInfo.getOpenFiles, | 
|  | ); | 
|  | registerExtension( | 
|  | 'ext.dart.io.getOpenFileById', | 
|  | _FileResourceInfo.getOpenFileInfoMapByID, | 
|  | ); | 
|  | _connectedResourceHandler = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<void> close() { | 
|  | return _dispatch(_IOService.fileClose, [null], markClosed: true).then(( | 
|  | result, | 
|  | ) { | 
|  | if (result == -1) { | 
|  | throw new FileSystemException("Cannot close file", path); | 
|  | } | 
|  | closed = closed || (result == 0); | 
|  | _maybePerformCleanup(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void closeSync() { | 
|  | _checkAvailable(); | 
|  | var id = _ops.close(); | 
|  | if (id == -1) { | 
|  | throw new FileSystemException("Cannot close file", path); | 
|  | } | 
|  | closed = closed || (id == 0); | 
|  | _maybePerformCleanup(); | 
|  | } | 
|  |  | 
|  | Future<int> readByte() { | 
|  | return _dispatch(_IOService.fileReadByte, [null]).then((response) { | 
|  | _checkForErrorResponse(response, "readByte failed", path); | 
|  | _resourceInfo.addRead(1); | 
|  | return response as int; | 
|  | }); | 
|  | } | 
|  |  | 
|  | int readByteSync() { | 
|  | _checkAvailable(); | 
|  | var result = _ops.readByte(); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("readByte failed", path, result); | 
|  | } | 
|  | _resourceInfo.addRead(1); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<Uint8List> read(int bytes) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(bytes, "bytes"); | 
|  | return _dispatch(_IOService.fileRead, [null, bytes]).then((response) { | 
|  | _checkForErrorResponse(response, "read failed", path); | 
|  | var result = (response as List<Object?>)[1] as Uint8List; | 
|  | _resourceInfo.addRead(result.length); | 
|  | return result; | 
|  | }); | 
|  | } | 
|  |  | 
|  | Uint8List readSync(int bytes) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(bytes, "bytes"); | 
|  | _checkAvailable(); | 
|  | var result = _ops.read(bytes); | 
|  | if (result is! Uint8List) { | 
|  | throw new FileSystemException("readSync failed", path, result as OSError); | 
|  | } | 
|  | _resourceInfo.addRead(result.length); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<int> readInto(List<int> buffer, [int start = 0, int? end]) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(buffer, "buffer"); | 
|  | end = RangeError.checkValidRange(start, end, buffer.length); | 
|  | if (end == start) { | 
|  | return new Future.value(0); | 
|  | } | 
|  | int length = end - start; | 
|  | return _dispatch(_IOService.fileReadInto, [null, length]).then((response) { | 
|  | _checkForErrorResponse(response, "readInto failed", path); | 
|  | var responseList = response as List<Object?>; | 
|  | var read = responseList[1] as int; | 
|  | var data = responseList[2] as List<int>; | 
|  | buffer.setRange(start, start + read, data); | 
|  | _resourceInfo.addRead(read); | 
|  | return read; | 
|  | }); | 
|  | } | 
|  |  | 
|  | int readIntoSync(List<int> buffer, [int start = 0, int? end]) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(buffer, "buffer"); | 
|  | _checkAvailable(); | 
|  | end = RangeError.checkValidRange(start, end, buffer.length); | 
|  | if (end == start) { | 
|  | return 0; | 
|  | } | 
|  | var result = _ops.readInto(buffer, start, end); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("readInto failed", path, result); | 
|  | } | 
|  | _resourceInfo.addRead(result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> writeByte(int value) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(value, "value"); | 
|  | return _dispatch(_IOService.fileWriteByte, [null, value]).then((response) { | 
|  | _checkForErrorResponse(response, "writeByte failed", path); | 
|  | _resourceInfo.addWrite(1); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | int writeByteSync(int value) { | 
|  | _checkAvailable(); | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(value, "value"); | 
|  | var result = _ops.writeByte(value); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("writeByte failed", path, result); | 
|  | } | 
|  | _resourceInfo.addWrite(1); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> writeFrom( | 
|  | List<int> buffer, [ | 
|  | int start = 0, | 
|  | int? end, | 
|  | ]) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(buffer, "buffer"); | 
|  | ArgumentError.checkNotNull(start, "start"); | 
|  | end = RangeError.checkValidRange(start, end, buffer.length); | 
|  | if (end == start) { | 
|  | return new Future.value(this); | 
|  | } | 
|  | _BufferAndStart result; | 
|  | try { | 
|  | result = _ensureFastAndSerializableByteData(buffer, start, end); | 
|  | } catch (e) { | 
|  | return new Future.error(e); | 
|  | } | 
|  |  | 
|  | List request = new List<dynamic>.filled(4, null); | 
|  | request[0] = null; | 
|  | request[1] = result.buffer; | 
|  | request[2] = result.start; | 
|  | request[3] = end - (start - result.start); | 
|  | return _dispatch(_IOService.fileWriteFrom, request).then((response) { | 
|  | _checkForErrorResponse(response, "writeFrom failed", path); | 
|  | _resourceInfo.addWrite(end! - (start - result.start)); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void writeFromSync(List<int> buffer, [int start = 0, int? end]) { | 
|  | _checkAvailable(); | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(buffer, "buffer"); | 
|  | ArgumentError.checkNotNull(start, "start"); | 
|  | end = RangeError.checkValidRange(start, end, buffer.length); | 
|  | if (end == start) { | 
|  | return; | 
|  | } | 
|  | _BufferAndStart bufferAndStart = _ensureFastAndSerializableByteData( | 
|  | buffer, | 
|  | start, | 
|  | end, | 
|  | ); | 
|  | var result = _ops.writeFrom( | 
|  | bufferAndStart.buffer, | 
|  | bufferAndStart.start, | 
|  | end - (start - bufferAndStart.start), | 
|  | ); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("writeFrom failed", path, result); | 
|  | } | 
|  | _resourceInfo.addWrite(end - (start - bufferAndStart.start)); | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> writeString( | 
|  | String string, { | 
|  | Encoding encoding = utf8, | 
|  | }) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(encoding, "encoding"); | 
|  | var data = encoding.encode(string); | 
|  | return writeFrom(data, 0, data.length); | 
|  | } | 
|  |  | 
|  | void writeStringSync(String string, {Encoding encoding = utf8}) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(encoding, "encoding"); | 
|  | var data = encoding.encode(string); | 
|  | writeFromSync(data, 0, data.length); | 
|  | } | 
|  |  | 
|  | Future<int> position() { | 
|  | return _dispatch(_IOService.filePosition, [null]).then((response) { | 
|  | _checkForErrorResponse(response, "position failed", path); | 
|  | return response as int; | 
|  | }); | 
|  | } | 
|  |  | 
|  | int positionSync() { | 
|  | _checkAvailable(); | 
|  | var result = _ops.position(); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("position failed", path, result); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> setPosition(int position) { | 
|  | return _dispatch(_IOService.fileSetPosition, [null, position]).then(( | 
|  | response, | 
|  | ) { | 
|  | _checkForErrorResponse(response, "setPosition failed", path); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void setPositionSync(int position) { | 
|  | _checkAvailable(); | 
|  | var result = _ops.setPosition(position); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("setPosition failed", path, result); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> truncate(int length) { | 
|  | return _dispatch(_IOService.fileTruncate, [null, length]).then((response) { | 
|  | _checkForErrorResponse(response, "truncate failed", path); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void truncateSync(int length) { | 
|  | _checkAvailable(); | 
|  | var result = _ops.truncate(length); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("truncate failed", path, result); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<int> length() { | 
|  | return _dispatch(_IOService.fileLength, [null]).then((response) { | 
|  | _checkForErrorResponse(response, "length failed", path); | 
|  | return response as int; | 
|  | }); | 
|  | } | 
|  |  | 
|  | int lengthSync() { | 
|  | _checkAvailable(); | 
|  | var result = _ops.length(); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("length failed", path, result); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> flush() { | 
|  | return _dispatch(_IOService.fileFlush, [null]).then((response) { | 
|  | _checkForErrorResponse(response, "flush failed", path); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void flushSync() { | 
|  | _checkAvailable(); | 
|  | var result = _ops.flush(); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException("flush failed", path, result); | 
|  | } | 
|  | } | 
|  |  | 
|  | static const int lockUnlock = 0; | 
|  | // static const int lockShared = 1; | 
|  | // static const int lockExclusive = 2; | 
|  | // static const int lockBlockingShared = 3; | 
|  | // static const int lockBlockingExclusive = 4; | 
|  |  | 
|  | int _fileLockValue(FileLock fl) => fl._type; | 
|  |  | 
|  | Future<RandomAccessFile> lock([ | 
|  | FileLock mode = FileLock.exclusive, | 
|  | int start = 0, | 
|  | int end = -1, | 
|  | ]) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(mode, "mode"); | 
|  | ArgumentError.checkNotNull(start, "start"); | 
|  | ArgumentError.checkNotNull(end, "end"); | 
|  | if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) { | 
|  | throw new ArgumentError(); | 
|  | } | 
|  | int lock = _fileLockValue(mode); | 
|  | return _dispatch(_IOService.fileLock, [null, lock, start, end]).then(( | 
|  | response, | 
|  | ) { | 
|  | _checkForErrorResponse(response, 'lock failed', path); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future<RandomAccessFile> unlock([int start = 0, int end = -1]) { | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(start, "start"); | 
|  | ArgumentError.checkNotNull(end, "end"); | 
|  | if (start == end) { | 
|  | throw new ArgumentError(); | 
|  | } | 
|  | return _dispatch(_IOService.fileLock, [null, lockUnlock, start, end]).then(( | 
|  | response, | 
|  | ) { | 
|  | _checkForErrorResponse(response, 'unlock failed', path); | 
|  | return this; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void lockSync([ | 
|  | FileLock mode = FileLock.exclusive, | 
|  | int start = 0, | 
|  | int end = -1, | 
|  | ]) { | 
|  | _checkAvailable(); | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(mode, "mode"); | 
|  | ArgumentError.checkNotNull(start, "start"); | 
|  | ArgumentError.checkNotNull(end, "end"); | 
|  | if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) { | 
|  | throw new ArgumentError(); | 
|  | } | 
|  | int lock = _fileLockValue(mode); | 
|  | var result = _ops.lock(lock, start, end); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException('lock failed', path, result); | 
|  | } | 
|  | } | 
|  |  | 
|  | void unlockSync([int start = 0, int end = -1]) { | 
|  | _checkAvailable(); | 
|  | // TODO(40614): Remove once non-nullability is sound. | 
|  | ArgumentError.checkNotNull(start, "start"); | 
|  | ArgumentError.checkNotNull(end, "end"); | 
|  | if (start == end) { | 
|  | throw new ArgumentError(); | 
|  | } | 
|  | var result = _ops.lock(lockUnlock, start, end); | 
|  | if (result is OSError) { | 
|  | throw new FileSystemException('unlock failed', path, result); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool closed = false; | 
|  |  | 
|  | int get fd => _ops.fd; | 
|  |  | 
|  | // WARNING: | 
|  | // Calling this function will increase the reference count on the native | 
|  | // object that implements the file operations. It should only be called to | 
|  | // pass the pointer to the IO Service, which will decrement the reference | 
|  | // count when it is finished with it. | 
|  | int _pointer() => _ops.getPointer(); | 
|  |  | 
|  | Future<Object?> _dispatch(int request, List data, {bool markClosed = false}) { | 
|  | if (closed) { | 
|  | return new Future.error(new FileSystemException("File closed", path)); | 
|  | } | 
|  | if (_asyncDispatched) { | 
|  | var msg = "An async operation is currently pending"; | 
|  | return new Future.error(new FileSystemException(msg, path)); | 
|  | } | 
|  | if (markClosed) { | 
|  | // Set closed to true to ensure that no more async requests can be issued | 
|  | // for this file. | 
|  | closed = true; | 
|  | } | 
|  | _asyncDispatched = true; | 
|  | data[0] = _pointer(); | 
|  | return _IOService._dispatch(request, data).whenComplete(() { | 
|  | _asyncDispatched = false; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void _checkAvailable() { | 
|  | if (_asyncDispatched) { | 
|  | throw new FileSystemException( | 
|  | "An async operation is currently pending", | 
|  | path, | 
|  | ); | 
|  | } | 
|  | if (closed) { | 
|  | throw new FileSystemException("File closed", path); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | class _ReadPipe extends _FileStream implements ReadPipe { | 
|  | _ReadPipe(RandomAccessFile file) : super.forRandomAccessFile(file); | 
|  | } | 
|  |  | 
|  | class _WritePipe extends _IOSinkImpl implements WritePipe { | 
|  | RandomAccessFile _file; | 
|  | _WritePipe(file) | 
|  | : this._file = file, | 
|  | super(_FileStreamConsumer.fromRandomAccessFile(file), utf8); | 
|  | } | 
|  |  | 
|  | class _Pipe implements Pipe { | 
|  | final ReadPipe _readPipe; | 
|  | final WritePipe _writePipe; | 
|  |  | 
|  | ReadPipe get read => _readPipe; | 
|  | WritePipe get write => _writePipe; | 
|  |  | 
|  | _Pipe(this._readPipe, this._writePipe); | 
|  |  | 
|  | static Future<_Pipe> create() { | 
|  | final completer = Completer<_Pipe>.sync(); | 
|  |  | 
|  | _File._dispatchWithNamespace(_IOService.fileCreatePipe, [null]).then(( | 
|  | response, | 
|  | ) { | 
|  | final filePointers = (response as List).cast<int>(); | 
|  | completer.complete( | 
|  | _Pipe( | 
|  | _ReadPipe(_RandomAccessFile(filePointers[0], '')), | 
|  | _WritePipe(_RandomAccessFile(filePointers[1], '')), | 
|  | ), | 
|  | ); | 
|  | }); | 
|  | return completer.future; | 
|  | } | 
|  |  | 
|  | factory _Pipe.createSync() { | 
|  | final filePointers = _File._createPipe(_Namespace._namespace); | 
|  | return _Pipe( | 
|  | _ReadPipe(_RandomAccessFile(filePointers[0] as int, '')), | 
|  | _WritePipe(_RandomAccessFile(filePointers[1] as int, '')), | 
|  | ); | 
|  | } | 
|  | } |