我正在使用 System.IO.Packaing.Package 类来压缩文件。在读取和保存文件的同时运行我的应用程序的多个实例是可能的。处理小文件时一切似乎都很好,但是当涉及大文件时,如果应用程序的两个实例同时保存,我会收到一条异常消息 Store must be open for this operation,堆栈跟踪如下所示。
根据我的理解,在处理文件<10mb的包时,数据存储在一些内存流中,但是当内部>10mb时,它将切换到IsolatedStorage。考虑到这一点,我发现即使这些是多个运行的实例,它们都解决了相同的隔离存储位置,我相信这就是问题所在。我能够找到一个黑客来强制每个实例解决使用以下代码到不同的位置:
var rootDirUserField= typeof(IsolatedStorageFile).GetField("s_RootDirUser", BindingFlags.NonPublic | BindingFlags.Static);
rootDirUserField.SetValue(null, "<unique location in isolated storage>");
尽管这使问题消失了,但我一点也不喜欢它。请帮助弄清楚如何优雅地解决这个问题。在进一步的研究中,我发现IsolatedStorage 甚至不打算与多线程一起使用,这让我想知道为什么在处理包时它是一个选项。
at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, IsolatedStorageFile isf)
at MS.Internal.IO.Packaging.PackagingUtilities.SafeIsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, ReliableIsolatedStorageFileFolder folder)
at MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32 retryCount, String& fileName)
at MS.Internal.IO.Packaging.SparseMemoryStream.EnsureIsolatedStoreStream()
at MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
at MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at MS.Internal.IO.Zip.ZipIOFileItemStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[] buffer, Int32 offset, Int32 count)
更新:
此外,可能会遇到问题,因为要访问 IsolatedStorage,您的代码必须拥有所有必要的本机平台操作系统权限,如果没有,则无法创建 IsolatedStorage 流。
更新 2
已发布针对 Windows 8.1 和 Windows Server 2012 R2 上的 .NET Framework 4.5、4.5.1 和 4.5.2的修补程序以解决此问题。Eric White 还编写了一个新的 System.IO.Packaging 实现以不使用独立存储,这实际上将添加到 COREFX。他的实现可在此处获得。
Microsoft 指出的与此相关的 System.IO.Packaging 可能发生的其他问题如下。
当您在单独的线程上使用大型包时,可能会发生死锁。System.IO.Packaging 对大于 10 兆字节 (MB) 的包使用 IsolatedStorage。当两个或多个线程使用大包时,即使包是独立的,也可能发生死锁。死锁涉及两个线程。一个在 IsolatedStorageFile.Lock 中等待,而另一个在 IsoloatedStorageFile 类的另一个方法中等待。此问题已通过向 System.IO.Packaging 添加同步来解决,以避免隔离存储文件中的问题。当您从在不同线程上打开的包中检索 PackageProperties 时,即使这些包是独立的,也可能会发生异常。由此产生的最常见的调用堆栈如下:
System.Xml.XmlException: Unrecognized root element in Core Properties part. Line 2, position 2. at
MS.Internal.IO.Packaging.PartBasedPackageProperties.ParseCorePropertyPart(PackagePart part) at
System.IO.Packaging.Package.get_PackageProperties()
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: id at
MS.Internal.IO.Packaging.PartBasedPackageProperties.ParseCorePropertyPart(PackagePart part) at
System.IO.Packaging.Package.get_PackageProperties()
此问题是由共享内部资源的争用引起的,可以通过为每个包提供该资源的副本来解决。