簡體   English   中英

可觀察。使用和異步流獲取損壞的數據

[英]Observable.Using and async streams getting corrupted data

我有一股流,其目的是要計算一組.zip文件中內容的簡單“校驗和”

為此,我設置了一個可觀察到的:

  1. 獲取給定文件夾中的所有文件
  2. 讀取每個文件的內容(作為ZipArchive讀取)
  3. 對於每個文件中的每個條目,執行校驗和的計算

為了說明這一點,我創建了以下示例:

注意使用AsyncContext.Runhttps://stackoverflow.com/a/9212343/1025407 )來使Main方法等待GetChecksum因為它是控制台應用程序

namespace DisposePoC
{
    using System.Collections.Generic;
    using System.IO;
    using System.IO.Compression;
    using System.Reactive.Linq;
    using Nito.AsyncEx;
    using System.Linq;
    using System.Threading.Tasks;


    class Program
    {
        private static void Main()
        {
            AsyncContext.Run(GetChecksums);
        }

        private static async Task<IList<byte>> GetChecksums()
        {
            var bytes = Directory.EnumerateFiles("FolderWithZips")
                .ToObservable()
                .SelectMany(path => Observable.Using(() => CreateZipArchive(path), archive => archive.Entries.ToObservable()))
                .SelectMany(entry => Observable.Using(entry.Open, stream => Observable.FromAsync(() => CalculateChecksum(stream, entry.Length))));

            return await bytes.ToList();
        }

        private static ZipArchive CreateZipArchive(string path)
        {
            return new ZipArchive(new FileStream(path, FileMode.Open, FileAccess.Read));
        }

        private static async Task<byte> CalculateChecksum(Stream stream, long entryLength)
        {
            var bytes = await GetBytesFromStream(stream, entryLength);
            return bytes.Aggregate((b1, b2) => (byte) (b1 ^ b2));
        }

        private static async Task<byte[]> GetBytesFromStream(Stream stream, long entryLength)
        {
            byte[] bytes = new byte[entryLength];
            await stream.ReadAsync(bytes, 0, (int)entryLength);
            return bytes;            
        }
    }
}

運行該應用程序,我會遇到各種錯誤:

'System.IO.InvalidDataException':本地文件頭已損壞。 'System.NotSupportedException':流不支持讀取。 'System.ObjectDisposedException':無法訪問已處置的對象。 'System.IO.InvalidDataException':塊長度與其補碼不匹配。

我究竟做錯了什么?

可觀察性本身是否存在問題,還是因為ZipArchive並非線程安全的? 如果不是,如何使代碼正常工作?

Rx可能不是最合適的選擇。 老實說,您甚至可以在沒有異步的情況下進行操作。

Directory.EnumerateFiles("FolderWithZips")
         .AsParallel()
         .Select(folder => CalculateChecksum(folder))
         .ToList()

您的問題似乎沒有任何“ Rx”。

如果將整個事情修改為命令集,那么它會很好地工作

private static async Task<IList<byte>> GetChecksums()
{
    var bytes = new List<byte>();
    foreach (var path in Directory.EnumerateFiles("FolderWithZips"))
    {
        using (var archive = CreateZipArchive(path))
        {
            foreach (var entry in archive.Entries)
            {
                using (var stream = entry.Open())
                {
                    var checksum = await CalculateChecksum(stream, entry.Length);
                    bytes.Add(checksum);
                }
            }
        }
    }

    return bytes;
}

因此,我想您會遇到一系列競爭條件(並發)和/或亂序處理問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM