如何使用资源
文件 摘要 .NET 中有一套非常完善的地方化系统被定义在 System.Resources 名字空间中。不过大多数人都被 MissingManifestResourceException 这个
错误困惑着。本文就是要让大家了解什么是资源
文件,它有什么用处以及如何正确的
调用从而避免一些"奇怪"的
错误,
包括 MissingManifestResourceException 这个常见
错误。 目录 本文来源以及最终目的 什么是资源
文件 资源
文件类型
调用资源
文件的几种
方法 如何准确的定义资源
文件的逻辑位置 推荐工具 总结 参考信息 关于作者 本文来源以及最终目的 最近作者在新闻组中看到许多有关资源
文件的问题,而大多数人都有 MissingManifestResourceException 这个非常时髦的
错误。所以作者考虑了一下,决定不想再让更多的人把时间都浪费在这个问题上了。这就是这篇
文章的诞生原因。而最终目的除了让这个问题在新闻组上消失之外还要让大家在 10 分钟内彻底掌握资源的
调用,从而成为真正的资源高手!:) 什么是资源
文件 在 .NET 中准备 World-Ready 程序时需要三步,Globalization,Localizability 和 Localization。在这第三步的 Localization 中就是使用资源
文件最常见的地方。(本文不讨论 World-Ready 程序,或许以后在另一篇
文章中)因为程序的逻辑界面需要与资源界面隔离,而资源界面就是我们所说的资源
文件。顾名思义,一个资源
文件中当然全是资源,不过,什么是资源?这里所谓的资源就是程序中可利用的数据,譬如:字符串、
图片和任何二进制数据,
包括任何类型的
文件。注意一个资源
文件可以有多种语言版本,举例,一个 Strings.resources
文件可以有英语版、简体
中文版、繁体
中文版等。 ResourceManager 可以
自动根据
文件名来确认
调用哪个版本。不同的版本只要在
文件名中添入区域语言就可以了。比如,我们的 Strings.resources 是默认版,英语版的可以是 Strings.en-US.resources(美国英文),简体
中文的可以是 Strings.zh-CHS.resources(简体
中文),而繁体
中文的就可以是 Strings.zh-CHT.resources(繁体
中文)。所谓的默认版就是当找不到适当的资源版本时用的资源,一般都是英文。默认
文件应当被嵌入到主 Assembly 中,这样就不会发生找不到资源的
错误。在 VS.NET 中将一个
文件的
属性设为 Embedded Resource 可以使资源被嵌入到主 Assembly 中。 资源
文件类型 System.Resources 名字空间
支持三种资源
文件: .txt
文件,只能有字符串资源。因为不能被嵌入到 Assembly 中,所以很容易暴露,被客户
修改。最大缺点是仅
支持字符串资源,所以不推荐使用。 .resx
文件,由 XML 组成,可以加入任何资源,
包括二进制。同样不能被嵌入到 Assembly 中。在 System.Resources 名字空间中有专用读写的类。VS.NET 创建这种
文件然后将其转成 .resources
文件并根据设置将其嵌入到 Assembly 中。 .resources
文件,PE 格式,可以加入任何资源。唯一可以被嵌入到 Assembly 的
文件,在 System.Resources 名字空间中有专用读写的类。
调用资源
文件的几种
方法 ResourceManager 可以根据不同的 UICulture 设置返回不同的本地资源(这与 World-Ready 程序有关,在此不讨论),我们只需知道
调用资源用到它就可以了。接下来让我们看看如何
调用每一种: .txt
文件: 不可以直接
调用,得先将其转换成 .resources
文件才能使用。(关于如何转换请看"推荐工具") .resx
文件: 可以用 ResXResourceReader 来做读取,但是这种
方法不直观,不推荐直接
调用 .resx
文件。正确的
方法是将其转换成 .resources
文件,然后用 ResourceManager 作读取工作。注意如果是在 VS.NET 中
添加的 .resx
文件,那么它们
自动被设为 Embedded Resource,转成 .resources
文件后被嵌入到 Assembly 中。 .resources
文件: 分成两种情况: 被嵌入或编译成 Satellite Assembly: 用 ResourceManager 的各种 constructor 来获得在 Assembly 中的资源。 单独
文件,没被编译或嵌入到 Assembly 中: 可以用 ResourceManager.CreateFileBasedResourceManager 来获得资源集(ResourceSet),就是所有的资源。 特殊情况: 还有一种特殊情况,那就是当你直接嵌入一资源时,也就是说,不通过一个资源
文件而直接将一资源嵌入到 Assembly 中。这可以在 VS.NET 中通过设置一
文件的 Build
属性为 Embedded Resource 实现。在这种情况下 ResourceManager 就没有用了,因为它只能
获取 .resources 资源
文件(在或不在 Assembly 中)。那么如何
调用这类的资源呢?不难,我们需要利用一些 Reflection 中的特征。别怕,不是让你再学 Reflection,其实我们只要了解一些 System.Reflection.Assembly 这个类中的一些
函数就可以了。有三个相关
函数,不过我们只需要 Assembly.GetManifestResourceStream 这个
函数。这个
函数将一嵌入到 Assembly 中的资源以 stream 的方式返回,而我们可以将这个 stream 转成在 .NET 中可用的对象。比如,如果嵌入资源是一
图片,那么我们可以利用 New Bitmap(Stream) 这个 Bitmap 的 constructor 获得这个
图片资源的 Bitmap 对象。 注:在这里仅介绍怎样获得不同的资源的
方法,关于怎样用各个类与
函数请参看有关文档。 如何准确的定义资源
文件的逻辑位置 我想这是许多人最关注的一段了!在这里作者将解说如何正确的填写 ResouceManager(String,Assembly) 这个 constructor,还有如何正确的填写 Assembly.GetManifestResourceStream(String),因为它们两个的原理是相同的。看过了上面的描述,到了这里就简单多了。这里主要讨论的是怎么填写那个 String。这个 String 就是资源的完整名,一个完整名由它的名字空间和
文件名前部分(BaseName)组成。例如,如果默认名字空间(root namespace)是 DefaultNamespace,资源
文件的名字是 Strings.en-US.resources,那么它的完整名就是 DefaultNamespace.Strings。这个很简单,不过怎样确定名字空间呢?这就有些奇怪了,因为 C# 的编译器与 VB.NET 的编译器有些不同。作者在这里分别给出两个编译器怎样给嵌入资源
自动添加命名空间: C# 它
自动添加 default namespace(与 root namespace 相同),但也
添加子
文件夹的名字。例如,在 Subfolder 子
文件夹下放的资源
文件 Strings.en-US.resources,它的完整名是 default namespace + subfolder + base name = DefaultNamespace.Subfolder.Strings VB.NET 在 VB.NET 中就很简单了,它
自动给嵌入资源
添加 root namespace。不管你在哪个子
文件夹中放置资源
文件,资源
文件的完整名永远是 root namespace + base name。 根据上面的描述,如果我们使用 C#,用 VS.NET 在 NewFolder 这个子
文件夹中
添加了一个叫 Images.resources 的资源
文件,那么我们应该用以下
代码获取这些资源,假设 default namespace 是 MyDefault: ResourceManager res = new ResourceManager("MyDefault.NewFolder.Images",this.GetType().Assembly); 但如果我们用 VB.NET 的话,就应该这样: Dim res As New ResourceManager("MyDefault.Images",Me.GetType().Assembly) 推荐工具 resgen.exe:SDK 中的工具,专门用来做资源
文件类型之间的转换。
支持 .txt <-> .resx <-> .resources 之间的转换。 Resourcer:专门用来创建资源
文件,简单易用,
支持 .resx 与 .resources
文件格式。(http://www.aisto.com/roeder/dotnet) .NET Reflector:用来浏览 Assembly。如果你不确定一个资源
文件的完整名时可以用这个工具在 Assembly 中查看。(http://www.aisto.com/roeder/dotnet) 总结 本文中谈及了以下
内容: 什么是资源 什么是资源
文件 .NET 中有哪几类资源
文件 如何定义资源
文件的逻辑位置
调用资源
文件的几种
方法 本文通过正确定位资源
文件而
解决了那个非常时髦的 MissingManifestResourceException。本文给了您一个很丰富资源
调用经验。想让您完全了解有关资源
文件的任何可能问题,当然也会有漏洞。如果有的话希望大家谅解! 参考信息 以下是一些文档的
链接,如果您的帮助是
中文的话请在 MSDNVS 后
添加".2052": Resource File Generator (Resgen.exe) ms-help://MS.VSCC/MS.MSDNVS/cptools/html/cpgrfresourcefilegeneratorutilityresgenexe.htm Resources in Applications ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpconcreatingusingresources.htm Resource Fallback Process ms-help://MS.VSCC/MS.MSDNVS/cpguide/html/cpconpackagingdeployingresources.htm#cpconpackagingdeployingresourcesanchor1 关于作者 作者:袁伟(Kefroth) 电子
邮件:kefroth@interlap.com.ar