GetManifestResourceStream返回NULL

时间:2014-02-07 21:11:44

标签: c# embedded-resource

这是一个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,但似乎没有任何效果。

13 个答案:

答案 0 :(得分:141)

您可以使用

检查资源是否已正确嵌入
//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核心
有关如何使用.NET Core嵌入的详细信息,请参阅此SO post

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

我还没想出如何在.NET Core中完成等效的Assembly.GetExecutingAssembly()!如果有人知道 - 请告诉我,我会更新这个答案。

答案 1 :(得分:49)

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

答案 2 :(得分:8)

这是我的空值的原因。

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

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

使用所有需要的文件设置此属性后.GetManifestResourceStream开始返回corrent流而不是NULL

答案 3 :(得分:6)

只是一个警告。

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

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

怪异。

答案 4 :(得分:2)

嵌入文件的“构建操作” 属性应设置为“嵌入资源” ,以正确运行该行,如下所示:

Stream stream = assembly.GetManifestResourceStream(resourceName)

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

Google results

答案 5 :(得分:1)

我遇到了同样的问题,多亏了周杰伦,我发现它在目录名称中是连字符。

ProjectName.ResourceFolder.Sub-Directory在您引用资源流时变为ProjectName.ResourceFolder.Sub_Directory

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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

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#类:

enter image description here

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

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

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

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

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

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

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

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

答案 8 :(得分:0)

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

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

希望这可以帮助处于相同情况的人。

我觉得调用Assembly.GetExecutingAssembly().GetManifestResourceNames();非常有用。

答案 9 :(得分: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>

答案 10 :(得分:0)

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

<EmbeddedResource Include="yourpath" />

答案 11 :(得分:0)

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

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

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

enter image description here

另一个项目的路径:

enter image description here

在这里捕获:

 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上,我用

指定

Namespace.Folder.Resource

那样:

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

,结果显示在文本框中: enter image description here

我花了几个小时把它弄对了;为此,我不得不在“即时窗口”中使用很多这些东西:

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

希望它对某人有帮助

答案 12 :(得分:-2)

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