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
}
在 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
}