GetManifestResourceStream mengembalikan NULL


105

Ini adalah aplikasi C # .NET 4.0:

Saya menyematkan file teks sebagai sumber daya dan kemudian mencoba menampilkannya di kotak dialog:

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

Solusinya adalah MyProjSolution dan yang dapat dieksekusi adalah MyProj.exe. Help.txt adalah sumber daya yang disematkan. Namun, alirannya null. Saya sudah mencoba MyProjSolution.Help.txt dan MyProjSolution.MyProj.Help.txt tetapi tidak ada yang berhasil.


1
Gunakan ildasm.exe untuk melihat nama .mresource di manifes rakitan. Hindari jatuh ke dalam lubang kesengsaraan ini, gunakan Project + Properties, tab Resource sebagai gantinya. Jadi Anda bisa menggunakan Properties.Resources.Help di kode sumber Anda.
Hans Passant

Jawaban:


189

Anda dapat memeriksa bahwa sumber daya disematkan dengan benar menggunakan

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

saat debugging. Ini akan mencantumkan semua (nama yang memenuhi syarat) dari semua sumber daya yang tertanam dalam rakitan tempat kode Anda ditulis.

Lihat Assembly.GetManifestResourceNames () di MSDN.

Cukup salin nama yang relevan, dan gunakan itu alih-alih apa pun yang telah Anda tetapkan dalam variabel 'resourceName'.

Catatan - nama sumber daya peka huruf besar / kecil, dan jika Anda salah menyematkan file sumber daya, itu tidak akan muncul dalam daftar yang dikembalikan oleh panggilan ke GetManifestResourceNames (). Juga - pastikan Anda membaca sumber daya dari rakitan yang benar (jika beberapa rakitan digunakan) - terlalu mudah untuk mendapatkan sumber daya dari rakitan yang sedang dieksekusi daripada dari rakitan yang direferensikan.

EDIT - .NET Core
Silakan lihat posting SO ini untuk detail tentang cara menanamkan menggunakan .NET Core.

Pengambilan info manifes terlihat serupa - cukup gunakan this.GetType().GetTypeInfo().Assembly.GetManifestResourceNames()untuk mendapatkan manifes dari rakitan tempat kode dijalankan.

Saya belum menemukan cara untuk melakukan hal yang setara Assembly.GetExecutingAssembly()dengan .NET Core! jika ada yang tahu - tolong beri tahu saya dan saya akan memperbarui jawaban ini.


5
Itu berhasil. ProjectName.Resources.Help.txt adalah nama resource yang disematkan.
Ron

2
Saya senang bisa membantu! Jika Anda merasa posting ini telah menjawab pertanyaan Anda, maka jangan lupa untuk menandai ini sebagai jawaban yang diterima.
Jay

1
Ya, jadi di .Net Standard seharusnya [ProjectName]. [Namespace]. [Resource]. Saya kehilangan nama proyek. Terima kasih!
Billy Jake O'Connor

Masalah saya adalah menggunakan GetExecutingAssembly () dan bukan GetEntryAssembly (). Sumber daya yang saya inginkan ada di dapat dieksekusi, tetapi fungsi untuk memuat sumber daya ada di proyek lain yang direferensikan dalam solusi yang sama.
lettucemode

63

Saya memiliki masalah serupa, periksa terlebih dahulu apakah file tersebut disertakan dalam proyek Anda, lalu buka properti dan setel tindakan pembuatan file tersebut ke Sumber Daya Tertanam. ini berhasil untuk saya.


Ini membantu saya! Saya memiliki beberapa file yang ditambahkan sebelumnya yang default ke sumber daya yang disematkan, kemudian yang saya tambahkan nanti yang disetel ke "Tidak Ada". Visual Studio terkadang sangat mengganggu. Bagian terburuknya adalah bahwa semua file XML untuk sumber daya TIDAK memiliki setelan untuk tindakan build. Seharusnya tindakan membangun ditetapkan di sana.
John Suit

1
Ingatlah untuk menggunakan namespace default dan jalur ke sumber daya. mis DefatultNameSpace.Infrastructure.Help.txt. Namespace default di halaman properti proyek Anda dan Infrastructureakan menjadi folder tempat Anda berada
jabu.hlong

Inilah yang saya inginkan Cheers!
kucing

19

Properti "Build Action" file yang disematkan harus disetel sebagai "Sumber Daya yang Tersemat" untuk menjalankan baris, yang diberikan di bawah ini, dengan benar:

Stream stream = assembly.GetManifestResourceStream(resourceName)

Klik kanan pada file, klik properti, lalu setel properti "Build Action" sebagai "Sumber Daya Tersemat":

masukkan deskripsi gambar di sini


Persisnya apa masalah saya. Terima kasih!
Riki

1
Ini adalah masalahku. Saya menambahkannya menggunakan Resources.resx dan tidak berhasil.
Hélder Lima

11

Inilah penyebab nilai null saya.

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

The GetManifestResourceStreamMetode akan selalu kembali NULLjika properti sumber daya 'dibangun tindakan' tidak diatur ke 'sumber daya tertanam'

Setelah menyetel properti ini dengan semua file yang diperlukan assembly.GetManifestResourceStreammulai mengembalikan aliran yang benar, bukan NULL.


1
Terima kasih lagi. Ini memperbaiki masalah saya satu atau dua bulan yang lalu lalu saya lupa tentangnya dan memiliki masalah yang sama dan memperbaikinya lagi.
Kaya

