blob: dbbcb260b56292728d00ad5523dd3ccaefb7f870 [file] [log] [blame]
// Copyright (c) 2012, 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;
/// A reference to a directory (or _folder_) on the file system.
///
/// A [Directory] is an object holding a [path] on which operations can
/// be performed. The path to the directory can be [absolute] or relative.
/// It allows access to the [parent] directory,
/// since it is a [FileSystemEntity].
///
/// The [Directory] also provides static access to the system's temporary
/// file directory, [systemTemp], and the ability to access and change
/// the [current] directory.
///
/// Create a new [Directory] to give access the directory with the specified
/// path:
/// ```dart
/// var myDir = Directory('myDir');
/// ```
/// Most intance methods of [Directory] exist in both synchronous
/// and asynchronous variants, for example, [create] and [createSync].
/// Unless you have a specific reason for using the synchronous version
/// of a method, prefer the asynchronous version to avoid blocking your program.
///
/// ## Create a directory
///
/// The following code sample creates a directory using the [create] method.
/// By setting the `recursive` parameter to true, you can create the
/// named directory and all its necessary parent directories,
/// if they do not already exist.
/// ```dart
/// import 'dart:io';
///
/// void main() async {
/// // Creates dir/ and dir/subdir/.
/// var directory = await Directory('dir/subdir').create(recursive: true)
/// print(directory.path);
/// }
/// ```
/// ## List the entries of a directory
///
/// Use the [list] or [listSync] methods to get the files and directories
/// contained in a directory.
/// Set `recursive` to true to recursively list all subdirectories.
/// Set `followLinks` to true to follow symbolic links.
/// The list method returns a [Stream] of [FileSystemEntity] objects.
/// Listen on the stream to access each object as it is found:
/// ```dart
/// import 'dart:io';
///
/// void main() async {
/// // Get the system temp directory.
/// var systemTempDir = Directory.systemTemp;
///
/// // List directory contents, recursing into sub-directories,
/// // but not following symbolic links.
/// await for (var entity in
/// systemTempDir.list(recursive: true, followLinks: false)) {
/// print(entity.path);
/// }
/// }
/// ```
/// ## The use of asynchronnous methods
///
/// I/O operations can block a program for some period of time while it waits for
/// the operation to complete. To avoid this, all
/// methods involving I/O have an asynchronous variant which returns a [Future].
/// This future completes when the I/O operation finishes. While the I/O
/// operation is in progress, the Dart program is not blocked,
/// and can perform other operations.
///
/// For example,
/// the [exists] method, which determines whether the directory exists,
/// returns a boolean value asynchronously using a [Future].
/// ```dart
/// import 'dart:io';
///
/// void main() async {
/// final myDir = Directory('dir');
/// var isThere = await myDir.exists();
/// print(isThere ? 'exists' : 'non-existent');
/// }
/// ```
///
/// In addition to [exists], the [stat], [rename],
/// and other methods are also asynchronous.
///
/// ## Other resources
///
/// * The [Files and directories](https://dart.dev/guides/libraries/library-tour#files-and-directories)
/// section of the library tour.
///
/// * [Write Command-Line Apps](https://dart.dev/tutorials/server/cmdline),
/// a tutorial about writing command-line apps, includes information about
/// files and directories.
@pragma("vm:entry-point")
abstract class Directory implements FileSystemEntity {
/// Gets the path of this directory.
String get path;
/// Creates a [Directory] object.
///
/// If [path] is a relative path, it will be interpreted relative to the
/// current working directory (see [Directory.current]), when used.
///
/// If [path] is an absolute path, it will be immune to changes to the
/// current working directory.
@pragma("vm:entry-point")
factory Directory(String path) {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
return new _Directory(path);
}
return overrides.createDirectory(path);
}
@pragma("vm:entry-point")
factory Directory.fromRawPath(Uint8List path) {
// TODO(bkonyi): Handle overrides.
return new _Directory.fromRawPath(path);
}
/// Create a [Directory] from a URI.
///
/// If [uri] cannot reference a directory this throws [UnsupportedError].
factory Directory.fromUri(Uri uri) => new Directory(uri.toFilePath());
/// Creates a directory object pointing to the current working
/// directory.
static Directory get current {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
return _Directory.current;
}
return overrides.getCurrentDirectory();
}
/// A [Uri] representing the directory's location.
///
/// The URI's scheme is always "file" if the entity's [path] is
/// absolute, otherwise the scheme will be empty and the URI relative.
/// The URI's path always ends in a slash ('/').
Uri get uri;
/// Sets the current working directory of the Dart process.
///
/// This affects all running isolates.
/// The new value set can be either a [Directory] or a [String].
///
/// The new value is passed to the OS's system call unchanged, so a
/// relative path passed as the new working directory will be
/// resolved by the OS.
///
/// Note that setting the current working directory is a synchronous
/// operation and that it changes the working directory of *all*
/// isolates.
///
/// Use this with care — especially when working with asynchronous
/// operations and multiple isolates. Changing the working directory,
/// while asynchronous operations are pending or when other isolates
/// are working with the file system, can lead to unexpected results.
static void set current(path) {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
_Directory.current = path;
return;
}
overrides.setCurrentDirectory(path);
}
/// Creates the directory if it doesn't exist.
///
/// If [recursive] is false, only the last directory in the path is
/// created. If [recursive] is true, all non-existing path components
/// are created. If the directory already exists nothing is done.
///
/// Returns a `Future<Directory>` that completes with this
/// directory once it has been created. If the directory cannot be
/// created the future completes with an exception.
Future<Directory> create({bool recursive = false});
/// Synchronously creates the directory if it doesn't exist.
///
/// If [recursive] is false, only the last directory in the path is
/// created. If [recursive] is true, all non-existing path components
/// are created. If the directory already exists nothing is done.
///
/// If the directory cannot be created an exception is thrown.
void createSync({bool recursive = false});
/// The system temp directory.
///
/// This is the directory provided by the operating system for creating
/// temporary files and directories in.
/// The location of the system temporary directory is platform-dependent,
/// and may be controlled by an environment variable on some platforms.
static Directory get systemTemp {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
return _Directory.systemTemp;
}
return overrides.getSystemTempDirectory();
}
/// Creates a temporary directory in this directory.
///
/// Additional random characters are appended to [prefix]
/// to produce a unique directory name.
/// If [prefix] is missing or null, the empty string is used as [prefix].
///
/// Returns a `Future<Directory>` that completes with the newly
/// created temporary directory.
Future<Directory> createTemp([String? prefix]);
/// Synchronously creates a temporary directory in this directory.
///
/// Additional random characters are appended to [prefix] to produce
/// a unique directory name. If [prefix] is missing or null, the empty
/// string is used as [prefix].
///
/// Returns the newly created temporary directory.
Directory createTempSync([String? prefix]);
Future<String> resolveSymbolicLinks();
String resolveSymbolicLinksSync();
/// Renames this directory.
///
/// Returns a `Future<Directory>` that completes
/// with a [Directory] for the renamed directory.
///
/// If [newPath] identifies an existing directory, that directory is
/// removed first.
/// If [newPath] identifies an existing file, the operation
/// fails and the future completes with an exception.
Future<Directory> rename(String newPath);
/// Synchronously renames this directory.
///
/// Returns a [Directory] for the renamed directory.
///
/// If [newPath] identifies an existing directory, that directory is
/// removed first.
/// If [newPath] identifies an existing file the operation
/// fails and an exception is thrown.
Directory renameSync(String newPath);
/// A [Directory] whose path is the absolute path of [this].
///
/// The absolute path is computed by prefixing
/// a relative path with the current working directory,
/// or by returning an absolute path unchanged.
Directory get absolute;
/// Lists the sub-directories and files of this [Directory].
///
/// Optionally recurses into sub-directories.
///
/// If [followLinks] is `false`, then any symbolic links found
/// are reported as [Link] objects, rather than as directories or files,
/// and are not recursed into.
///
/// If [followLinks] is `true`, then working links are reported as
/// directories or files, depending on what they point to,
/// and links to directories are recursed into f [recursive] is `true`.
///
/// Broken links are reported as [Link] objects.
///
/// If a symbolic link makes a loop in the file system, then a recursive
/// listing will not follow a link twice in the
/// same recursive descent, but will report it as a [Link]
/// the second time it is seen.
///
/// The result is a stream of [FileSystemEntity] objects
/// for the directories, files, and links.
Stream<FileSystemEntity> list(
{bool recursive = false, bool followLinks = true});
/// Lists the sub-directories and files of this [Directory].
/// Optionally recurses into sub-directories.
///
/// If [followLinks] is `false`, then any symbolic links found
/// are reported as [Link] objects, rather than as directories or files,
/// and are not recursed into.
///
/// If [followLinks] is `true`, then working links are reported as
/// directories or files, depending on what they point to,
/// and links to directories are recursed into if `recursive` is `true`.
///
/// Broken links are reported as [Link] objects.
///
/// If a link makes a loop in the file system, then a recursive
/// listing will not follow a link twice in the
/// same recursive descent, but will report it as a [Link]
/// the second time it is seen.
///
/// Returns a [List] containing [FileSystemEntity] objects for the
/// directories, files, and links.
List<FileSystemEntity> listSync(
{bool recursive = false, bool followLinks = true});
/// Returns a human readable representation of this [Directory].
String toString();
}