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

Can an embedded file resource in Visual Studio be referenced by name in code?

在 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 #1060870 了解到 None 的用法。)

有什么方法可以将此文件作为真正的 project/solution 项目包含在内,并避免对文件名进行硬编码?

编辑:

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

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
}

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

另外,正如 hintham 提到的,您需要做什么(我做了并测试过),我创建了一个空的 zip 文件并将其添加到我的项目中。我称它为"EmptyZipFile.zip"。在此文件上,对于属性,单击 "Build Action" 并更改为 "Embedded Resource"。我的项目(和命名空间)的名称是 "EmptyZipTest"

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

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

MessageBox.Show(sb.ToString());

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

的资源
"EmptyZipTest.EmptyZipFile.zip"

这是您的可执行文件中的文件。现在,如果您想将此基线 zip 文件复制到某个新文件名,请创建一个简单的函数,该函数可能会获取另一个文件名/位置并提供它来创建文件并写出 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);
   }
}   

显然我没有在这个快速位中进行错误检查/验证,但它应该可以满足您的需求。内部文件名将始终是一个固定值...您将该流写入的内容不同...

OPTION 与硬编码字符串。

我想我明白你的意思了,你可以试试这个...创建一个 "enum" 实例并将你的资源放在那里,但替换为“。”对于枚举中的“_”,因为对象名称中不能有句点...例如

   public enum MyResources
   {
      EmptyZipTest_EmptyZipFile_zip,
      EmptyZipTest_SomeOtherFile_jpg,
      EmptyZipTest_AnotherFile_ini
   }

然后,将该枚举作为参数,您就不会不小心拼错所有地方的硬编码名称,但需要有一个正确的引用实例。然后,在处理流式资源获取的函数中,您可以将“_”替换为“。”。比如

   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
   }