GetManifestResourceStream返回NULL


105

这是一个C#.NET 4.0应用程序:

我将文本文件嵌入为资源,然后尝试在对话框中显示它:

    var assembly = Assembly.GetExecutingAssembly();
    var resourceName = "MyProj.Help.txt";

        using (Stream stream = assembly.GetManifestResourceStream(resourceName))
        {
            using (StreamReader reader = new StreamReader(stream))
            {
                string result = reader.ReadToEnd();
                System.Windows.Forms.MessageBox.Show(result, "MyProj", MessageBoxButtons.OK);
            }
        }

解决方案是MyProjSolution,可执行文件是MyProj.exe。Help.txt是嵌入式资源。但是,流为空。我已经尝试过MyProjSolution.Help.txt和MyProjSolution.MyProj.Help.txt,但似乎没有任何效果。


1
使用ildasm.exe查看程序集清单中的.mresource名称。要避免陷入这种痛苦之中,请改用“项目+属性”,“资源”选项卡。因此,您只需在源代码中使用Properties.Resources.Help。
Hans Passant 2014年

Answers:


189

您可以使用以下方法检查资源是否正确嵌入

//From the assembly where this code lives!
this.GetType().Assembly.GetManifestResourceNames()

//or from the entry point to the application - there is a difference!
Assembly.GetExecutingAssembly().GetManifestResourceNames()

调试时。这将列出嵌入代码的程序集中嵌入的所有资源的所有(完全限定名称)。

请参阅MSDN上的Assembly.GetManifestResourceNames()

只需复制相关名称,然后使用该名称代替您在变量“ resourceName”中定义的名称。

注意-资源名称区分大小写,并且如果您错误地嵌入了资源文件,则该资源文件将不会出现在对GetManifestResourceNames()的调用返回的列表中。另外-确保您正在从正确的程序集中读取资源(如果使用了多个程序集)-从当前正在执行的程序集而不是从引用的程序集获取资源太容易了。

编辑-.NET Core有关如何使用.NET Core进行嵌入的详细信息,
请参见此SO帖子

检索清单信息看起来很相似-仅用于this.GetType().GetTypeInfo().Assembly.GetManifestResourceNames()从执行代码的程序集中获取清单。

我还没有想出如何Assembly.GetExecutingAssembly()在.NET Core中实现等效功能 !如果有人知道-请让我知道,我将更新此答案。


5
那行得通。ProjectName.Resources.Help.txt是嵌入式资源名称。
罗恩2014年

2
我很高兴为您提供帮助!如果您认为此帖子已经回答了您的问题,那么请不要忘记将其标记为已接受的答案。
周杰伦

1
是的,因此在.Net Standard中,它应该是[ProjectName]。[Namespace]。[Resource]。我缺少项目名称。谢谢!
比利·杰克·奥康纳

我的问题是使用GetExecutingAssembly()而不是GetEntryAssembly()。我想要的资源在可执行文件中,但是用于加载资源的功能却存在于同一解决方案中的另一个引用项目中。
lettucemode

63

我有一个类似的问题检查,首先检查文件是否包含在您的项目中,然后转到属性并将该文件的生成操作设置为Embedded Resource。这对我有用。


这对我有帮助!我之前添加了一些文件,这些文件默认为嵌入式资源,后来我添加的文件被设置为“无”。Visual Studio有时很烦人。最糟糕的是,所有用于资源的XML文件都没有针对构建操作的设置。应该在那里设置构建动作。
John Suit

1
请记住使用默认的名称空间和资源路径。例如DefatultNameSpace.Infrastructure.Help.txt。项目属性页面中的默认名称空间,Infrastructure将是您文件所在的文件夹
jabu.hlong

这就是我想要的干杯!
平纹

18

嵌入式文件的“ Build Action”属性应设置为“ Embedded Resource”才能正确运行该行,如下所示:

Stream stream = assembly.GetManifestResourceStream(resourceName)

右键单击该文件,单击属性,然后将“构建操作”属性设置为“嵌入资源”:

在此处输入图片说明


正是我的问题。谢谢!

1
这是我的问题。我使用Resources.resx添加了它,但是没有用。
赫尔德利马

11

这是我的空值的原因。

http://adrianmejia.com/blog/2011/07/18/cs-getmanifestresourcestream-gotcha/

如果资源的“已构建操作”属性未设置为“嵌入式资源”,则该GetManifestResourceStream方法将始终返回NULL

在为所有需要的文件设置此属性后,assembly.GetManifestResourceStream开始返回正确的流而不是NULL


1
再次感谢。这在一两个月前解决了我的问题,然后我忘记了它,遇到了同样的问题,然后又修复了它。
丰富

8

只是警告。

即使指定了文件并且具有Build Action属性,我也无法将文件作为嵌入式资源访问。浪费了很多时间来敲我的头。我嵌入了一个csharp代码文件,并在文件名(xxx.cs.txt)后面附加了.txt。由于某种原因,GetManifestResourceNames()和GetManifestResourceStream()方法将看不到名称中带有.cs的文件。

我只是将其重命名为xxx.txt,一切都很好。

奇怪的。


