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 в маніфесті збірки. Не уникайте потрапляння в цю неприємність, замість цього використовуйте вкладку Project + Properties, Resource. Таким чином, ви можете просто використовувати Properties.Resources.Help у своєму вихідному коді.
— Ганс Пасант

Відповіді:


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

при налагодженні. Тут буде перераховано всі (повністю кваліфіковані імена) усіх ресурсів, вбудованих у збірку, в яку написано ваш код.

Див. Розділ Assembly.GetManifestResourceNames () на MSDN.

Просто скопіюйте відповідне ім’я та використовуйте це замість того, що ви визначили у змінній "resourceName".

Примітки - ім'я ресурсу чутливе до регістру, і якщо ви неправильно вставили файл ресурсу, він не відображатиметься у списку, поверненому викликом GetManifestResourceNames (). Крім того, переконайтеся, що ви читаєте ресурс з правильної збірки (якщо використовується декілька збірок) - отримати надто просто з ресурсів, що виконуються в даний час, а не з посилальної збірки.

EDIT - .NET Core
Будь ласка, перегляньте цей пост, щоб дізнатися, як вбудувати за допомогою .NET Core.

Отримання інформації про маніфест схоже - просто використовуйте this.GetType().GetTypeInfo().Assembly.GetManifestResourceNames()для отримання маніфесту з збірки, де виконується код.

Я ще не придумав, як зробити еквівалент Assembly.GetExecutingAssembly()в .NET Core! якщо хтось знає - повідомте мене, і я оновлю цю відповідь.


5
Це спрацювало. ProjectName.Resources.Help.txt було вбудованою назвою ресурсу.
— Рон

2
Я радий, що допомогли! Якщо ви вважаєте, що ця публікація відповіла на ваше запитання, то не забудьте позначити це як прийняту відповідь.
— Джей

1
Так, так у .Net Standard це повинно бути [ProjectName]. [Простір імен]. [Resource]. У мене відсутня назва проекту. Дякую!
— Біллі Джейк О'Коннор

У моїй проблемі було використання GetExecutingAssembly () замість GetEntryAssembly (). Ресурс, який я хотів, знаходився у виконаному файлі, але функція для завантаження ресурсу жила в іншому, посилається на проект, у тому самому рішенні.
— lettucemode

63

У мене була аналогічна проблема, спочатку перевірте, чи файл включений у ваш проект, потім перейдіть до властивостей і встановіть дію збірки цього файлу на Вбудований ресурс. це працювало для мене.


Це мені допомогло! У мене були раніше додані файли, які дефолтом були вбудовані ресурси, а потім ті, які я додав пізніше, які були встановлені на "None". Visual Studio часом так дратує. Найгірше, що всі файли XML для ресурсів не мають налаштувань для дії збірки. Повинна бути встановлена ​​дія збірки.
— John Suit

1
Не забудьте використовувати простір імен за замовчуванням і шлях до ресурсу. напр DefatultNameSpace.Infrastructure.Help.txt. Простір імен за замовчуванням на вашій сторінці властивостей проекту, і Infrastructureце папка, в яку ви знаходитесь
— jabu.hlong

Це те, що я хотів ура!
— таббі

19

Властивість "Build Action" вбудованого файлу слід встановити як "Embedded Resource", щоб правильно запустити рядок, який наведено нижче:

Stream stream = assembly.GetManifestResourceStream(resourceName)

Клацніть правою кнопкою миші на файл, клацніть на властивості та встановіть властивість "Build Action" як "Вбудований ресурс":

введіть тут опис зображення


Саме це було моїм питанням. Дякую!
— Рікі

1
Це була моя проблема. Я додав його за допомогою Resources.resx, і він не працював.
— Гелдер Ліма

11

Ось причина мого нульового значення.

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

GetManifestResourceStreamМетод завжди повертається , NULLякщо ресурс «Built дії» властивість не встановлено на «впроваджений ресурс»

Після встановлення цього властивості з усіма необхідними файлами assembly.GetManifestResourceStreamпочинає повертати правильний потік замість NULL.


1
Знову дякую. Це виправлено мою проблему місяць-два тому, тоді я забув про неї, у мене була та сама проблема, і вона виправлена ​​знову.
— Багатий

8

Просто попередження.

Я не міг отримати доступ до свого файлу як вбудований ресурс, хоча я вказав, що він є, і хоча він мав це властивість Build Action. Даремно багато часу стукав головою. Я вбудував файл коду csharp з .txt, доданим до його імені (xxx.cs.txt). Чомусь методи GetManifestResourceNames () та GetManifestResourceStream () не побачать файл із .cs у своєму імені.

Я її перейменував просто xxx.txt, і все було добре.

Дивно.


1
На це сьогодні витрачено занадто багато часу! Він буде вбудовувати його, якщо ви використовуєте, Resourceале ні Embedded Resource, що робить його ще більш дивакуватим ... Видалення .cs.з імені змушує його працювати. Арг.
— Метт

Проблема не в тому, що .cs. шлях / сегмент у файлах розпізнається як файл C #, а не як CultureInfo.
— frontlinebg

2
Здається, що з подвійним розширенням це зовсім не працює.
— Даріон Бадлідон

3

У мене була така ж проблема, завдяки Джею я виявив, що це дефіси в імені каталогу.

ProjectName.ResourceFolder.Sub-Directoryстає, ProjectName.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();

І як запропоновано інші відповіді, не забудьте встановити "Вбудований ресурс" у властивості Build Action файлу ресурсу.

Перевагою цього рівномірного рішення є

  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 з ресурсів тієї ж Асамблеї, деякі відповіді припускають, що коли ресурси знаходяться в іншому проекті чи зборах, їх не можна отримати, і є справедливою причиною повернення 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";

І на Form1.cs з WinFormFramework, з яким я вказую

Простір імен.Folder.Resource

щось схоже на те:

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

Можливо, вам потрібно буде вказати шлях до вашого файлу txt у GetManifestResourceStreamпараметрі, або ви можете спробувати вставити файл txt у той самий каталог, що і ваш виконуваний файл. Сподіваюся, що це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.