public async Task AddFileAsync(FileContainerEntityParam param, Func <ISequentialWritable <byte>, CancellationToken, Task <bool> > composeProc, long?fileSizeHint = null, CancellationToken cancel = default)
        {
            param.Validate();

            using var doorHolder   = Door.Enter();
            using var cancelHolder = this.CreatePerTaskCancellationToken(out CancellationToken c, cancel);

            if (this.CanWrite == false)
            {
                throw new CoresException("Current state doesn't allow write operations.");
            }

            // 実装の新規ファイル作成を呼び出す
            SequentialWritableImpl <byte> obj = await AddFileAsyncImpl(param, fileSizeHint, c);

            try
            {
                // ユーザー提供の composeProc を呼び出す
                // これによりユーザーは ISequentialWritable に対して書き込み操作を実施する
                bool ok = await composeProc(obj, c);

                // 実装のファイル追加処理を完了させる
                await obj.CompleteAsync(ok, c);
            }
            catch
            {
                // 途中で何らかのエラーが発生した
                // 実装のファイル追加処理を失敗させる
                await obj.CompleteAsync(false, c);

                throw;
            }
        }
 public async Task AddFileSimpleDataAsync(FileContainerEntityParam param, ReadOnlyMemory <byte> data, CancellationToken cancel = default)
 {
     await AddFileAsync(param, async (w, c) =>
     {
         await w.AppendAsync(data, cancel);
         return(true);
     },
                        fileSizeHint : data.Length,
                        cancel : cancel);
 }
        ///////////// 以下はユーティリティ関数

        // 任意のファイルシステムの物理ファイルをインポートする
        public async Task ImportFileAsync(FilePath srcFilePath, FileContainerEntityParam destParam, CancellationToken cancel = default)
        {
            destParam._NullCheck();

            destParam = destParam._CloneDeep();

            // 元ファイルのメタデータ読み込み
            destParam.MetaData = await srcFilePath.GetFileMetadataAsync(FileMetadataGetFlags.NoAlternateStream | FileMetadataGetFlags.NoAuthor | FileMetadataGetFlags.NoPhysicalFileSize | FileMetadataGetFlags.NoPreciseFileSize | FileMetadataGetFlags.NoSecurity);

            int bufferSize = CoresConfig.BufferSizes.FileCopyBufferSize;

            // 元ファイルを開く
            using (var srcFile = await srcFilePath.OpenAsync(false, cancel: cancel))
            {
                // 先ファイルを作成
                await this.AddFileAsync(destParam, async (w, c) =>
                {
                    // 元ファイルから先ファイルにデータをコピー
                    byte[] buffer = ArrayPool <byte> .Shared.Rent(bufferSize);

                    try
                    {
                        while (true)
                        {
                            int readSize = await srcFile.ReadAsync(buffer, cancel);
                            if (readSize == 0)
                            {
                                break;
                            }

                            await w.AppendAsync(buffer.AsMemory(0, readSize), cancel);
                        }
                    }
                    finally
                    {
                        ArrayPool <byte> .Shared.Return(buffer, false);
                    }

                    return(true);
                },
                                        destParam.MetaData.Size,
                                        cancel);
            }
        }
