MemoryStream 而不是字節對於作為資源添加的文件?
我有一個 .NET 程序集,我向其中添加了許多文件作為資源(二進製文件,每個文件 >500KB)。我以前一直在使用
ResourceManager.GetObject()自動生成的Resources類上的方法訪問這些,它返回一個byte[].出於性能和語法的原因,我寧願將這些二進制資源作為流而不是字節數組進行操作。我發現,通過手動編輯 .resx 文件並將
<value>元素中的類名稱從System.Byte[]更改為System.IO.MemoryStream,我可以使用該ResourceManager.GetStream()方法成功地以流的形式訪問資源,例如<data name="MyFile" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\MyFile.ext;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </data>變成:
<data name="MyFile" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\MyFile.ext;System.IO.MemoryStream, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </data>這種方法的唯一缺點是 Visual Studio 總是在
byte[]表單中添加新的文件資源。有沒有辦法讓它MemoryStream為我設置類型?
您可以在
ResourceManager.public static class ResourceExtensions { public static MemoryStream GetMemoryStream(this ResourceManager resourceManager, String name) { object resource = resourceManager.GetObject(name); if (resource is byte[]) { return new MemoryStream((byte[])resource); } else { throw new System.InvalidCastException("The specified resource is not a binary resource."); } } }打電話
ResourceManager resourceManager = Properties.Resources.ResourceManager; MemoryStream stream = resourceManager.GetMemoryStream("binaryResource");不過,這似乎也一樣。
MemoryStream stream = new MemoryStream(Properties.Resources.SomeBinaryResource);我不確定我是否會修改資源文件,因為它們很容易更改,而且我確信在某些情況下 Visual Studio 會覆蓋更改。
根據您的擔憂,問題在於這會將數據的副本創建到記憶體中,從而產生記憶體佔用。對於壽命很短的輕量級資源,這不是問題,但它可能是一個大問題。
答案很簡短:您無法避免使用
ResourceManager. 問題是兩者都ResourceManager.GetObject(String)創建ResourceManager.GetStream(String)了數據的副本。即使GetStream(String)返回 anUnmanagedMemoryStream,它實際上也會在GetObject(String)內部呼叫,並且仍然會創建一個副本。如果您調試應用程序並分析記憶體,您將看到記憶體仍然被分配。我嘗試了多種方法來解決這個問題,方法是在
unsafe上下文中使用指針和反射,但沒有任何效果。ResourceManager只是沒有那麼靈活或優化。但是,我能夠找到解決方案,但它需要您使用
Embedded Resources. 除了將資源文件的建構操作設置Embedded Resource為Build Action. 使用它,您可以使用反射來創建一個UnmanagedMemoryStream不創建數據副本的對象。private UnmanagedMemoryStream GetUnmanagedMemoryStream(String embeddedResourceName) { Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNames = assembly.GetManifestResourceNames(); string resourceName = resourceNames.SingleOrDefault(resource => resource.EndsWith(embeddedResourceName, StringComparison.InvariantCultureIgnoreCase)); if (resourceName != null) { return (UnmanagedMemoryStream)assembly.GetManifestResourceStream(resourceName); } else { throw new System.ArgumentException("The specified embedded resource could not be found.", "embeddedResourceName"); } }我沒有對此進行廣泛的測試,但它確實有效。我的測試數據是一個 17 兆字節的小文件。我的測試應用程序的工作集記憶體從大約 50 兆字節開始,在將資源檢索到流中後,它不會改變。當使用
ResourceManager它時,它會立即通過資源的大小增加工作集。您可能需要換出對
EndsWith清單中正確資源名稱檢查的呼叫,因為資源名稱與直接通過ResourceManager.我實際上很失望,我無法使用現有的 . 找到解決方案
ResourceManager,但它不夠靈活。