/// <summary> /// Replaces the contents of this file with the contents of another file, deleting the original file, and creating a backup of the replaced file and optionally ignores merge errors. /// </summary> /// <param name="destPath">The path of the file being replaced.</param> /// <param name="destBackupPath">The path of the backup file (maybe null, in that case, it doesn't create any backup)</param> /// <param name="ignoreMetadataErrors"><c>true</c> to ignore merge errors (such as attributes and access control lists (ACLs)) from the replaced file to the replacement file; otherwise, <c>false</c>.</param> public void ReplaceTo(UPath destPath, UPath destBackupPath, bool ignoreMetadataErrors) { FileSystem.ReplaceFile(Path, destPath, destBackupPath, ignoreMetadataErrors); }
/// <summary> /// Initializes a new instance of the <see cref="FileEntry"/> class. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The file path.</param> public FileEntry(IFileSystem fileSystem, UPath path) : base(fileSystem, path) { }
/// <summary> /// Tries to get a <see cref="FileSystemEntry"/> for the specified path. If the file or directory does not exist, returns null. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The file or directory path.</param> /// <returns>A new <see cref="FileSystemEntry"/> from the specified path.</returns> public static FileSystemEntry TryGetFileSystemEntry(this IFileSystem fileSystem, UPath path) { var fileExists = fileSystem.FileExists(path); if (fileExists) { return(new FileEntry(fileSystem, path)); } var directoryExists = fileSystem.DirectoryExists(path); if (directoryExists) { return(new DirectoryEntry(fileSystem, path)); } return(null); }
/// <summary>Moves a specified file to a new location, providing the option to specify a new file name.</summary> /// <param name="destFileName">The path to move the file to, which can specify a different file name. </param> /// <exception cref="T:System.IO.IOException"> /// An I/O error occurs, such as the destination file already exists or the /// destination device is not ready. /// </exception> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="destFileName" /> is null. /// </exception> /// <exception cref="T:System.ArgumentException"> /// <paramref name="destFileName" /> is empty, contains only white spaces, or contains invalid characters. /// </exception> /// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception> /// <exception cref="T:System.UnauthorizedAccessException"> /// <paramref name="destFileName" /> is read-only or is a directory. /// </exception> /// <exception cref="T:System.IO.FileNotFoundException">The file is not found. </exception> /// <exception cref="T:System.IO.DirectoryNotFoundException"> /// The specified path is invalid, such as being on an unmapped /// drive. /// </exception> /// <exception cref="T:System.IO.PathTooLongException"> /// The specified path, file name, or both exceed the system-defined /// maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names /// must be less than 260 characters. /// </exception> /// <exception cref="T:System.NotSupportedException"> /// <paramref name="destFileName" /> contains a colon (:) in the middle of the string. /// </exception> public void MoveTo(UPath destFileName) { FileSystem.MoveFile(Path, destFileName); }
private SearchPattern(ref UPath path, ref string searchPattern) { path.AssertAbsolute(); if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } this._exactMatch = null; this._regexMatch = null; // Optimized path, most common case if (searchPattern == "*") { return; } if (searchPattern.StartsWith("/")) { throw new ArgumentException($"The search pattern `{searchPattern}` cannot start by an absolute path `/`"); } searchPattern = searchPattern.Replace('\\', '/'); // If the path contains any directory, we need to concatenate the directory part with the input path if (searchPattern.IndexOf('/') > 0) { var pathPattern = new UPath(searchPattern); var directory = pathPattern.GetDirectory(); if (!directory.IsNull && !directory.IsEmpty) { path /= directory; } searchPattern = pathPattern.GetName(); // If the search pattern is again a plain any, optimized path if (searchPattern == "*") { return; } } var startIndex = 0; StringBuilder builder = null; try { int nextIndex; while ((nextIndex = searchPattern.IndexOfAny(SpecialChars, startIndex)) >= 0) { if (builder == null) { builder = UPath.GetSharedStringBuilder(); builder.Append("^"); } var lengthToEscape = nextIndex - startIndex; if (lengthToEscape > 0) { var toEscape = Regex.Escape(searchPattern.Substring(startIndex, lengthToEscape)); builder.Append(toEscape); } var c = searchPattern[nextIndex]; var regexPatternPart = c == '*' ? "[^/]*" : "[^/]"; builder.Append(regexPatternPart); startIndex = nextIndex + 1; } if (builder == null) { this._exactMatch = searchPattern; } else { var length = searchPattern.Length - startIndex; if (length > 0) { var toEscape = Regex.Escape(searchPattern.Substring(startIndex, length)); builder.Append(toEscape); } builder.Append("$"); var regexPattern = builder.ToString(); this._regexMatch = new Regex(regexPattern); } } finally { if (builder != null) { builder.Length = 0; } } }
/// <summary> /// Copies a file between two filesystems. /// </summary> /// <param name="fs">The source filesystem</param> /// <param name="destFileSystem">The destination filesystem</param> /// <param name="srcPath">The source path of the file to copy from the source filesystem</param> /// <param name="destPath">The destination path of the file in the destination filesystem</param> /// <param name="overwrite"><c>true</c> to overwrite an existing destination file</param> public static void CopyFileCross(this IFileSystem fs, IFileSystem destFileSystem, UPath srcPath, UPath destPath, bool overwrite) { if (destFileSystem == null) { throw new ArgumentNullException(nameof(destFileSystem)); } // If this is the same filesystem, use the file system directly to perform the action if (fs == destFileSystem) { fs.CopyFile(srcPath, destPath, overwrite); return; } srcPath.AssertAbsolute(nameof(srcPath)); if (!fs.FileExists(srcPath)) { throw NewFileNotFoundException(srcPath); } destPath.AssertAbsolute(nameof(destPath)); var destDirectory = destPath.GetDirectory(); if (!destFileSystem.DirectoryExists(destDirectory)) { throw NewDirectoryNotFoundException(destDirectory); } if (destFileSystem.FileExists(destPath) && !overwrite) { throw new IOException($"The destination file path `{destPath}` already exist and overwrite is false"); } using (var sourceStream = fs.OpenFile(srcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var copied = false; try { using (var destStream = destFileSystem.OpenFile(destPath, FileMode.Create, FileAccess.Write, FileShare.Read)) { sourceStream.CopyTo(destStream); } // NOTE: For some reasons, we can sometimes get an Unauthorized access if we try to set the LastWriteTime after the SetAttributes // So we setup it here. destFileSystem.SetLastWriteTime(destPath, fs.GetLastWriteTime(srcPath)); // Preserve attributes and LastWriteTime as a regular File.Copy destFileSystem.SetAttributes(destPath, fs.GetAttributes(srcPath)); copied = true; } finally { if (!copied) { try { destFileSystem.DeleteFile(destPath); } catch { // ignored } } } } }
/// <summary> /// Returns an enumerable collection of <see cref="FileSystemEntry"/> that match a search pattern in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for files and directories.</param> /// <returns>An enumerable collection of <see cref="FileSystemEntry"/> that match a search pattern in a specified path.</returns> public static IEnumerable <FileSystemEntry> EnumerateFileSystemEntries(this IFileSystem fileSystem, UPath path) { return(EnumerateFileSystemEntries(fileSystem, path, "*")); }
/// <summary> /// Parses and normalize the specified path and <see cref="SearchPattern"/>. /// </summary> /// <param name="path">The path.</param> /// <param name="searchPattern">The search pattern.</param> /// <returns>An instance of <see cref="SearchPattern"/> in order to use <see cref="Match(Zio.UPath)"/> on a path.</returns> public static SearchPattern Parse(ref UPath path, ref string searchPattern) { return(new SearchPattern(ref path, ref searchPattern)); }
/// <summary> /// Returns an enumerable collection of file or directory names in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for files or directories.</param> /// <param name="searchPattern">The search string to match against the names of directories in path. This parameter can contain a combination /// of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.</param> /// <param name="searchOption">One of the enumeration values that specifies whether the search operation should include only the current directory /// or should include all subdirectories. /// The default value is TopDirectoryOnly.</param> /// <returns>An enumerable collection of the full names (including paths) for the files and directories in the directory specified by path.</returns> public static IEnumerable <UPath> EnumeratePaths(this IFileSystem fileSystem, UPath path, string searchPattern, SearchOption searchOption) { if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } return(fileSystem.EnumeratePaths(path, searchPattern, searchOption, SearchTarget.Both)); }
/// <summary> /// Returns an enumerable collection of <see cref="DirectoryEntry"/> that match a search pattern in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for directories.</param> /// <param name="searchPattern">The search string to match against the names of directories in path. This parameter can contain a combination /// of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.</param> /// <param name="searchOption">One of the enumeration values that specifies whether the search operation should include only the current directory /// or should include all subdirectories. /// The default value is TopDirectoryOnly.</param> /// <returns>An enumerable collection of <see cref="DirectoryEntry"/> from the specified path.</returns> public static IEnumerable <DirectoryEntry> EnumerateDirectoryEntries(this IFileSystem fileSystem, UPath path, string searchPattern, SearchOption searchOption) { if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } foreach (var subPath in EnumerateDirectories(fileSystem, path, searchPattern, searchOption)) { yield return(new DirectoryEntry(fileSystem, subPath)); } }
/// <summary> /// Returns an enumerable collection of file or directory names in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for files or directories.</param> /// <returns>An enumerable collection of the full names (including paths) for the files and directories in the directory specified by path.</returns> public static IEnumerable <UPath> EnumeratePaths(this IFileSystem fileSystem, UPath path) { return(EnumeratePaths(fileSystem, path, "*")); }
/// <summary> /// Returns an enumerable collection of file names in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for files.</param> /// <param name="searchPattern">The search string to match against the names of directories in path. This parameter can contain a combination /// of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.</param> /// <param name="searchOption">One of the enumeration values that specifies whether the search operation should include only the current directory /// or should include all subdirectories. /// The default value is TopDirectoryOnly.</param> /// <returns>An enumerable collection of the full names (including paths) for the files in the directory specified by path.</returns> public static IEnumerable <UPath> EnumerateFiles(this IFileSystem fileSystem, UPath path, string searchPattern, SearchOption searchOption) { if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } foreach (var subPath in fileSystem.EnumeratePaths(path, searchPattern, searchOption, SearchTarget.File)) { yield return(subPath); } }
/// <summary> /// Creates or overwrites a file in the specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path and name of the file to create.</param> /// <returns>A stream that provides read/write access to the file specified in path.</returns> public static Stream CreateFile(this IFileSystem fileSystem, UPath path) { path.AssertAbsolute(); return(fileSystem.OpenFile(path, FileMode.Create, FileAccess.ReadWrite)); }
/// <summary>Copies an existing file to a new file, allowing the overwriting of an existing file.</summary> /// <returns> /// A new file, or an overwrite of an existing file if <paramref name="overwrite" /> is true. If the file exists /// and <paramref name="overwrite" /> is false, an <see cref="T:System.IO.IOException" /> is thrown. /// </returns> /// <param name="destFileName">The name of the new file to copy to. </param> /// <param name="overwrite">true to allow an existing file to be overwritten; otherwise, false. </param> /// <exception cref="T:System.ArgumentException"> /// <paramref name="destFileName" /> is empty, contains only white spaces, or contains invalid characters. /// </exception> /// <exception cref="T:System.IO.IOException"> /// An error occurs, or the destination file already exists and /// <paramref name="overwrite" /> is false. /// </exception> /// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="destFileName" /> is null. /// </exception> /// <exception cref="T:System.IO.DirectoryNotFoundException"> /// The directory specified in <paramref name="destFileName" /> /// does not exist. /// </exception> /// <exception cref="T:System.UnauthorizedAccessException"> /// A directory path is passed in, or the file is being moved to a /// different drive. /// </exception> /// <exception cref="T:System.IO.PathTooLongException"> /// The specified path, file name, or both exceed the system-defined /// maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names /// must be less than 260 characters. /// </exception> /// <exception cref="T:System.NotSupportedException"> /// <paramref name="destFileName" /> contains a colon (:) in the middle of the string. /// </exception> public FileEntry CopyTo(UPath destFileName, bool overwrite) { FileSystem.CopyFile(Path, destFileName, overwrite); return(new FileEntry(FileSystem, destFileName)); }
/// <summary> /// Returns an enumerable collection of <see cref="FileSystemEntry"/> that match a search pattern in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for files and directories.</param> /// <param name="searchPattern">The search string to match against the names of directories in path. This parameter can contain a combination /// of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.</param> /// <returns>An enumerable collection of <see cref="FileSystemEntry"/> that match a search pattern in a specified path.</returns> public static IEnumerable <FileSystemEntry> EnumerateFileSystemEntries(this IFileSystem fileSystem, UPath path, string searchPattern) { if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } return(EnumerateFileSystemEntries(fileSystem, path, searchPattern, SearchOption.TopDirectoryOnly)); }
private SearchPattern(ref UPath path, ref string searchPattern) { path.AssertAbsolute(); if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } _exactMatch = null; _regexMatch = null; // Optimized path, most common case if (searchPattern == "*") { return; } if (searchPattern.StartsWith("/")) { throw new ArgumentException($"The search pattern `{searchPattern}` cannot start by an absolute path `/`"); } searchPattern = searchPattern.Replace('\\', '/'); // If the path contains any directory, we need to concatenate the directory part with the input path if (searchPattern.IndexOf('/') > 0) { var pathPattern = new UPath(searchPattern); var directory = pathPattern.GetDirectory(); if (!directory.IsNull && !directory.IsEmpty) { path = path / directory; } searchPattern = pathPattern.GetName(); // If the search pattern is again a plain any, optimized path if (searchPattern == "*") { return; } } bool appendSpecialCaseForExt3Chars = false; var startIndex = 0; int nextIndex; StringBuilder builder = null; try { while ((nextIndex = searchPattern.IndexOfAny(SpecialChars, startIndex)) >= 0) { if (builder == null) { builder = UPath.GetSharedStringBuilder(); builder.Append("^"); } var lengthToEscape = nextIndex - startIndex; if (lengthToEscape > 0) { var toEscape = Regex.Escape(searchPattern.Substring(startIndex, lengthToEscape)); builder.Append(toEscape); } var c = searchPattern[nextIndex]; var regexPatternPart = c == '*' ? "[^/]*" : "[^/]"; builder.Append(regexPatternPart); // If the specified extension is exactly three characters long, // the method returns files with extensions that begin with the specified extension. // For example, "*.xls" returns both "book.xls" and "book.xlsx". // 012345 // *.txt if (c == '*' && nextIndex + 5 == searchPattern.Length && searchPattern[nextIndex + 1] == '.' && searchPattern.IndexOf('.', nextIndex + 2) < 0) { appendSpecialCaseForExt3Chars = true; } startIndex = nextIndex + 1; } if (builder == null) { _exactMatch = searchPattern; } else { var length = searchPattern.Length - startIndex; if (length > 0) { var toEscape = Regex.Escape(searchPattern.Substring(startIndex, length)); builder.Append(toEscape); } if (appendSpecialCaseForExt3Chars) { builder.Append("[^/]*"); } builder.Append("$"); var regexPattern = builder.ToString(); _regexMatch = new Regex(regexPattern); } } finally { if (builder != null) { builder.Length = 0; } } }
/// <summary> /// Returns an enumerable collection of <see cref="FileSystemEntry"/> that match a search pattern in a specified path. /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The path of the directory to look for files and directories.</param> /// <param name="searchPattern">The search string to match against the names of directories in path. This parameter can contain a combination /// of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.</param> /// <param name="searchOption">One of the enumeration values that specifies whether the search operation should include only the current directory /// or should include all subdirectories. /// The default value is TopDirectoryOnly.</param> /// <param name="searchTarget">The search target either <see cref="SearchTarget.Both"/> or only <see cref="SearchTarget.Directory"/> or <see cref="SearchTarget.File"/>. Default is <see cref="SearchTarget.Both"/></param> /// <returns>An enumerable collection of <see cref="FileSystemEntry"/> that match a search pattern in a specified path.</returns> public static IEnumerable <FileSystemEntry> EnumerateFileSystemEntries(this IFileSystem fileSystem, UPath path, string searchPattern, SearchOption searchOption, SearchTarget searchTarget = SearchTarget.Both) { if (searchPattern == null) { throw new ArgumentNullException(nameof(searchPattern)); } foreach (var subPath in fileSystem.EnumeratePaths(path, searchPattern, searchOption, searchTarget)) { yield return(fileSystem.DirectoryExists(subPath) ? (FileSystemEntry) new DirectoryEntry(fileSystem, subPath) : new FileEntry(fileSystem, subPath)); } }
/// <summary> /// Normalizes the specified path and <see cref="SearchPattern"/>. /// </summary> /// <param name="path">The path.</param> /// <param name="searchPattern">The search pattern.</param> public static void Normalize(ref UPath path, ref string searchPattern) { Parse(ref path, ref searchPattern); }
/// <summary> /// Gets a <see cref="FileSystemEntry"/> for the specified path. If the file or directory does not exist, throws a <see cref="FileNotFoundException"/> /// </summary> /// <param name="fileSystem">The file system.</param> /// <param name="path">The file or directory path.</param> /// <returns>A new <see cref="FileSystemEntry"/> from the specified path.</returns> public static FileSystemEntry GetFileSystemEntry(this IFileSystem fileSystem, UPath path) { var fileExists = fileSystem.FileExists(path); if (fileExists) { return(new FileEntry(fileSystem, path)); } var directoryExists = fileSystem.DirectoryExists(path); if (directoryExists) { return(new DirectoryEntry(fileSystem, path)); } throw NewFileNotFoundException(path); }
public FileChangedEventArgs(IFileSystem fileSystem, WatcherChangeTypes changeType, UPath fullPath) { if (fileSystem is null) { throw new ArgumentNullException(nameof(fileSystem)); } fullPath.AssertNotNull(nameof(fullPath)); fullPath.AssertAbsolute(nameof(fullPath)); FileSystem = fileSystem; ChangeType = changeType; FullPath = fullPath; Name = fullPath.GetName(); }
/// <summary> /// Moves a file between two filesystems. /// </summary> /// <param name="fs">The source filesystem</param> /// <param name="destFileSystem">The destination filesystem</param> /// <param name="srcPath">The source path of the file to move from the source filesystem</param> /// <param name="destPath">The destination path of the file in the destination filesystem</param> public static void MoveFileCross(this IFileSystem fs, IFileSystem destFileSystem, UPath srcPath, UPath destPath) { if (destFileSystem == null) { throw new ArgumentNullException(nameof(destFileSystem)); } // If this is the same filesystem, use the file system directly to perform the action if (fs == destFileSystem) { fs.MoveFile(srcPath, destPath); return; } // Check source srcPath.AssertAbsolute(nameof(srcPath)); if (!fs.FileExists(srcPath)) { throw NewFileNotFoundException(srcPath); } // Check destination destPath.AssertAbsolute(nameof(destPath)); var destDirectory = destPath.GetDirectory(); if (!destFileSystem.DirectoryExists(destDirectory)) { throw NewDirectoryNotFoundException(destPath); } if (destFileSystem.DirectoryExists(destPath)) { throw NewDestinationDirectoryExistException(destPath); } if (destFileSystem.FileExists(destPath)) { throw NewDestinationFileExistException(destPath); } using (var sourceStream = fs.OpenFile(srcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var copied = false; try { using (var destStream = destFileSystem.OpenFile(destPath, FileMode.Create, FileAccess.Write, FileShare.Read)) { sourceStream.CopyTo(destStream); } // Preserve all attributes and times destFileSystem.SetAttributes(destPath, fs.GetAttributes(srcPath)); destFileSystem.SetCreationTime(destPath, fs.GetCreationTime(srcPath)); destFileSystem.SetLastAccessTime(destPath, fs.GetLastAccessTime(srcPath)); destFileSystem.SetLastWriteTime(destPath, fs.GetLastWriteTime(srcPath)); copied = true; } finally { if (!copied) { try { destFileSystem.DeleteFile(destPath); } catch { // ignored } } } } var deleted = false; try { fs.DeleteFile(srcPath); deleted = true; } finally { if (!deleted) { try { destFileSystem.DeleteFile(destPath); } catch { // ignored } } } }