如何获得一个exe的嵌入资源的文件名

本文关键字:exe 嵌入资源 文件名 一个 何获得 | 更新日期: 2023-09-27 18:09:18

在visual studio中,我有一个构建操作设置为'嵌入式资源'的文件。我想在运行时提取此文件,但无法获得文件名:

// returns null
Assembly.GetExecutingAssembly().GetManifestResourceInfo(resourceName).FileName

如何获得一个exe的嵌入资源的文件名

请注意,清单资源名确实包括原始文件名和项目相对子目录。

另一个答案中缺少的关键信息(使该答案不那么有用)是项目名称和包含原始文件的任何文件夹/目录在资源名称中表示为组件。整个清单资源名使用'.'字符分隔成这些组件。

掌握了这些知识,您应该能够正确地处理资源。特别是,您需要删除名称的第一个组件(它只是项目名称),然后将该名称的最后一个组件以外的所有组件视为目录名称。

这有点棘手,因为a)你的文件名可能有一个扩展名(所以里面已经有一个'.'字符),b)编译器会转义(以一种基本的方式)在文件夹/子目录名中找到的任何'.'字符。

下面的代码示例展示了基本的方法:
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(string.Join(Environment.NewLine,
            Assembly.GetEntryAssembly().GetManifestResourceNames()));
        Assembly assembly = Assembly.GetEntryAssembly();
        string exeDirectory = Path.GetDirectoryName(assembly.Location);
        foreach (string resourceName in assembly.GetManifestResourceNames())
        {
            string fileName = _GetFileNameFromResourceName(resourceName),
                directory = Path.GetDirectoryName(fileName);
            if (!string.IsNullOrEmpty(directory))
            {
                Directory.CreateDirectory(directory);
            }
            using (Stream outputStream =
                File.OpenWrite(Path.Combine(exeDirectory, fileName)))
            {
                assembly.GetManifestResourceStream(resourceName).CopyTo(outputStream);
            }
        }
    }
    private static string _GetFileNameFromResourceName(string resourceName)
    {
        // NOTE: this code assumes that all of the file names have exactly one
        // extension separator (i.e. "dot"/"period" character). I.e. all file names
        // do have an extension, and no file name has more than one extension.
        // Directory names may have periods in them, as the compiler will escape these
        // by putting an underscore character after them (a single character
        // after any contiguous sequence of dots). IMPORTANT: the escaping
        // is not very sophisticated; do not create folder names with leading
        // underscores, otherwise the dot separating that folder from the previous
        // one will appear to be just an escaped dot!
        StringBuilder sb = new StringBuilder();
        bool escapeDot = false, haveExtension = false;
        for (int i = resourceName.Length - 1; i >= 0 ; i--)
        {
            if (resourceName[i] == '_')
            {
                escapeDot = true;
                continue;
            }
            if (resourceName[i] == '.')
            {
                if (!escapeDot)
                {
                    if (haveExtension)
                    {
                        sb.Append('''');
                        continue;
                    }
                    haveExtension = true;
                }
            }
            else
            {
                escapeDot = false;
            }
            sb.Append(resourceName[i]);
        }
        string fileName = Path.GetDirectoryName(sb.ToString());
        fileName = new string(fileName.Reverse().ToArray());
        return fileName;
    }
}

用上面的代码创建一个新项目,然后将嵌入的资源添加到项目中,在项目文件夹中或不在项目文件夹中,以查看结果。

注意:你可能会发现过滤资源名称列表很有用。例如,如果你的项目有你使用设计器添加的传统资源(即显示项目属性,然后单击"资源"选项卡并在那里添加资源,而不是显式地作为嵌入资源),你将获得一个名为MyProjectName.Resources.resources的资源。否则,您将获得每个单独的清单资源。

注意:请记住,要写入可执行文件所在的目录,可能需要比当前进程更高级别的权限。例如,如果用户以admin身份将您的EXE复制到"程序文件"目录中的目录,但随后试图以受限用户身份运行该程序。正如评论者Luaan在你的问题下所暗示的那样,看起来你只是实现某种安装程序会更好。(Visual Studio提供免费访问基本的Install Shield产品,或者您可以使用例如wix & help;实际上不需要从头编写安装程序来实现安装程序)。

请注意GetManifestResourceInfo(resourceName)。FileName仅获取包含清单资源的文件的名称(如果它与清单文件不相同)。关于舱单,请看这里:http://www.dotnetspark.com/kb/682-what-is-manifest.aspx

可以使用程序集获取程序集中所有资源的名称列表。GetManifestResourceNames方法。

:

//str包含所有嵌入的资源名称

 string[] str = assembly.GetManifestResourceNames();