2012-01-13 43 views
12

编辑:从Tim Schmelter阅读答案编号1,然后使用这个问题来举例说明如何嵌入资源并在运行时访问它们。解开关于嵌入式资源的混淆

嵌入式资源的主题出现了很多,尤其是在人们询问如何在运行时访问嵌入式文件的情况下。事情变得更加令人困惑,因为Visual Studio为您提供了两种不同的嵌入资源的方式,以及在运行时访问这些资源的不同方式。问题在于,根据您用来嵌入资源的方法,您尝试在运行时用于访问文件的方法可能不起作用。这篇文章是为了澄清我所看到的所有困惑,但我也有一个问题,没有人能够真实地回答:为什么我编译的程序TWICE的大小与嵌入式资源的大小有时相同?例如,如果我将20MB文件嵌入到我的项目中,为什么我的程序会编译为40MB?我过去曾问过这个问题,但没有人能够重现我的结果。我发现他们无法重现的原因是因为他们以不同的方式嵌入文件。在这里看到:

方法1:在我的项目

双击打开属性页,然后转到资源选项卡。现在点击添加资源>添加现有文件。浏览到您要嵌入的文件。对于这个例子,我正在使用可执行文件。现在,您将看到您在资源选项卡文件:

enter image description here

您也将看到一个名为Resources文件夹中的项目下创建和嵌入的文件已经放在此文件夹中:

enter image description here

编辑:这下一步是问题。当你通过资源标签添加一个文件时,你应该设置而不是设置构建对嵌入资源的操作。反击直觉可以说至少!

现在选中该文件,向下看文件的属性窗口,并将构建操作更改为嵌入式资源:(此步骤只能在通过方法2添加文件时执行)。

enter image description here

现在编译程序。你会看到你编译的程序的大小至少是嵌入式资源大小的两倍。这不会发生的方法2,请参阅:

方法2:在您的项目名称

右键单击,然后选择添加>现有项。浏览到您的文件,这时候你会发现,虽然这确实是放在你的项目下,也没有创建资源文件夹:

enter image description here

现在再次选择该文件并更改生成操作嵌入式资源和编译。这一次编译后的程序的大小将与预期的一样 - 关于嵌入文件的大小,而不是方法1的两倍。

您使用哪种方法来嵌入文件将决定您可以使用哪种方法在运行时访问文件。对于方法1,这是很简单的,你需要做的是:

My.Computer.FileSystem.WriteAllBytes(Path, My.Resources.ResourceName, Append) 

其中Path是要保存在硬盘文件的位置和名称,资源名称是嵌入式资源的名称,你在项目窗口中查看(减去任何扩展名),Append是您是否要创建新文件或覆盖现有文件。因此,例如,使用TEST.EXE从上面的图片,我可以说文件保存到C盘是这样的:

My.Computer.FileSystem.WriteAllBytes(“C:\test.exe”, My.Resources.test, False) 

再简单不过了。

然而,方法2似乎不能让您访问My.Resources,因此它会变得更复杂一些。您必须创建一个Stream来保存资源,将该流放入一个字节数组,然后将这些字节写入文件系统。我发现这样做最简单的方法是这样的:

Using s As Stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(Project.ResourceName) 
Dim bytes(s.Length) As Byte 
s.Read(bytes, 0, bytes.Length) 
File.WriteAllBytes(OutputFile, bytes) 
End Using 

采用这种方法资源名称必须包含文件扩展名和项目名称,以便使用从上面我们可以做我们的例子:

Using s As Stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(WindowsApplication1.test.exe) 
Dim bytes(s.Length) As Byte 
s.Read(bytes, 0, bytes.Length) 
File.WriteAllBytes(“C:\test.exe”, bytes) 
End Using 

基于文本的文件有点不同:

Dim output As String 
Using sr As StreamReader = New StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(WindowsApplication1.test.txt)) 
output = sr.ReadToEnd() 
End Using 

Using sw As StreamWriter = New StreamWriter(“C:\test.txt”) 
sw.Write(output) 
End Using 

在过去一直困扰着我,我希望这会帮助别人。如果你认为你可以真实地解释为什么嵌入资源的方法1使我编译的程序扩大了两倍,我真的很感激它。

回答

9

我假设方法1是两次添加文件。

至少这是thread above的结论。

报价

你去到项目属性的资源页面添加的文件存在,对不对?然后,您进入解决方案资源管理器并将文件的Build Action更改为Embedded Resource,对吧?这就是为什么你将文件大小加倍:你将每个文件添加两次。

有两种不同的添加资源的方式:在项目属性的资源页面和解决方案资源管理器中。你不这样做。如果你想使用GetManifestResourcestream,那么你不使用资源页面。您可以手动将这些文件添加到Solution Explorer中的项目中,然后将Build Action设置为Embedded Resource。

未来,做一个或另一个,而不是两个。

  1. 将文件添加到项目属性的资源页面,然后通过My.Resources访问它。这会自动将文件添加到解决方案资源管理器中的项目中,但Build Action将为None,并且应该保留该方式。

  2. 使用添加新项目或添加现有项目将文件添加到解决方案资源管理器中的项目。将文件的Build Action设置为Embedded Resource,然后使用GetManifestResourceStream访问资源。

+0

你是绝对正确的。我自己的困惑在于,即使在通过资源选项卡添加文件时,构建操作也必须设置为“嵌入式资源”。我想这是一个非常普遍的错误。因此,考虑到My.Resources使事情变得如此简单,为什么我不想使用资源选项卡来添加嵌入式资源? – 2012-01-13 15:00:31