.NET(C#):浅谈程序集清单资源和RESX资源

本文涉及的产品
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: 原文:.NET(C#):浅谈程序集清单资源和RESX资源  目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceManager解析二进制资源文件 小看RESX资源文件的Designer.
原文: .NET(C#):浅谈程序集清单资源和RESX资源

 

 

 

返回目录

程序集清单资源

在程序集中嵌入资源的最简单方法是什么?那就是使用Visual Studio中的“嵌入式资源(Embedded Resource)”创建选项,相当于使用csc的”/resource”参数。具体步骤,首先在Visual Studio的工程中选择资源文件,然后选择“属性”,接着在属性框中的Build Action中选择Embedded Resource,如下图,把a.file作为资源文件。

image

 

这个a.file成为嵌入资源后,它将会作为清单资源(Manifest Resource)存入程序集清单中(Assembly Manifest):

IC3648

 

程序集清单是程序集不可缺少的元素,上图来自MSDN,可以参考更多关于程序集或者程序集清单的信息在这里:http://msdn.microsoft.com/zh-cn/library/1w45z383(v=VS.100).aspx,本文就不再多说了。

 

接下来要关心的是怎样使用程序集清单中的资源。

我们可以使用Assembly类的GetManifestResourceNames方法,返回程序集的所有清单资源的文件名。

或者Assembly.GetMenifestResourceStream方法返回指定资源的流。

 

比如刚才那个包含a.file的程序集。

var ass = Assembly.GetExecutingAssembly();

foreach(var file in ass.GetManifestResourceNames())

    Console.WriteLine(file);

 

输出

Mgen.a.file

前面的Mgen是程序集的默认命名空间,VS在编译后会自动把命名空间加在文件名的前面的。

 

接下来使用GetManifestResourceStream来读取文件内容:

var ass = Assembly.GetExecutingAssembly();

var stream = ass.GetManifestResourceStream("Mgen.a.file");

/* 操作Stream对象来读取文件信息 */

 

 

返回目录

RESX资源文件

另外一种创建资源的形式就是RESX资源文件,这个通过VS的添加文件中的“资源文件”类型。RESX文件相比手动创建上面讲的程序集清单资源最大的优势就是:

  • 支持多语言
  • 快速创建资源
  • 管理方便

RESX可以支持多语言,Visual Studio编译后会出现附属程序集(satellite assembly),事实上是连接器(AL.exe)做这份工作。程序在执行在不同语言环境会搜索相应语言的资源。同时Visual Studio还提供了强大的RESX的资源编辑器。

 

同程序集清单资源一样,我们还是要弄懂所谓RESX资源到底是怎么存的。

现在,在工程中创建一个Resource1.resx,编辑它,添加一个b.file文件,再添加一个字符串,随便写个名称。

 

完成后,你会发现工程里多了些文件:

image

 

a.file是上面我们手动加的程序集清单资源。而Resource1.resx中的文件被存到了一个叫Resources的文件夹内(图中的b.file)。

 

检查这两个文件的属性中的Build Action,你会发现,Resources内的文件的Build Action都是None,VS不会对他们进行任何操作的,就好像他们不在工程里似的。而RESX文件的Build Action则是Embedded Resource,它会成为程序员清单资源,不同于不同程序集清单资源,RESX在编译时下面的Custom Tool是一个叫ResXFileCodeGenerator的工具:

image

 

这个工具会把所有RESX的资源连起来创建成一个二进制文件,VS最后把这个生成的文件最终作为程序集清单资源文件保存到程序集中。这个二进制资源文件的扩展名是.resources。

 

此时再运行上面讲的Assembly.GetManifestResourceNames方法来枚举程序集清单资源文件,输出会成:

Mgen.a.file

Mgen.Resource1.resources

 

Resource1.resx文件会最终编译成Mgen.Resource1.resources资源文件。

整个过程可以看这张图:

image

 

 

返回目录

使用ResourceReader和ResourceSet解析二进制资源文件

建议先读这篇文章来先了解IResourceReader,IResourceWriter和ResourceSet类型:.NET(C#):使用IResourceReader,IResourceWriter和ResourceSet。这里就不在讲这三个类型的使用。

 

上面讲过,RESX资源文件最终会被编译成.resources扩展名的资源文件(二进制)并保存在程序集清单资源(assembly manifest resource)。

下面我们用.NET中的.resources二进制资源文件的解析类ResourceReader和ResourceSet来手动解析这个.resources文件。

 

代码:

//+ using System.Resources

static void Main()

{

    using (Stream resources = Assembly.GetExecutingAssembly().GetManifestResourceStream("Mgen.Resource1.resources"))

    {

        //使用IResourceReader

        ReadUsingResourceReader(resources);

        //重新定位Stream

        resources.Seek(0, SeekOrigin.Begin);

        //使用ResourceSet

        ReadUsingResourceSet(resources);

    }

}

 

//使用IResourceReader

static void ReadUsingResourceReader(Stream st)

{

    Console.WriteLine("== 使用IResourceReader");

    IResourceReader rr = new ResourceReader(st);

    var iter = rr.GetEnumerator();

    while (iter.MoveNext())

        Console.WriteLine("键: {0} 值: {1}", iter.Key, iter.Value);

    //不需要调用IResourceReader.Dispose,Stream会在Main方法中被Dipose

}

//使用ResourceSet

static void ReadUsingResourceSet(Stream st)

{

    Console.WriteLine("== 使用ResourceSet");

    ResourceSet rs = new ResourceSet(new ResourceReader(st));

    Console.WriteLine(BitConverter.ToString((byte[])rs.GetObject("b")));

    Console.WriteLine(rs.GetString("String1"));

    //不需要调用ResourceSet.Dispose,Stream会在Main方法中被Dipose

}

这将会以ResourceReader和ResourceSet两种方式输出b.file的字节内容和String1字符串。

 

 

返回目录

使用ResourceManager解析二进制资源文件

关于ResourceManager类型的使用,可以参考:.NET(C#):使用ResourceManager类型。这里就不再多讲了。

我们就直接使用ResourceManager,还是上面的工程,用ResourceManager来解析这个.resources二进制的资源文件。

 

代码:

//+ using System.Resources

ResourceManager resManager = new ResourceManager(typeof(Resource1));

//等效于:new ResourceManager("Mgen.Resource1", Assembly.GetExecutingAssembly());

//此时ResourceManager.BaseName是Type.FullName正好是Mgen.Resource1

 

//获取file.b的内容

Console.WriteLine(BitConverter.ToString((byte[])resManager.GetObject("b")));

//获取资源中的字符串

Console.WriteLine(resManager.GetString("String1"));

这将会输出b.file的字节内容和String1字符串。

 

 

返回目录

小看RESX资源文件的Designer.cs文件

最后再让我们看看RESX资源文件后面的那个xxx.Designer.cs文件。

image

 

它定义了资源读取的一个类,比如资源文件名称是Resource1,这个类的名称就是Resource1。这个类其实就是内部包装了一个上面讲的ResourceManager,并且根据用户RESX定义的资源数据显示的定义具有强类型的属性值用来读取文件。

 

其内部ResourceManager是这样被初始化的,可以看到,ResourceManager.BaseName就是程序集清单资源的名称(注意ResourceManager.BaseName属性没有CultureInfo名称和.resources扩展名,但是有命名空间(其实完全就是文件名),所以本例中的Mgen.Resource1.resources程序集清单资源文件的ResourceManager初始化BaseName就是:Mgen.Resource1。)

internal static global::System.Resources.ResourceManager ResourceManager {

    get {

        if (object.ReferenceEquals(resourceMan, null)) {

            global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Mgen.Resource1", typeof(Resource1).Assembly);

            resourceMan = temp;

        }

        return resourceMan;

    }

}

 

接着RESX中定义的文件b和字符串String1资源完全就是ResourceManager的方法的包装,比如b文件读取返回字节数组,就是调用ResourceManager.GetObject,然后转换成byte[]:

internal static byte[] b {

    get {

        object obj = ResourceManager.GetObject("b", resourceCulture);

        return ((byte[])(obj));

    }

}

 

好了,就到这里吧,希望读者读完文章后对RESX文件和程序集清单资源有更好的理解!

Open-mouthed smile

目录
相关文章
|
11天前
|
开发框架 前端开发 .NET
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
集成于VS 2019,EXT.NET前端和ASP.NET后端,搭配MSSQL 2018数据库。系统覆盖样品管理、数据分析、报表和项目管理等实验室全流程。应用广泛,包括生产质检(如石化、制药)、环保监测、试验研究等领域。随着技术发展,现代LIMS还融合了临床、电子实验室笔记本和SaaS等功能,以满足复杂多样的实验室管理需求。
22 3
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
|
4天前
|
前端开发 测试技术 C#
如何开发一套基于C#和.NET 6.0手术麻醉系统? 手术麻醉系统源码
如何开发一套基于C#和.NET 6.0手术麻醉系统?
15 1
|
5天前
|
开发框架 前端开发 调度
C#基于Quartz.NET实现任务调度并部署Windows服务
C#基于Quartz.NET实现任务调度并部署Windows服务
|
9天前
|
C#
WPF/C#:程序关闭的三种模式
WPF/C#:程序关闭的三种模式
13 3
|
10天前
|
Java C# 数据安全/隐私保护
|
17天前
|
Cloud Native API C#
C#的现代化:.NET Core引领的技术革命
【6月更文挑战第9天】`.NET Core引领C#现代化,实现跨平台革命,提升性能并支持云原生应用。异步编程模型优化体验,统一API简化开发流程。C#应用场景扩展,开发效率提高,技术创新加速,预示其未来在技术领域将持续发挥关键作用。`
29 10
|
15天前
|
并行计算 算法 C#
C# Mandelbrot和Julia分形图像生成程序更新到2010-9-14版 支持多线程计算 多核处理器
此文档是一个关于分形图像生成器的介绍,作者分享了个人开发的M-J算法集成及色彩创新,包括源代码和历史版本。作者欢迎有兴趣的读者留言交流,并提供了邮箱(delacroix_xu@sina.com)以分享资源。文中还展示了程序的发展历程,如增加了真彩色效果、圈选放大、历史记录等功能,并分享了几幅精美的分形图像。此外,还提到了程序的新特性,如导入ini文件批量输出图像和更新一批图片的功能。文档末尾附有多张程序生成的高分辨率分形图像示例。
|
15天前
|
存储 编解码 算法
C#.NET逃逸时间算法生成分形图像的毕业设计完成!晒晒功能
该文介绍了一个使用C#.NET Visual Studio 2008开发的程序,包含错误修复的Julia、Mandelbrot和优化过的Newton三种算法,生成色彩丰富的分形图像。作者改进了原始算法的效率,将内层循环的画点操作移至外部,提升性能。程序提供五种图形模式,支持放大缩小及颜色更新,并允许用户自定义画布大小以调整精度。还具备保存为高质JPG的功能。附有四张示例图片展示生成的分形效果。
|
23天前
|
XML 开发框架 .NET
【.NET Core】常见C#代码约定
【.NET Core】常见C#代码约定
19 5
|
22天前
|
前端开发 Java C#
GitHub突破5k Star!这件事情我坚持了3年,努力打造C#/.NET/.NET Core全面的学习、工作、面试指南知识库
GitHub突破5k Star!这件事情我坚持了3年,努力打造C#/.NET/.NET Core全面的学习、工作、面试指南知识库