예제 #1
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 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);
            }
        }