揭开嵌入式资源的混乱局面

时间:2012-01-13 14:23:48

标签: vb.net visual-studio embedded-resource

编辑:阅读Tim Schmelter的答案1,然后使用此问题获取如何嵌入资源并在运行时访问它们的示例。

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

方法1:

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

enter image description here

您还会看到在项目下创建了名为Resources的文件夹,并且嵌入的文件已放在此文件夹中:

enter image description here

编辑:这个下一步是问题所在。当你通过资源标签添加文件时,你应该将构建行为设置为嵌入资源。至少可以直截了当地说出反对!

现在选择文件,查看文件的属性窗口,并将构建操作更改为嵌入式资源:(仅当通过方法2添加文件时才应执行此步骤。)

enter image description here

现在编译你的程序。您将看到已编译程序的大小至少是嵌入式资源大小的两倍。方法2不会发生这种情况。请参见此处:

方法2:

右键单击您的项目名称,然后选择添加>现有项目。浏览到您的文件,这次您会注意到,当它确实放在您的项目下时,没有创建Resources文件夹:

enter image description here

现在再次选择文件并将Build Action更改为Embedded Resource并进行编译。这次编译程序的大小将与您预期的一样 - 大约是嵌入文件的大小,而不是方法1的大小的两倍。

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

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

其中Path是要保存在硬盘上的文件的位置和名称,ResourceName是您在项目窗口中看到的嵌入资源的名称(减去任何扩展名),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

使用此方法,ResourceName必须包含文件扩展名AND项目名称,因此使用上面的示例我们可以这样做:

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会使我的编译程序膨胀到其大小的两倍,我会非常感激。

2 个答案:

答案 0 :(得分:9)

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

至少这是thread above的结论。

<强>引用

您转到项目属性的“资源”页面并在那里添加了文件,对吧?然后,您进入解决方案资源管理器并将文件的构建操作更改为嵌入式资源,对吧?这就是你将文件大小加倍的原因:你要两次添加每个文件。

添加资源有两种不同的方法:在项目属性的“资源”页面和“解决方案资源管理器”中。你不是两个都做。如果要使用GetManifestResourcestream,则不要使用“资源”页面。您可以手动将解压缩资源管理器中的文件添加到项目中,然后将“构建操作”设置为“嵌入资源”。

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

  1. 将文件添加到项目属性的“资源”页面,然后通过My.Resources访问它。这将自动将文件添加到解决方案资源管理器中的项目中,但构建操作将为“无”,应该保留该方式。

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

答案 1 :(得分:0)

对于任何想要使用此代码的人来说,只是一个更新。由于字节数组从零开始声明,因此该代码实际上向该文件写入了一个额外的字节。

要获取原始文件的准确副本,请将代码更改为:

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