GetManifestResourceStream trả về NULL


105

Đây là ứng dụng C # .NET 4.0:

Tôi đang nhúng một tệp văn bản làm tài nguyên và sau đó cố gắng hiển thị nó trong một hộp thoại:

    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);
            }
        }

Giải pháp là MyProjSolution và tệp thực thi là MyProj.exe. Help.txt là một tài nguyên được nhúng. Tuy nhiên, luồng không có giá trị. Tôi đã thử MyProjSolution.Help.txt và MyProjSolution.MyProj.Help.txt nhưng dường như không có gì hoạt động.


1
Sử dụng ildasm.exe để xem tên .mresource trong tệp kê khai hợp ngữ. Để tránh rơi vào hố khổ này, hãy sử dụng tab Project + Properties, Resource để thay thế. Vì vậy, bạn chỉ có thể sử dụng Properties.Resources.Help trong mã nguồn của mình.
Hans Passant

Câu trả lời:


189

Bạn có thể kiểm tra xem các tài nguyên có được nhúng chính xác hay không bằng cách sử dụng

//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()

khi gỡ lỗi. Điều này sẽ liệt kê tất cả (tên đủ điều kiện) của tất cả các tài nguyên được nhúng trong assembly mà mã của bạn được viết trong đó.

Xem Assembly.GetManifestResourceNames () trên MSDN.

Chỉ cần sao chép tên có liên quan và sử dụng tên đó thay vì bất kỳ tên nào bạn đã xác định trong biến 'resourceName'.

Lưu ý - tên tài nguyên có phân biệt chữ hoa chữ thường và nếu bạn nhúng tệp tài nguyên không chính xác, nó sẽ không hiển thị trong danh sách được trả về bởi lệnh gọi GetManifestResourceNames (). Ngoài ra - hãy đảm bảo rằng bạn đang đọc tài nguyên từ đúng assembly (nếu sử dụng nhiều assembly) - quá dễ dàng để lấy tài nguyên từ assembly đang thực thi hơn là từ một assembly được tham chiếu.

EDIT - .NET Core
Vui lòng xem bài đăng SO này để biết chi tiết về cách nhúng bằng .NET Core.

Việc truy xuất thông tin tệp kê khai có vẻ tương tự - chỉ cần sử dụng this.GetType().GetTypeInfo().Assembly.GetManifestResourceNames()để lấy tệp kê khai từ hợp ngữ nơi mã đang thực thi.

Tôi vẫn chưa tìm ra cách làm tương tự như Assembly.GetExecutingAssembly()trong .NET Core! nếu ai biết - xin vui lòng cho tôi biết và tôi sẽ cập nhật câu trả lời này.


5
Điều đó đã hiệu quả. ProjectName.Resources.Help.txt là tên tài nguyên được nhúng.
Ron

2
Tôi rất vui vì đã giúp đỡ! Nếu bạn cảm thấy rằng bài đăng này đã trả lời câu hỏi của bạn, thì xin đừng quên đánh dấu đây là câu trả lời được chấp nhận.
Jay

1
Vâng, vì vậy trong .Net Standard, nó phải là [Tên dự án]. [Không gian tên]. [Tài nguyên]. Tôi thiếu tên dự án. Cảm ơn!
Billy Jake O'Connor

Sự cố của tôi là sử dụng GetExecutingAssembly () thay vì GetEntryAssembly (). Tài nguyên tôi muốn nằm trong tệp thực thi, nhưng chức năng tải tài nguyên nằm trong một dự án khác, được tham chiếu trong cùng một giải pháp.
xà lách,

63

Trước tiên, tôi đã gặp sự cố tương tự, kiểm tra xem tệp có được bao gồm trong dự án của bạn không, sau đó chuyển đến thuộc tính và đặt hành động xây dựng của tệp đó thành Tài nguyên được nhúng. điều này đã làm việc cho tôi.


