如何从资源文件中获取流对象(控制台应用程序/Windows 服务项目) [英] How To Get A Stream Object From A Resource File (Console App/Windows Service Project)

查看:18
本文介绍了如何从资源文件中获取流对象(控制台应用程序/Windows 服务项目)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个 Windows 服务并试图访问我添加到资源文件中的一些文件,但我被卡住了,因为我不知道如何访问各个文件.只是为了一些背景信息,这是我到目前为止所做的:

I'm creating a Windows service and am trying to access some files I added to a resource file, but I'm stuck because I don't know how to access the individual files. Just for some background info, here's what I've done so far:

  • 这是一个在调试模式下作为控制台应用程序运行的 C# Windows 服务应用程序,它帮助我进入代码.

  • This is a C# Windows Service application running in debug mode as a console app, which helps me step into the code.

我在根目录中添加了一个名为Resources.resx"的资源文件.

I added a resource file to the root called "Resources.resx".

在我的资源文件中,我使用视觉设计器/编辑器添加了一些 jpg 图像和 html 文件.

In my resource file, I added a few jpg images and html files using the visual designer/editor.

在我将图像和 html 文件添加到资源文件后,我的项目中出现了一个名为Resources"的新文件夹,其中包含我添加的所有文件.

After I added the images and html files to the resource file, a new folder in my project appeared named "Resources" with all the files I added.

在这个新文件夹中,我转到每个文件的属性并将构建操作更改为嵌入式资源.(不知道有没有必要.我搜索的一些博客说可以试试.)

In this new folder, I went to the properties of each file and changed the Build Action to Embedded Resource. (I don't know if this is necessary. Some blog I searched said to try it.)

该项目的命名空间称为MicroSecurity.EmailService".

The project's namespace is called "MicroSecurity.EmailService".

为了得到资源文件的名字,我用了

In order to get the name of the resource file, I used

GetType().Assembly.GetManifestResourceNames()

GetType().Assembly.GetManifestResourceNames()

我得到以下内容

GetType().Assembly.GetManifestResourceNames() {string[2]} string[][0] "MicroSecurity.EmailService.Services.EmailService.resources" 字符串[1] "MicroSecurity.EmailService.Resources.resources" 字符串

GetType().Assembly.GetManifestResourceNames() {string[2]} string[] [0] "MicroSecurity.EmailService.Services.EmailService.resources" string [1] "MicroSecurity.EmailService.Resources.resources" string

由此我确定MicroSecurity.EmailService.Resources.resources"是我想要使用的字符串(索引 1).

From this I identified that "MicroSecurity.EmailService.Resources.resources" is the string I want to use (index 1).

  • 我使用此代码获取流对象.

  • I used the this code to get a stream object.

var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MicroSecurity.EmailService.Resources.resources");

var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MicroSecurity.EmailService.Resources.resources");

在调试期间向该变量添加监视时,我可以看到诸如图像的元数据等内容.

When I add a watch to this variable during debugging, I can see things such as metadata for my images and etc.

这就是我被卡住的地方.我想访问名为logo.jpg"的图像.这就是我为获取图像所做的工作,但它不起作用.

Here is where I'm stuck. I would like to access the image called "logo.jpg". This is what I'm doing to get at the image, but it's not working.

var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MicroSecurity.EmailService.Resources.resources.logo.jpg");

如何从我的 logo.jpg 文件中获取流?

How can I get a stream from my logo.jpg file?

更新:

多亏了安德鲁,我才弄明白了.下面是我为演示项目编写的一些代码,目的是研究资源文件与直接嵌入文件的工作方式.我希望这有助于其他人澄清差异.

Thanks to Andrew, I was able to figure it out. Below is some code I wrote for a demo project in order to study how the resource file works vs. embedding files directly. I hope this helps others to clarify the differences.

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 Imageszombie.gif file and the text from the TextTextFile.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 Imageszombie.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 Imageszombie.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;
            }
        }
    }
}

推荐答案

如果您将 Resources 文件夹中的文件设置为 Embedded Resource,那么您应该已经看到它列在 GetManifestResourceNames() 调用中.你可以试试

If you set the files in the Resources folder to Embedded Resource then you should have seen it listed in the GetManifestResourceNames() call. You could try

var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MicroSecurity.EmailService.Resources.logo.jpg");

如果位于资源文件夹中,则名称应为MicroSecurity.EmailService.Resources.logo.jpg".然而,将文件本身标记为嵌入资源违背了资源文件的目的(图像本身将被嵌入两次).

The name should be "MicroSecurity.EmailService.Resources.logo.jpg" if it is in the Resources folder. However, marking the file itself as an Embedded Resource defeats the purpose of the Resources file (the image itself would be embedded twice).

您可以完全删除资源文件并将每个文件设置为嵌入式资源.那时,每个文件都应该有单独的清单资源.在 C# 项目中,每个文件名都会以项目命名空间 + 子文件夹为前缀.例如.如果在 Resources/Embedded 文件夹中添加logo.jpg"文件,则资源名称将为MicroSecurity.EmailService.Resources.Embedded.logo.jpg".

You can remove the resources file entirely and set each file as an Embedded Resource. At that point, there should be separate manifest resources for each file. In a C# project, each file name will be prefixed by the project namespace + the sub folder. Eg. if you add a "logo.jpg" file in a Resources/Embedded folder, the resource name will be "MicroSecurity.EmailService.Resources.Embedded.logo.jpg".

或者,从资源文件中获取位图并将其转换为流.您可以在 如何将位图转换为字节[]?

Alternatively, get the bitmap from the Resources file and convert it to a stream. You can find an example of converting a Bitmap to a MemoryStream in How do I convert a Bitmap to byte[]?

这篇关于如何从资源文件中获取流对象(控制台应用程序/Windows 服务项目)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