Visual Studio中的嵌入式文件资源是否可以通过代码中的名称引用?

时间:2015-03-20 17:42:41

标签: c# visual-studio-2010 embedded-resource

在Visual Studio 2010中,我将一个zip文件作为嵌入式资源包含在我的可执行文件中并将其解压缩以便在运行时使用。这样的文件不能作为文件资源(文本或二进制文件)包含在内,因为文件资源总是作为单独的项链接,这不是我想要的。因此,我无法通过Properties.Resources在我的代码中引用该文件。

要提取zip文件,我必须在我的代码中对其名称进行硬编码,如下所示:

stream = Assembly.GetEntryAssembly().GetManifestResourceStream("myembeddedfile.zip");

我注意到.csproj文件中引用了zip文件,如下所示:

<ItemGroup>
    <EmbeddedResource Include="myembeddedfile.zip" />
    <None Include="packages.config" />
</ItemGroup>

但是,我不认为以上内容可以从代码中引用。 (我知道来自SO question #1060870None用法。)

有什么方法可以将此文件作为真实项目/解决方案项目包含在内并防止对文件名进行硬编码?

修改

在代码中引用文件的非硬编码方式如下:

GetManifestResourceStream(Properties.Resources.EmbeddedFile);

但正如我所提到的,上述情况是不可能的,因为Properties.Resources对象中不包含嵌入式资源。

DRapp后续编辑对其接受的答案编辑:

以下DRapp的枚举方案是这个问题的最终解决方案,只需进行一项修改:当嵌入多个资源文件时,资源文件名将按字母顺序由GetManifestResourceNames()返回。因此,必须相应地安排enum名称。在调试期间拍摄以下快照之前,按以下顺序手动添加了三个嵌入文件:1_FIRST, 3_THIRD, 2_SECOND,但可以观察到,内部存储按字母顺序排列:

对于包含三个文件的上述示例,相应的enum将定义为:

public enum MyResources
{
    EmptyZipTest_1_FIRST_zip,
    EmptyZipTest_2_SECOND_zip,
    EmptyZipTest_3_THIRD_zip
}

1 个答案:

答案 0 :(得分:1)

With binary write stream credit from Jon Skeet's answer用于CopyStream函数并调用它...你可以嵌入一个zip文件。

另外,正如hintham所说,你需要做什么(我做过和测试过),我创建了一个空的zip文件并将其添加到我的项目中。我叫它#34; EmptyZipFile.zip&#34;。在此文件中,对于属性,单击&#34;构建操作&#34;并更改为&#34; Embedded Resource&#34;。我的项目(和命名空间)的名称是&#34; EmptyZipTest&#34;

您非常接近获取资源,但必须包含完全限定的命名空间PLUS文件名,因为它是嵌入的。要查看资源中所有内容的快速列表..

StringBuilder sb = new StringBuilder();
foreach (string s in Assembly.GetEntryAssembly().GetManifestResourceNames())
   sb.AppendLine(s);

MessageBox.Show(sb.ToString());

通过这样做,它会暴露(根据我的示例项目)

的资源
"EmptyZipTest.EmptyZipFile.zip"

这是您的可执行文件中的文件。现在,如果要将此基线zip文件OUT复制到某个新文件名,请创建一个可以获取另一个文件名/位置的简单函数,并提供该函数以创建该文件并将zip文件写出来。

public void WriteNewZipFile( string newFilePathAndName )
{
   Stream zipStream = Assembly.GetEntryAssembly().GetManifestResourceStream(
      "EmptyZipTest.EmptyZipFile.zip" );

   if (zipStream != null)
   {
      using (Stream outStream = File.Create( newFilePathAndName ))
      {
         CopyStream(zipStream, outStream);
      }
   }
}

public static void CopyStream(Stream input, Stream output)
{
   byte[] buffer = new byte[8 * 1024];
   int len;
   while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
   {
      output.Write(buffer, 0, len);
   }
}   

显然,我没有在这个快速位中进行错误检查/验证,但是它应该得到你所需要的。内部文件名总是一个固定的值......你写的那个流OUT是不同的......

OPTION vs Hardcoding strings。

我想我明白了你的意思,你可以试试这个......创造一个&#34; enum&#34;实例并在那里放入你的资源,但替换&#34;。&#34;为&#34; _&#34;在枚举中,因为你不能在对象名称中有句号......例如

   public enum MyResources
   {
      EmptyZipTest_EmptyZipFile_zip,
      EmptyZipTest_SomeOtherFile_jpg,
      EmptyZipTest_AnotherFile_ini
   }

然后,将枚举作为参数,您不会在整个地方意外拼错硬编码名称,但需要有一个正确的引用实例。然后,在处理流式资源获取的函数中,您可以.REPLACE()&#34; _&#34;到&#34;。&#34;比如

   public Stream GetMyResource( MyResources myRes )
   {
      string actualResource = myRes.ToString().Replace( "_", "." );
      // This would convert the sample enums above to
      // EmptyZipTest.EmptyZipFile.zip,
      // EmptyZipTest.SomeOtherFile.jpg,
      // EmptyZipTest.AnotherFile.ini
   }