Điều này đã giúp tôi! Tôi đã thêm một số tệp trước đó được đặt mặc định là tài nguyên nhúng, sau đó những tệp tôi thêm sau đó được đặt thành "Không có". Visual Studio đôi khi rất khó chịu. Phần tồi tệ nhất của điều này là tất cả các tệp XML cho tài nguyên KHÔNG có cài đặt cho hành động xây dựng. Nên đặt hành động xây dựng ở đó.
John Suit

1
Hãy nhớ sử dụng không gian tên mặc định và đường dẫn đến tài nguyên. vd DefatultNameSpace.Infrastructure.Help.txt. Namespace mặc định trong trang thuộc tính dự án của bạn và Infrastructuresẽ là thư mục mà bạn tập tin là trong
jabu.hlong

Đây là những gì tôi muốn Cheers!
tabby

19

Thuộc tính "Hành động xây dựng" của tệp nhúng phải được đặt thành "Tài nguyên được nhúng" để chạy dòng, được cung cấp bên dưới, đúng cách:

Stream stream = assembly.GetManifestResourceStream(resourceName)

Nhấp chuột phải vào tệp, nhấp vào thuộc tính và sau đó đặt thuộc tính "Hành động xây dựng" thành "Tài nguyên được nhúng":

nhập mô tả hình ảnh ở đây


Chính xác vấn đề của tôi là gì. Cảm ơn!
Riki

1
Đây là vấn đề của tôi. Tôi đã thêm nó bằng cách sử dụng Resources.resx và nó không hoạt động.
Hélder Lima

11

Đây là nguyên nhân của giá trị null của tôi.

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

Các GetManifestResourceStreamphương pháp sẽ luôn luôn trở lại NULLnếu tài sản tài nguyên 'xây dựng hành động' không được thiết lập để 'tài nguyên nhúng'

Sau khi thiết lập thuộc tính này với tất cả các tệp cần thiết, assembly.GetManifestResourceStreambắt đầu trả về luồng chính xác thay vì NULL.


1
Cảm ơn một lần nữa. Điều này đã khắc phục sự cố của tôi một hoặc hai tháng trước, sau đó tôi quên nó và gặp sự cố tương tự và nó đã sửa lại.
Giàu

8

Chỉ là một cảnh báo.

Tôi không thể truy cập tệp của mình dưới dạng tài nguyên nhúng mặc dù tôi đã chỉ định rằng đó là tài nguyên và mặc dù nó có thuộc tính Build Action. Lãng phí rất nhiều thời gian đập đầu của tôi. Tôi đã nhúng một tệp mã csharp với .txt được thêm vào tên của nó (xxx.cs.txt). Vì một số lý do, các phương thức GetManifestResourceNames () và GetManifestResourceStream () sẽ không thấy tệp có .cs trong tên của nó.

Tôi đã đổi tên nó chỉ đơn giản là xxx.txt và mọi thứ đều ổn.

Kỳ dị.


1
Điều này đã làm mất quá nhiều thời gian ngày hôm nay! Nó sẽ nhúng nó nếu bạn sử dụng Resourcenhưng không Embedded Resource, điều này làm cho nó thậm chí còn kỳ lạ hơn ... Xóa .cs.khỏi tên sẽ làm cho nó hoạt động. Argh.
Matt

Vấn đề không phải là .cs. đường dẫn / phân đoạn trong tệp được nhận dạng là tệp C # nhưng là một CultureInfo.
frontlinebg

2
Có vẻ như với phần mở rộng gấp đôi thì nó không hoạt động chút nào.
Darion Badlydone

3

Tôi đã gặp vấn đề tương tự, nhờ Jay tôi tìm thấy nó là dấu gạch nối trong tên thư mục.

ProjectName.ResourceFolder.Sub-Directorytrở thành ProjectName.ResourceFolder.Sub_Directorykhi bạn tham chiếu đến dòng tài nguyên.


2

Trong trường hợp của tôi, vấn đề là mã tìm kiếm tài nguyên nằm trong một dự án khác với chính tài nguyên đó.

Bạn chỉ có thể truy cập các tài nguyên nằm trong cùng một dự án có mã. Tôi nghĩ rằng tôi có thể đặt tất cả tài nguyên của mình vào dự án trang web, nhưng tôi cũng cần hình ảnh trong dự án thư.