1
今天已经浪费了太多时间!这将嵌入它,如果你使用Resource,但不是Embedded Resource,这使得它更加古怪...删除.cs.从名字上也可以正常工作。啊
马特

问题不是那个.cs。文件中的路径/段被识别为C#文件,而不是CultureInfo。
frontlinebg 2016年

2
似乎使用双扩展名根本不起作用。
Darion Badlydone '16

3

我遇到了同样的问题,这要归功于Jay,我发现它在目录名中是连字符。

ProjectName.ResourceFolder.Sub-DirectoryProjectName.ResourceFolder.Sub_Directory当您引用资源流时变为。


2

在我的情况下,问题是寻找资源的代码与资源本身在不同的项目中。

您只能访问代码所在的同一项目中的资源。我以为我可以将所有资源都放在网页项目中,但是我也需要在邮件项目中添加图像。

希望这可以帮助与我一样的人。

我觉得打电话真的很有用Assembly.GetExecutingAssembly().GetManifestResourceNames();


至少自2011年以来,情况并非如此:至少通过Assembly.LoadFrom()typeof都可以访问另一个项目中的资源
Marcelo Scofano

1

如果它对其他人有帮助,请确保Assembly.GetExecutingAssembly()从具有嵌入式资源的同一程序集中调用该行。


除非您从另一个项目中调用它,否则在这种情况下,您应该使用Assembly.LoadFrom()typeof,以便可以访问另一个项目中的资源...
Marcelo Scofano

1

一个简单且简化的解决方案是拥有以下类:

public class EmbededResourceReader
{
    protected string LoadString(string fileName)
    {
        return LoadString(fileName, Encoding.UTF8);
    }

    protected string LoadString(string fileName, Encoding encoding)
    {
        var assembly = this.GetType().Assembly;
        var resourceStream = assembly.GetManifestResourceStream($"{this.GetType().Namespace}.{fileName}");
        using (var reader = new StreamReader(resourceStream, encoding))
        {
            return reader.ReadToEnd();
        }
    }
}

然后,当您添加资源时,您将在同一文件夹中创建一个阅读器C#类:

在此处输入图片说明

阅读器类MyResource.cs非常简单:

public class MyResource : EmbededResourceReader
{
    public string LoadString() => LoadString($"{nameof(MyResource)}.txt");
}

因此,每个资源都有一个“影子”类,该类知道如何正确读取它。

这是您在代码中读取资源的方式:

var text = new MyResource().LoadString();

如建议的其他答案一样,请不要忘记在资源文件的“构建操作”属性中设置“嵌入资源”。

这种统一解决方案的优点是

  1. 查找正确的资源全名的麻烦更少,尤其是当放置在嵌套文件夹中时
  2. 如果文件夹被重命名或项目设置中的默认命名空间被更改,则代码不会中断

0
    First Unload the project and click on edit the project file. 

    Inside the project file make sure that the item you are fetching from the assembly is included inside <EmbeddedResource> tag.

    Eg: 

         <ItemGroup>
          <EmbeddedResource Include="Template\ForExampleFile.html" />
         </ItemGroup>


    The files I added into the project were just in Content tag but not in the EmbeddedResource as shown below by default. Hence the stream was returning null.
    <ItemGroup>
        <Content Include="Template\ForExampleFile.html" />
  </ItemGroup>

0

您需要卸载解决方案,然后编辑项目。找到文件夹并进行如下更改:

<EmbeddedResource Include="yourpath" />

0

尽管OP使GetManifestResourceStream从同一程序集中的资源返回NULL,但一些答案表明,当Resources位于另一个项目或程序集中时,它们将无法检索,这是GetManifestResourceStream返回NULL的合理原因。

至少自2011年以来,情况并非如此。正如我在其他评论中指出的那样,Assembly.LoadFrom()typeof可以解决问题,因此您可以访问另一个项目中的资源。

我这里有一个比较复杂的例子来说明;这是我的测试设置:

在此处输入图片说明

另一个项目的路径:

在此处输入图片说明

在这里捕获:

 var sharedXMLResource =
                "D:\\My Documents\\Consultório Impressos\\DB Pacientes\\Teste\\TestesVariados\\WinFormFramework\\Read_Embedded_XML_File_CS\\bin\\Debug\\Read_Embedded_XML_File_CS.exe";

在WinFormFramework的Form1.cs上,我用

命名空间。文件夹。资源

像那样:

StreamReader reader = 
                new StreamReader(Assembly.LoadFrom(sharedXMLResource).GetManifestResourceStream("Read_Embedded_XML_File_CS.SharedResources.ContactList.xml") ?? throw new InvalidOperationException());

结果显示在文本框中: 在此处输入图片说明

我花了几个小时才把它弄好。为此,我不得不在“即时窗口”中大量使用这些:

Environment.CurrentDirectory
AppDomain.CurrentDomain.BaseDirectory
System.Reflection.Assembly.GetExecutingAssembly().Location
System.Reflection.Assembly.GetAssembly(typeof(WinFormFramework.Program)).Location

希望对别人有帮助


-2

您可能需要在GetManifestResourceStream参数中指定txt文件的路径,或者可以尝试将txt文件粘贴到与可执行文件相同的目录中。希望有帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.