|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Enumeration;
namespace System.IO
{
public sealed class DirectoryInfo : FileSystemInfo
{
private bool _isNormalized;
public DirectoryInfo(string path)
{
ArgumentNullException.ThrowIfNull(path);
Init(originalPath: path,
fullPath: Path.GetFullPath(path),
isNormalized: true);
}
internal DirectoryInfo(string originalPath, string? fullPath = null, string? fileName = null, bool isNormalized = false)
{
Init(originalPath, fullPath, fileName, isNormalized);
}
private void Init(string originalPath, string? fullPath = null, string? fileName = null, bool isNormalized = false)
{
OriginalPath = originalPath;
fullPath ??= originalPath;
fullPath = isNormalized ? fullPath : Path.GetFullPath(fullPath);
_name = fileName;
FullPath = fullPath;
_isNormalized = isNormalized;
}
public override string Name
{
get
{
string? name = _name;
if (name is null)
{
ReadOnlySpan<char> fullPath = FullPath.AsSpan();
_name = name = (PathInternal.IsRoot(fullPath) ?
fullPath :
Path.GetFileName(Path.TrimEndingDirectorySeparator(fullPath))).ToString();
}
return name;
}
}
public DirectoryInfo? Parent
{
get
{
// FullPath might end in either "parent\child" or "parent\child\", and in either case we want
// the parent of child, not the child. Trim off an ending directory separator if there is one,
// but don't mangle the root.
string? parentName = Path.GetDirectoryName(PathInternal.IsRoot(FullPath.AsSpan()) ? FullPath : Path.TrimEndingDirectorySeparator(FullPath));
return parentName != null ?
new DirectoryInfo(parentName, isNormalized: true) :
null;
}
}
public DirectoryInfo CreateSubdirectory(string path)
{
ArgumentNullException.ThrowIfNull(path);
if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
throw new ArgumentException(SR.Argument_PathEmpty, nameof(path));
if (Path.IsPathRooted(path))
throw new ArgumentException(SR.Arg_Path2IsRooted, nameof(path));
string newPath = Path.GetFullPath(Path.Combine(FullPath, path));
ReadOnlySpan<char> trimmedNewPath = Path.TrimEndingDirectorySeparator(newPath.AsSpan());
// Trim any trailing separator, including from a root path for proper boundary checking.
// TrimEndingDirectorySeparator does not trim the character from path roots.
ReadOnlySpan<char> trimmedCurrentPath = FullPath.TrimEnd(Path.DirectorySeparatorChar);
// We want to make sure the requested directory is actually under the subdirectory.
if (trimmedNewPath.StartsWith(trimmedCurrentPath, PathInternal.StringComparison)
// Allow the exact same path, but prevent allowing "..\FooBar" through when the directory is "Foo"
&& ((trimmedNewPath.Length == trimmedCurrentPath.Length) || PathInternal.IsDirectorySeparator(newPath[trimmedCurrentPath.Length])))
{
FileSystem.CreateDirectory(newPath);
return new DirectoryInfo(newPath);
}
// We weren't nested
throw new ArgumentException(SR.Format(SR.Argument_InvalidSubPath, path, FullPath), nameof(path));
}
public void Create()
{
FileSystem.CreateDirectory(FullPath);
Invalidate();
}
// Returns an array of Files in the DirectoryInfo specified by path
public FileInfo[] GetFiles() => GetFiles("*", enumerationOptions: EnumerationOptions.Compatible);
// Returns an array of Files in the current DirectoryInfo matching the
// given search criteria (i.e. "*.txt").
public FileInfo[] GetFiles(string searchPattern) => GetFiles(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public FileInfo[] GetFiles(string searchPattern, SearchOption searchOption)
=> GetFiles(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
public FileInfo[] GetFiles(string searchPattern, EnumerationOptions enumerationOptions)
=> new List<FileInfo>((IEnumerable<FileInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Files, enumerationOptions)).ToArray();
// Returns an array of strongly typed FileSystemInfo entries which will contain a listing
// of all the files and directories.
public FileSystemInfo[] GetFileSystemInfos() => GetFileSystemInfos("*", enumerationOptions: EnumerationOptions.Compatible);
// Returns an array of strongly typed FileSystemInfo entries in the path with the
// given search criteria (i.e. "*.txt").
public FileSystemInfo[] GetFileSystemInfos(string searchPattern)
=> GetFileSystemInfos(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public FileSystemInfo[] GetFileSystemInfos(string searchPattern, SearchOption searchOption)
=> GetFileSystemInfos(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
public FileSystemInfo[] GetFileSystemInfos(string searchPattern, EnumerationOptions enumerationOptions)
=> new List<FileSystemInfo>(InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Both, enumerationOptions)).ToArray();
// Returns an array of Directories in the current directory.
public DirectoryInfo[] GetDirectories() => GetDirectories("*", enumerationOptions: EnumerationOptions.Compatible);
// Returns an array of Directories in the current DirectoryInfo matching the
// given search criteria (i.e. "System*" could match the System & System32 directories).
public DirectoryInfo[] GetDirectories(string searchPattern) => GetDirectories(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public DirectoryInfo[] GetDirectories(string searchPattern, SearchOption searchOption)
=> GetDirectories(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
public DirectoryInfo[] GetDirectories(string searchPattern, EnumerationOptions enumerationOptions)
=> new List<DirectoryInfo>((IEnumerable<DirectoryInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Directories, enumerationOptions)).ToArray();
public IEnumerable<DirectoryInfo> EnumerateDirectories()
=> EnumerateDirectories("*", enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern)
=> EnumerateDirectories(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern, SearchOption searchOption)
=> EnumerateDirectories(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern, EnumerationOptions enumerationOptions)
=> (IEnumerable<DirectoryInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Directories, enumerationOptions);
public IEnumerable<FileInfo> EnumerateFiles()
=> EnumerateFiles("*", enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileInfo> EnumerateFiles(string searchPattern) => EnumerateFiles(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileInfo> EnumerateFiles(string searchPattern, SearchOption searchOption)
=> EnumerateFiles(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
public IEnumerable<FileInfo> EnumerateFiles(string searchPattern, EnumerationOptions enumerationOptions)
=> (IEnumerable<FileInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Files, enumerationOptions);
public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos() => EnumerateFileSystemInfos("*", enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern)
=> EnumerateFileSystemInfos(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, SearchOption searchOption)
=> EnumerateFileSystemInfos(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, EnumerationOptions enumerationOptions)
=> InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Both, enumerationOptions);
private IEnumerable<FileSystemInfo> InternalEnumerateInfos(
string path,
string searchPattern,
SearchTarget searchTarget,
EnumerationOptions enumerationOptions)
{
ArgumentNullException.ThrowIfNull(searchPattern);
ArgumentNullException.ThrowIfNull(enumerationOptions);
Debug.Assert(path != null);
_isNormalized &= FileSystemEnumerableFactory.NormalizeInputs(ref path, ref searchPattern, enumerationOptions.MatchType);
return searchTarget switch
{
SearchTarget.Directories => FileSystemEnumerableFactory.DirectoryInfos(path, searchPattern, enumerationOptions, _isNormalized),
SearchTarget.Files => FileSystemEnumerableFactory.FileInfos(path, searchPattern, enumerationOptions, _isNormalized),
SearchTarget.Both => FileSystemEnumerableFactory.FileSystemInfos(path, searchPattern, enumerationOptions, _isNormalized),
_ => throw new ArgumentException(SR.ArgumentOutOfRange_Enum, nameof(searchTarget)),
};
}
public DirectoryInfo Root => new DirectoryInfo(Path.GetPathRoot(FullPath)!);
public void MoveTo(string destDirName)
{
ArgumentException.ThrowIfNullOrEmpty(destDirName);
string destination = Path.GetFullPath(destDirName);
FileSystem.MoveDirectory(FullPath, destination);
Init(originalPath: destDirName,
fullPath: PathInternal.EnsureTrailingSeparator(destination),
fileName: null,
isNormalized: true);
// Flush any cached information about the directory.
Invalidate();
}
public override void Delete() => Delete(recursive: false);
public void Delete(bool recursive)
{
FileSystem.RemoveDirectory(FullPath, recursive);
Invalidate();
}
public override bool Exists
{
get
{
try
{
return ExistsCore;
}
catch
{
return false;
}
}
}
}
}
|