Hy vọng điều này sẽ giúp một ai đó trong hoàn cảnh giống tôi.

Tôi thấy cách gọi thực sự hữu ích Assembly.GetExecutingAssembly().GetManifestResourceNames();.


Điều này không đúng, ít nhất là kể từ năm 2011: thông qua cả Assembly.LoadFrom ()typeof, bạn có thể truy cập các tài nguyên nằm trong một dự án khác
Marcelo Scofano

1

Trong trường hợp nó giúp ích cho bất kỳ ai khác, hãy đảm bảo rằng Assembly.GetExecutingAssembly()dòng được gọi từ cùng một tổ hợp có tài nguyên nhúng.


Ngoại trừ trường hợp bạn gọi nó từ một dự án khác và trong trường hợp này, bạn nên sử dụng Assembly.LoadFrom () hoặc typeof để bạn có thể truy cập các tài nguyên nằm trong một dự án khác ...
Marcelo Scofano

1

Một giải pháp đơn giản và hợp lý là có lớp cơ sở này :

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();
        }
    }
}

Sau đó, khi bạn thêm một tài nguyên, bạn tạo một lớp đọc C # trong cùng một thư mục:

nhập mô tả hình ảnh ở đây

trong đó lớp người đọc MyResource.cs rất đơn giản:

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

Vì vậy, mỗi tài nguyên sẽ có một lớp "bóng" biết cách đọc nó đúng cách.

Đây là cách bạn đọc tài nguyên trong mã của mình:

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

Và như các câu trả lời khác được đề xuất, đừng quên đặt "Tài nguyên nhúng" trong thuộc tính Hành động xây dựng của tệp tài nguyên.

Ưu điểm của giải pháp đồng nhất này là

  1. ít rắc rối hơn với việc tìm tên đầy đủ chính xác của tài nguyên, đặc biệt khi được đặt trong các thư mục lồng nhau
  2. trong trường hợp khi thư mục được đổi tên HOẶC Không gian tên mặc định trong cài đặt dự án bị thay đổi, mã sẽ KHÔNG bị hỏng

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

Bạn cần dỡ bỏ giải pháp của mình, sau đó chỉnh sửa dự án. Sau đó tìm kiếm thư mục của bạn và thay đổi như sau:

<EmbeddedResource Include="yourpath" />

0

Mặc dù OP đã nhận GetManifestResourceStream trả về NULL từ các tài nguyên trong cùng một Assembly, một số Câu trả lời gợi ý rằng khi Tài nguyên nằm trong một Dự án hoặc Assembly khác, chúng không thể được truy xuất và là nguyên nhân hợp lý khiến GetManifestResourceStream trả về NULL.

Điều này không đúng, ít nhất là kể từ năm 2011; như tôi đã chỉ ra trong một số nhận xét ở nơi khác, Assembly.LoadFrom () hoặc typeof thực hiện thủ thuật và kết quả là bạn có thể truy cập các tài nguyên nằm trong một dự án khác.

Tôi có một ví dụ vừa phải phức tạp ở đây để minh họa; đây là thiết lập thử nghiệm của tôi:

nhập mô tả hình ảnh ở đây

Đường dẫn đến một dự án khác:

nhập mô tả hình ảnh ở đây

Chụp ở đây:

 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";

Và trên Form1.cs từ WinFormFramework, tôi chỉ định với

Namespace.Folder.Resource

như thế:

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

Và kết quả hiển thị tại textbox: nhập mô tả hình ảnh ở đây

Tôi đã dành vài giờ để làm đúng; vì điều đó, tôi đã phải sử dụng rất nhiều những thứ này tại Cửa sổ ngay lập tức:

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

Hy vọng nó sẽ giúp ai đó


-2

Bạn có thể cần chỉ định đường dẫn đến tệp txt của mình trong GetManifestResourceStreamtham số hoặc bạn có thể thử gắn tệp txt vào cùng thư mục với tệp thực thi của bạn. Hy vọng rằng sẽ giúp!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.