8

Hanya peringatan.

Saya tidak dapat mengakses file saya sebagai sumber daya yang disematkan meskipun saya menetapkannya dan meskipun file tersebut memiliki properti Build Action. Membuang banyak waktu untuk membenturkan kepalaku. Saya menyematkan file kode csharp dengan .txt ditambahkan ke namanya (xxx.cs.txt). Untuk beberapa alasan, metode GetManifestResourceNames () dan GetManifestResourceStream () tidak akan melihat file dengan nama .cs.

Saya mengganti namanya menjadi xxx.txt dan semuanya baik-baik saja.

Aneh.


1
Ini telah menghabiskan terlalu banyak waktu hari ini! Ini akan menyematkannya jika Anda menggunakan Resourcetetapi tidak Embedded Resource, yang membuatnya semakin aneh ... Menghapus .cs.dari namanya membuatnya berfungsi. Argh.
Matt

Masalahnya bukan itu .cs. jalur / segmen dalam file dikenali sebagai file C # melainkan sebagai CultureInfo.
frontlinebg

2
Tampaknya dengan ekstensi ganda itu tidak berfungsi sama sekali.
Darion Badlydone

3

Saya memiliki masalah yang sama, berkat Jay, saya menemukan itu adalah tanda hubung di nama direktori.

ProjectName.ResourceFolder.Sub-Directorymenjadi ProjectName.ResourceFolder.Sub_Directorysaat Anda mereferensikan aliran sumber daya.


2

Dalam kasus saya, masalahnya adalah bahwa kode yang mencari sumber daya berada di proyek yang berbeda dari sumber daya itu sendiri.

Anda hanya dapat mengakses sumber daya dalam proyek yang sama dengan kodenya. Saya pikir saya bisa menempatkan semua sumber daya saya di proyek halaman web, tetapi saya membutuhkan gambar di proyek surat juga.

Semoga ini membantu seseorang dalam situasi yang sama dengan saya.

Saya menemukan panggilan yang sangat berguna Assembly.GetExecutingAssembly().GetManifestResourceNames();.


Ini tidak benar, setidaknya sejak 2011: melalui Assembly.LoadFrom () dan typeof Anda dapat mengakses sumber daya yang ada di proyek lain
Marcelo Scofano

1

Jika membantu orang lain, Pastikan Assembly.GetExecutingAssembly()baris dipanggil dari rakitan yang sama yang memiliki sumber daya tertanam.


Kecuali jika Anda memanggilnya dari proyek lain, dan dalam hal ini Anda harus menggunakan Assembly.LoadFrom () atau typeof sehingga Anda dapat mengakses sumber daya yang ada di proyek lain ...
Marcelo Scofano

1

Solusi sederhana dan efisien adalah memiliki kelas dasar ini :

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

Kemudian, saat Anda menambahkan sumber daya, Anda membuat kelas C # pembaca di folder yang sama:

masukkan deskripsi gambar di sini

di mana kelas pembaca MyResource.cs sangat sederhana:

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

Jadi, setiap sumber daya akan memiliki kelas "bayangan" yang tahu cara membacanya dengan benar.

Ini adalah cara Anda membaca sumber daya di kode Anda:

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

Dan seperti jawaban lain yang disarankan, jangan lupa untuk menyetel "Sumber Daya Tersemat" di properti Tindakan Bangun dari file sumber daya.

Keuntungan dari solusi seragam ini adalah

  1. tidak terlalu repot menemukan nama lengkap sumber daya yang benar, terutama bila ditempatkan di folder bertingkat
  2. jika folder diubah namanya ATAU Namespace Default dalam pengaturan proyek diubah, kode TIDAK akan rusak

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

Anda perlu membongkar solusi Anda, kemudian mengedit proyek. Setelah menemukan folder Anda dan ubah seperti ini:

<EmbeddedResource Include="yourpath" />

0

Meskipun OP mendapat GetManifestResourceStream mengembalikan NULL dari sumber daya dalam Majelis yang sama, beberapa Answers menyarankan bahwa ketika Sumber daya berada di Proyek atau Majelis lain, mereka tidak dapat diambil, dan merupakan penyebab wajar GetManifestResourceStream mengembalikan NULL.

Ini tidak benar, setidaknya sejak 2011; seperti yang saya tunjukkan di beberapa komentar di tempat lain, Assembly.LoadFrom () atau typeof melakukan trik dan sebagai hasilnya Anda dapat mengakses sumber daya yang ada di proyek lain.

Saya memiliki contoh yang cukup rumit untuk diilustrasikan; ini adalah pengaturan pengujian saya:

masukkan deskripsi gambar di sini

Jalur ke proyek lain:

masukkan deskripsi gambar di sini

Diambil di sini:

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

Dan pada Form1.cs dari WinFormFramework saya tentukan dengan

Namespace.Folder.Resource

seperti itu:

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

Dan hasilnya ditampilkan di textbox: masukkan deskripsi gambar di sini

Saya menghabiskan beberapa jam untuk melakukannya dengan benar; untuk itu, saya harus banyak menggunakan ini di Immediate Window:

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

Semoga bisa membantu seseorang


-2

Anda mungkin perlu menentukan jalur ke file txt Anda di GetManifestResourceStreamparameter, atau Anda dapat mencoba menempelkan file txt di direktori yang sama dengan file yang dapat dieksekusi. Semoga membantu!

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.