【问题标题】:Cannot access a closed Stream?无法访问已关闭的 Stream?
【发布时间】:2016-03-22 13:51:50
【问题描述】:

我刚刚在我的代码中遇到了一个错误,它打开了文件并读取了 rawData。

我得到的错误如下:

如您所见,我正在打开一个内存流,但在这样做时我收到一条错误消息,提示我无法访问该流?

我无法访问关闭的流有什么原因吗?

使用的代码:

// Try to decompress the file data.
byte[] rawData = null;

using (MemoryStream zipStream = new MemoryStream(fileData))
{
    if (ZipPackage.IsZipFile(zipStream))
    {
        using (ZipPackage unzipper = ZipPackage.Open(zipStream))
        {
            // The zip package only contains one entry since GeoObject.FileData only contains one shape or POI.
            if (unzipper.ZipPackageEntries.Count > 0)
            {
                StreamReader reader = new StreamReader(unzipper.ZipPackageEntries[0].OpenInputStream());
                rawData = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd());
            }
        }
    }
}

堆栈

at System.IO.__Error.StreamIsClosed()
at System.IO.MemoryStream.set_Position(Int64 value)
at Telerik.Windows.Zip.ZipPackage.IsZipFile(Stream stream)
at Satmap.Planner.Silverlight.XmlConverters.DBGeoObjectsToFromDBShapes.ExtractRawFileData(GeoObject geoObject, Byte[] fileData)
at Satmap.Planner.Silverlight.DatabaseShapesToFromMapShapes.ConvertDatabaseShapesToMapShapes(GeoObject geoObject, Boolean filter)
at Satmap.Planner.Silverlight.DatabaseShapesToFromMapShapes.ConvertDatabaseShapesToMapShapes(GeoObject geoObject)
at Satmap.Planner.Silverlight.ViewControllers.MainMapViewController.BackgroundWorkerFileLoad_RunWorkerCompleted(Object sender, RunWorkerCompletedEventArgs e)
at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
at System.ComponentModel.BackgroundWorker.<OnRun>b__1(Object state) 

新堆栈:

at System.IO.MemoryStream.set_Capacity(Int32 value)
at System.IO.MemoryStream.EnsureCapacity(Int32 value)
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Stream.InternalCopyTo(Stream destination, Int32 bufferSize)
at System.IO.Stream.CopyTo(Stream destination)
at Telerik.Windows.Zip.ZipArchive.WriteArchive()
at Telerik.Windows.Zip.ZipArchive.Dispose(Boolean disposing)
at Telerik.Windows.Zip.ZipArchive.Dispose()
at Satmap.Planner.Silverlight.XmlConverters.DBGeoObjectsToFromDBShapes.ExtractRawFileData(GeoObject geoObject, Byte[] fileData)
at Satmap.Planner.Silverlight.DatabaseShapesToFromMapShapes.ConvertDatabaseShapesToMapShapes(GeoObject geoObject, Boolean filter)
at Satmap.Planner.Silverlight.DatabaseShapesToFromMapShapes.ConvertDatabaseShapesToMapShapes(GeoObject geoObject)
at Satmap.Planner.Silverlight.ViewControllers.MainMapViewController.BackgroundWorkerFileLoad_RunWorkerCompleted(Object sender, RunWorkerCompletedEventArgs e)
at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
at System.ComponentModel.BackgroundWorker.<OnRun>b__1(Object state)

【问题讨论】:

  • 发布简短的可执行代码和包含堆栈的异常 ToString 输出。看起来像是 zip 库中的错误。
  • @usr 我已经添加了信息。如果您需要更多信息,请告诉我。
  • 看起来像一个错误,内部代码崩溃。向泰勒里克报告。他们也希望查看样本数据以进行重现。
  • 似乎不太可能。小心调试器的 Set Next Statement 命令。

标签: c# stream streamreader memorystream


【解决方案1】:

您在这里看到的是 Telerik ZipPackage 类的行为。静态 IsZipFile 方法正在处理流,可能是由于一个错误(您可以联系 Telerik 支持)。

但是,您可能没有必要首先检查 zip 包的有效性。只需在相关代码周围使用try...catch

// Try to decompress the file data.
byte[] rawData = null;

using (MemoryStream zipStream = new MemoryStream(fileData))
{
    try
    {
        using (ZipPackage unzipper = ZipPackage.Open(zipStream))
        {
            // The zip package only contains one entry since GeoObject.FileData only contains one shape or POI.
            if (unzipper.ZipPackageEntries.Count > 0)
            {
                StreamReader reader = new StreamReader(unzipper.ZipPackageEntries[0].OpenInputStream());
                rawData = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd());
            }
        }
    }
    catch (Exception ex)
    {
         // ZipPackage throws an exception of type Exception if the 
         // package is not valid. Handle exception here, e.g. log etc
    }
}

更新

Telerik 的 ZipArchive 类似乎是一只奇怪的野兽。如果您使用的是 .NET 4.5 或更高版本,则最好切换到 System.IO.Compression.ZipArchive 类。如果没有,您可以通过不从固定数组创建内存流来解决不可扩展内存流的问题。你可以使用 new MemoryStream(fileData) 而不是:

using (var zipStream = new MemoryStream())
{
    zipStream.Write(fileData, 0, fileData.Length);
    zipStream.Position = 0;

    // continue here
}

【讨论】:

  • 感谢您的回答。我刚刚进行了更改,然后错误Memory stream is not expandable. 被捕获在异常中?
  • @BenClarke:你能更新你的问题并发布新的堆栈跟踪吗?
  • 感谢您的更新,现在一切正常。为什么写入 Stream 可以工作,但我不能作为参数传递?
  • 当您通过传入字节数组创建MemoryStream 时,内存流将获得固定大小且不可调整大小。您可以对其进行写入,但写入的字节数不得超过初始大小。如果您只是创建一个MemoryStream,则内部缓冲区不是固定大小的,并且在您写入时会增长。 - 为什么 Telerik ZipArchive 类想要写入流,尽管你所做的只是要求它读取我完全不知道的包。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-05
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 2017-12-15
  • 2013-07-15
  • 2011-01-20
相关资源
最近更新 更多