您可以在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)
返回一个UnmanagedMemoryStream
,它实际上也会在内部调用GetObject(String)
,并且仍然会创建一个副本。如果您调试应用程序并分析内存,则会看到仍然分配了内存。
我尝试使用指针在unsafe
上下文中和反射等多种方法来解决此问题,但都没有成功。 ResourceManager
并不是那么灵活或优化。
然而,我找到了一种解决方案,但需要您使用嵌入式资源
。这不会改变任何内容,除了将资源文件的构建操作设置为嵌入式资源
。通过使用这种方法,您可以使用反射创建一个不创建数据副本的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
找到解决方案,因为它不够灵活。
编辑 我在这里撰写了一篇深入的博客文章,介绍了这个主题。
GetStream
而不是GetObject
的原因;以避免先将整个文件读入内存。 - Bradley Smith