Как получить потоковый объект из файла ресурсов (Консольное приложение / Проект службы Windows)
Я создаю службу Windows и пытаюсь получить доступ к некоторым файлам, которые я добавил к файлу ресурса, но я застрял, потому что не знаю, как получить доступ к отдельным файлам. Просто для справки, вот что я сделал до сих пор:
Это приложение службы Windows C#, работающее в режиме отладки как консольное приложение, которое помогает мне войти в код.
Я добавил файл ресурсов в корень под названием "Resources.resx".
В своем файле ресурсов я добавил несколько изображений jpg и html-файлов с помощью визуального дизайнера / редактора.
После того, как я добавил изображения и html-файлы в файл ресурсов, в моем проекте появилась новая папка "Resources" со всеми добавленными мной файлами.
В этой новой папке я перешел к свойствам каждого файла и изменил действие Build Action на Embedded Resource. (Я не знаю, если это необходимо. В каком-то блоге, который я искал, сказано, чтобы попробовать.)
Пространство имен проекта называется "MicroSecurity.EmailService".
Чтобы получить имя файла ресурса, я использовал
GetType().Assembly.GetManifestResourceNames()
и я получаю следующее
GetType().Assembly.GetManifestResourceNames() {string[2]} string[] [0] "MicroSecurity.EmailService.Services.EmailService.resources" string [1] "MicroSecurity.EmailService.Resources.resources" string
Из этого я определил, что "MicroSecurity.EmailService.Resources.resources" - это строка, которую я хочу использовать (индекс 1).
Я использовал этот код, чтобы получить объект потока.
var stream = Assembly.GetExecutingAssembly (). GetManifestResourceStream ("MicroSecurity.EmailService.Resources.resources");
Когда я добавляю часы к этой переменной во время отладки, я вижу такие вещи, как метаданные для моих изображений и т. Д.
Вот где я застрял. Я хотел бы получить доступ к изображению под названием "logo.jpg". Это то, что я делаю, чтобы получить изображение, но оно не работает.
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MicroSecurity.EmailService.Resources.resources.logo.jpg");
Как я могу получить поток из моего файла logo.jpg?
ОБНОВИТЬ:
Благодаря Андрею я смог в этом разобраться. Ниже приведен код, который я написал для демонстрационного проекта, чтобы изучить, как работает файл ресурсов, а не встраивать файлы напрямую. Я надеюсь, что это помогает другим прояснить различия.
using System;
using System.Drawing;
using System.IO;
using System.Reflection;
namespace UsingResourceFiles
{
public class Program
{
/// <summary>
/// Enum to indicate what type of file a resource is.
/// </summary>
public enum FileType
{
/// <summary>
/// The resource is an image.
/// </summary>
Image,
/// <summary>
/// The resource is something other than an image or text file.
/// </summary>
Other,
/// <summary>
/// The resource is a text file.
/// </summary>
Text,
}
public static void Main(string[] args)
{
// There are two ways to reference resource files:
// 1. Use embedded objects.
// 2. Use a resource file.
// Get the embedded resource files in the Images and Text folders.
UseEmbeddedObjects();
// Get the embedded resource files in the Images and Text folders. This allows for dynamic typing
// so the resource file can be returned either as a stream or an object in its native format.
UseEmbeddedObjectsViaGetResource();
// Use the zombie.gif and TextFile.txt in the Resources.resx file.
UseResourceFile();
}
public static void UseEmbeddedObjects()
{
// =============================================================================================================================
//
// -=[ Embedded Objects ]=-
//
// This way is the easiest to accomplish. You simply add a file to your project in the directory of your choice and then
// right-click the file and change the "Build Action" to "Embedded Resource". When you reference the file, it will be as an
// unmanaged stream. In order to access the stream, you'll need to use the GetManifestResourceStream() method. This method needs
// the name of the file in order to open it. The name is in the following format:
//
// Namespace + Folder Path + File Name
//
// For example, in this project the namespace is "UsingResourceFiles", the folder path is "Images" and the file name is
// "zombie.gif". The string is "UsingResourceFiles.Images.zombie.gif".
//
// For images, once the image is in a stream, you'll have to convert it into a Bitmap object in order to use it as an Image
// object. For text, you'll need to use a StreamReader to get the text file's text.
// =============================================================================================================================
var imageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UsingResourceFiles.Images.zombie.gif");
var image = new Bitmap(imageStream);
var textStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UsingResourceFiles.Text.TextFile.txt");
var text = new StreamReader(textStream).ReadToEnd();
}
public static void UseEmbeddedObjectsViaGetResource()
{
// =============================================================================================================================
//
// -=[ Embedded Objects Using GetResource() ]=-
//
// Using the overloaded GetResource() method, you can easily obtain an embedded resource file by specifying the dot file path
// and type. If you need the stream version of the file, pass in false to the useNativeFormat argument. If you use the
// GetResource() method outside of this file and are getting a null value back, make sure you set the resource's "Build Action"
// to "Embedded Resource".
// =============================================================================================================================
// Use the GetResource() methods to obtain the Images\zombie.gif file and the text from the Text\TextFile.txt file.
Bitmap image = GetResource("Images.zombie.gif", FileType.Image);
Stream imageStream = GetResource("Images.zombie.gif", FileType.Image, false);
string text = GetResource("Text.TextFile.txt", FileType.Text);
Stream textStream = GetResource("Text.TextFile.txt", FileType.Text, false);
}
public static void UseResourceFile()
{
// =============================================================================================================================
//
// -=[ Resource File ]=-
//
// This way takes more upfront work, but referencing the files is easier in the code-behind. One drawback to this approach is
// that there is no way to organize your files in a folder structure; everything is stuffed into a single resource blob.
// Another drawback is that once you create the resource file and add any files to it, a folder with the same name as your
// resource file is created, creating clutter in your project. A final drawback is that the properties of the Resources object
// may not follow proper C# naming conventions (e.g. "Resources.funny_man" instead of "Resources.FunnyMan"). A plus for using
// resource files is that they allow for localization. However, if you're only going to use the resource file for storing files,
// using the files as embedded objects is a better approach in my opinion.
// =============================================================================================================================
// The Resources object references the resource file called "Resources.resx".
// Images come back as Bitmap objects and text files come back as string objects.
var image = Resources.zombie;
var text = Resources.TextFile;
}
/// <summary>
/// This method allows you to specify the dot file path and type of the resource file and return it in its native format.
/// </summary>
/// <param name="dotFilePath">The file path with dots instead of backslashes. e.g. Images.zombie.gif instead of Images\zombie.gif</param>
/// <param name="fileType">The type of file the resource is.</param>
/// <returns>Returns the resource in its native format.</returns>
public static dynamic GetResource(string dotFilePath, FileType fileType)
{
try
{
var assembly = Assembly.GetExecutingAssembly();
var assemblyName = assembly.GetName().Name;
var stream = assembly.GetManifestResourceStream(assemblyName + "." + dotFilePath);
switch (fileType)
{
case FileType.Image:
return new Bitmap(stream);
case FileType.Text:
return new StreamReader(stream).ReadToEnd();
default:
return stream;
}
}
catch (Exception e)
{
Console.WriteLine(e);
return null;
}
}
/// <summary>
/// This method allows you to specify the dot file path and type of the resource file and return it in its native format.
/// </summary>
/// <param name="dotFilePath">The file path with dots instead of backslashes. e.g. Images.zombie.gif instead of Images\zombie.gif</param>
/// <param name="fileType">The type of file the resource is.</param>
/// <param name="useNativeFormat">Indicates that the resource is to be returned as resource's native format or as a stream.</param>
/// <returns>When "useNativeFormat" is true, returns the resource in its native format. Otherwise it returns the resource as a stream.</returns>
public static dynamic GetResource(string dotFilePath, FileType fileType, bool useNativeFormat)
{
try
{
if (useNativeFormat)
{
return GetResource(dotFilePath, fileType);
}
var assembly = Assembly.GetExecutingAssembly();
var assemblyName = assembly.GetName().Name;
return assembly.GetManifestResourceStream(assemblyName + "." + dotFilePath);
}
catch (Exception e)
{
Console.WriteLine(e);
return null;
}
}
}
}
3 ответа
Если вы установите для файлов в папке "Ресурсы" значение "Встроенный ресурс", вы должны были увидеть его в списке в вызове GetManifestResourceNames(). Вы могли бы попробовать
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MicroSecurity.EmailService.Resources.logo.jpg");
Имя должно быть "MicroSecurity.EmailService.Resources.logo.jpg", если оно находится в папке "Ресурсы". Однако пометка самого файла как встроенного ресурса отрицательно сказывается на назначении файла ресурсов (само изображение будет встроено дважды).
Вы можете полностью удалить файл ресурсов и установить каждый файл как встроенный ресурс. На этом этапе должны быть отдельные ресурсы манифеста для каждого файла. В проекте C# каждому имени файла будет предшествовать пространство имен проекта + подпапка. Например. если вы добавите файл "logo.jpg" в папку Resources/Embedded, именем ресурса будет "MicroSecurity.EmailService.Resources.Embedded.logo.jpg".
Кроме того, получить растровое изображение из файла ресурсов и преобразовать его в поток. Вы можете найти пример преобразования Bitmap
к MemoryStream
в Как преобразовать растровое изображение в байт []?
Вы можете использовать:
System.Drawing.Bitmap myLogo = MicroSecurity.Properties.Resources.logo;
public static readonly Func<string, object> GetDataByType = (path) => {
var fromStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path);
var formatter = new BinaryFormatter();
if (fromStream != null) {
var obj = formatter.Deserialize(fromStream);
fromStream.Close();
return obj;
}
return null;
};
var test GetDataByType("Resources.logo");
var byteArray = Resources.YourResxFileName.TheResxFileName;
Stream stream = new MemoryStream(byteArray);
Посмотрите, как он встроил файл значка в resxhttps://www.technical-recipes.com/2017/how-to-use-resource-files-in-your-csharp-project/