/// <summary> /// Function to copy the contents of a file system to the writable area. /// </summary> /// <param name="sourceFileSystem">The <see cref="IGorgonFileSystem"/> to copy.</param> /// <param name="copyProgress">A method callback used to track the progress of the copy operation.</param> /// <param name="allowOverwrite">[Optional] <b>true</b> to allow overwriting of files that already exist in the file system with the same path, <b>false</b> to throw an exception when a file with the same path is encountered.</param> /// <returns>A <see cref="ValueTuple{T1,T2}"/> containing the number of directories (<c>item1</c>) and the number of files (<c>item2</c>) copied, or <b>null</b> if the operation was cancelled.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="sourceFileSystem"/> parameter is <b>null</b>.</exception> /// <exception cref="IOException">Thrown when the a file exists in <see cref="IGorgonFileSystemWriter{T}.FileSystem"/>, and the <paramref name="allowOverwrite"/> parameter is set to <b>false</b>.</exception> /// <remarks> /// <para> /// This copies all the file and directory information from one file system, into the <see cref="IGorgonFileSystemWriter{T}.FileSystem"/> linked to this writer. /// </para> /// <para> /// When the <paramref name="allowOverwrite"/> is set to <b>false</b>, and a <see cref="IGorgonVirtualFile"/> already exists with the same path as another <see cref="IGorgonVirtualFile"/> in the /// <paramref name="sourceFileSystem"/>, then an exception will be raised. /// </para> /// </remarks> public (int DirectoryCount, int FileCount)? CopyFrom(IGorgonFileSystem sourceFileSystem, Func <GorgonWriterCopyProgress, bool> copyProgress = null, bool allowOverwrite = true) { if (sourceFileSystem == null) { throw new ArgumentNullException(nameof(sourceFileSystem)); } IGorgonVirtualFile[] files = sourceFileSystem.FindFiles("/", "*").ToArray(); IGorgonVirtualDirectory[] directories = sourceFileSystem.FindDirectories("/", "*").ToArray(); return((files.Length == 0) && (directories.Length == 0) ? ((int DirectoryCount, int FileCount)?)(0, 0) : CopyInternal(copyProgress, allowOverwrite, files, directories, CancellationToken.None)); }
/// <summary> /// Function to asynchronously copy the contents of a file system to the writable area. /// </summary> /// <param name="sourceFileSystem">The <see cref="IGorgonFileSystem"/> to copy.</param> /// <param name="cancelToken">The <see cref="CancellationToken"/> used to cancel an in progress copy.</param> /// <param name="copyProgress">A method callback used to track the progress of the copy operation.</param> /// <param name="allowOverwrite">[Optional] <b>true</b> to allow overwriting of files that already exist in the file system with the same path, <b>false</b> to throw an exception when a file with the same path is encountered.</param> /// <returns>A <see cref="ValueTuple{T1,T2}"/> containing the number of directories (<c>item1</c>) and the number of files (<c>item2</c>) copied, or <b>null</b> if the operation was cancelled.</returns> /// <remarks> /// <para> /// This copies all the file and directory information from one file system, into the <see cref="IGorgonFileSystemWriter{T}.FileSystem"/> linked to this writer. /// </para> /// <para> /// When the <paramref name="allowOverwrite"/> is set to <b>false</b>, and a <see cref="IGorgonVirtualFile"/> already exists with the same path as another <see cref="IGorgonVirtualFile"/> in the /// <paramref name="sourceFileSystem"/>, then an exception will be raised. /// </para> /// <para> /// This version of the copy method allows for an asynchronous copy of a set of a files and directories from another <see cref="IGorgonFileSystem"/>. This method should be used when there is a large /// amount of data to transfer between the file systems. /// </para> /// <para> /// Unlike the <see cref="IGorgonFileSystemWriter{T}.CopyFrom"/> method, this method will report the progress of the copy through the <paramref name="copyProgress"/> callback. This callback is a method that takes a /// <see cref="GorgonWriterCopyProgress"/> value as a parameter that will report the current state, and will return a <see cref="bool"/> to indicate whether to continue the copy or not (<b>true</b> to /// continue, <b>false</b> to stop). /// </para> /// <para> /// <note type="warning"> /// <para> /// The <paramref name="copyProgress"/> method does not switch back to the UI context. Ensure that you invoke any operations that update a UI on the appropriate thread (e.g <c>BeginInvoke</c> on a /// WinForms UI element or <c>Dispatcher</c> on a WPF element). /// </para> /// </note> /// </para> /// <para> /// This method also allows for cancellation of the copy operation by passing a <see cref="CancellationToken"/> to the <paramref name="cancelToken"/> parameter. /// </para> /// </remarks> public async Task <(int DirectoryCount, int FileCount)?> CopyFromAsync(IGorgonFileSystem sourceFileSystem, CancellationToken cancelToken, Func <GorgonWriterCopyProgress, bool> copyProgress = null, bool allowOverwrite = true) { if (sourceFileSystem == null) { throw new ArgumentNullException(nameof(sourceFileSystem)); } // ReSharper disable MethodSupportsCancellation (IGorgonVirtualFile[] Files, IGorgonVirtualDirectory[] Directories) = await Task.Run(() => { IGorgonVirtualFile[] files = sourceFileSystem.FindFiles("/", "*").ToArray(); IGorgonVirtualDirectory[] directories = sourceFileSystem.FindDirectories("/", "*").ToArray(); return(Files : files, Directories : directories); }).ConfigureAwait(false); return((Files.Length == 0) && (Directories.Length == 0) ? ((int DirectoryCount, int FileCount)?)(0, 0) : await Task.Run(() => CopyInternal(copyProgress, allowOverwrite, Files, Directories, cancelToken), cancelToken).ConfigureAwait(false)); // ReSharper restore MethodSupportsCancellation }
/// <summary> /// Function to copy data from a file system to the file system linked to this writer. /// </summary> /// <param name="sourceFileSystem">The file system to copy from.</param> /// <param name="progress">The callback for copy progress.</param> /// <param name="allowOverwrite">Flag to indicate whether to allow overwriting files or not.</param> /// <param name="token">The cancellation token for asynchronous copy.</param> /// <returns>A tuple containing the count of the directories and files copied.</returns> private (int DirectoryCount, int FileCount)? CopyInternal(IGorgonFileSystem sourceFileSystem, Func <GorgonWriterCopyProgress, bool> progress, bool allowOverwrite, CancellationToken token) { int directoryCount = 0; int fileCount = 0; // Enumerate files and directories from the source. IGorgonVirtualFile[] files = sourceFileSystem.FindFiles("/", "*").ToArray(); IGorgonVirtualDirectory[] directories = sourceFileSystem.FindDirectories("/", "*").ToArray(); if ((files.Length == 0) && (directories.Length == 0)) { return(0, 0); } // Create all the directories. foreach (IGorgonVirtualDirectory directory in directories) { if (token.IsCancellationRequested) { return(null); } CreateDirectory(directory.FullPath); ++directoryCount; } foreach (IGorgonVirtualFile file in files) { IGorgonVirtualFile destFile = FileSystem.GetFile(file.FullPath); if (token.IsCancellationRequested) { return(null); } // Do not allow overwrite if the user requested it. if ((destFile != null) && (!allowOverwrite)) { throw new IOException(string.Format(Resources.GORFS_ERR_FILE_EXISTS, destFile.FullPath)); } // Copy the file. using (Stream sourceStream = file.OpenStream()) { using (Stream destStream = OpenStream(file.FullPath, FileMode.Create)) { sourceStream.CopyTo(destStream, 80000); } } ++fileCount; if (progress == null) { continue; } if (!progress(new GorgonWriterCopyProgress(file, fileCount, files.Length, directories.Length))) { return(null); } } return(directoryCount, fileCount); }