Bra*_*ith 8 .net resx stream visual-studio-2010
我有一个.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>
Run Code Online (Sandbox Code Playgroud)
变为:
<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>
Run Code Online (Sandbox Code Playgroud)
这种方法的唯一缺点是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.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
呼唤
ResourceManager resourceManager = Properties.Resources.ResourceManager;
MemoryStream stream = resourceManager.GetMemoryStream("binaryResource");
Run Code Online (Sandbox Code Playgroud)
虽然,这似乎也一样。
MemoryStream stream = new MemoryStream(Properties.Resources.SomeBinaryResource);
Run Code Online (Sandbox Code Playgroud)
我不确定是否会修改资源文件,因为它们很容易更改,而且我确定在某些情况下Visual Studio会覆盖更改。
您所关心的问题是,这会将数据复制到内存中,从而占用内存。对于寿命短的轻量级资源,这不是问题,但这可能是一个大问题。
答案很简短:您无法使用来避免占用内存ResourceManager。问题是,无论是ResourceManager.GetObject(String)和ResourceManager.GetStream(String)创建数据的副本。即使GetStream(String)返回UnmanagedMemoryStream,它实际上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");
}
}
Run Code Online (Sandbox Code Playgroud)
我没有对此进行广泛的测试,但是确实可以。我的测试数据是一个17 MB的小文件。我的测试应用程序的工作集内存开始于大约50兆字节,并且在将资源检索到流中之后,它没有变化。使用时ResourceManager,会立即通过资源的大小增加工作集。
您可能需要交换EndsWith对清单中相应资源名称进行检查的调用,因为资源名称与直接通过进行访问的资源略有不同ResourceManager。
我很失望,因为我无法使用现有的解决方案找到解决方案ResourceManager,但是它不够灵活。
编辑我在这里写了一篇有关该主题的深入博客文章。
| 归档时间: |
|
| 查看次数: |
5853 次 |
| 最近记录: |