Ejemplo n.º 4
0
        // ユーザーが新しいファイルの追加要求を行なうとこの実装メソッドが呼び出される。
        // このメソッドで返した ISequentialWritable<byte> は、必ず Complete されることが保証されている。
        // また、多重呼び出しがされないことが保証されている。
        protected override async Task <SequentialWritableImpl <byte> > AddFileAsyncImpl(FileContainerEntityParam param, long?fileSizeHint, CancellationToken cancel = default)
        {
            // fileParam をコピー (加工するため)
            param = param._CloneDeep();

            // ファイル名などのチェック
            if (param.MetaData.IsDirectory)
            {
                throw new ArgumentOutOfRangeException(nameof(param), "Directory is not supported.");
            }

            param.PathString._FilledOrException();
            param.PathString = PathParser.NormalizeDirectorySeparatorIncludeWindowsBackslash(param.PathString);

            if (PathParser.IsAbsolutePath(param.PathString))
            {
                throw new ArgumentOutOfRangeException(nameof(param), $"Absolute path '{param.PathString}' is not supported.");
            }

            Encoding encoding = param.GetEncoding();

            param.PathString._CheckStrSizeException(ZipConsts.MaxFileNameSize, encoding);

            Writable w = new Writable(this, param, encoding, fileSizeHint ?? long.MaxValue);

            // ローカルファイルヘッダを書き込む
            await w.StartAsync(cancel);

            // 実装クラスを経由してユーザーに渡す
            return(w);
        }
        // 任意のファイルシステムのディレクトリ内のファイルを再帰的にインポートする
        public async Task ImportDirectoryAsync(DirectoryPath srcRootDir,
                                               FileContainerEntityParam?paramTemplate   = null,
                                               Func <FileSystemEntity, bool>?fileFilter = null,
                                               Func <DirectoryPathInfo, Exception, CancellationToken, Task <bool> >?exceptionHandler = null,
                                               string?directoryPrefix   = null,
                                               CancellationToken cancel = default)
        {
            if (paramTemplate == null)
            {
                paramTemplate = new FileContainerEntityParam("");
            }

            directoryPrefix = directoryPrefix._NonNullTrim();

            if (directoryPrefix._IsFilled())
            {
                if (directoryPrefix[0] == '\\' || directoryPrefix[0] == '/')
                {
                    directoryPrefix = directoryPrefix.Substring(1);
                }

                directoryPrefix = PathParser.Windows.RemoveLastSeparatorChar(directoryPrefix);
            }

            bool ret = await srcRootDir.FileSystem.DirectoryWalker.WalkDirectoryAsync(srcRootDir,
                                                                                      async (dirInfo, entries, c) =>
            {
                foreach (var e in entries.Where(x => x.IsFile))
                {
                    // フィルタ検査
                    if (fileFilter != null && fileFilter(e) == false)
                    {
                        continue;
                    }

                    // ファイル名の決定
                    string relativeFileName            = dirInfo.FileSystem.PathParser.GetRelativeFileName(e.FullPath, srcRootDir);
                    FileContainerEntityParam fileParam = paramTemplate._CloneDeep();

                    if (directoryPrefix._IsFilled())
                    {
                        relativeFileName = directoryPrefix + "/" + relativeFileName;
                    }

                    fileParam.PathString = relativeFileName;

                    await this.ImportFileAsync(new FilePath(e.FullPath, dirInfo.FileSystem), fileParam, c);
                }

                return(true);
            },
                                                                                      null,
                                                                                      exceptionHandler,
                                                                                      true,
                                                                                      cancel);

            if (ret == false)
            {
                throw new OperationCanceledException();
            }
        }
 public void ImportFile(FilePath srcFilePath, FileContainerEntityParam destParam, CancellationToken cancel = default)
 => ImportFileAsync(srcFilePath, destParam, cancel)._GetResult();
 public void AddFileSimpleData(FileContainerEntityParam param, ReadOnlyMemory <byte> data, CancellationToken cancel = default)
 => AddFileSimpleDataAsync(param, data, cancel)._GetResult();
 public void AddFile(FileContainerEntityParam param, Func <ISequentialWritable <byte>, CancellationToken, bool> composeProc, long?fileSizeHint = null, CancellationToken cancel = default)
 => AddFileAsync(param, (x, y) => Task.FromResult(composeProc(x, y)), fileSizeHint, cancel)._GetResult();
 // FileContainer の派生クラスが具備すべきメソッド一覧
 protected abstract Task <SequentialWritableImpl <byte> > AddFileAsyncImpl(FileContainerEntityParam param, long?fileSizeHint, CancellationToken cancel = default);