** .NET ** ** 系统学习 ** ** ----Globalization & Resources **
l 前言
l 了解资源文件
l 创建资源文件
l 在程序中使用资源文件
l 资源文件的命名和部署
l 参考
** 前言: ** ** **
在学习如何使用 .NET 资源文件以及如何开发 World-Ready 程序之前,我们先通过一个例子来看看为什么要使用资源文件,以及使用它的好处。
假设要在程序中根据当前的 Culutre 来设置 Form 的 Title 和 Logo :
private void Form1_Load( object sender, System.EventArgs e) {
CultureInfo ci = new CultureInfo ( Thread.CurrentThread.CurrentUICulture.ToString ());
switch ( ci.ToString (). ToLower ()) {
case " zh-cn ": // 中文版本
this .Text = FormTitle_ZH_CN ;
imgLogo.Image = new Bitmap( Application.StartupPath + "/ Logo_ZH_CN.jpg ");
break ;
case "en-us": // 英文版本
this .Text = FormTitle_EN_US ;
imgLogo.Image = new Bitmap( Application.StartupPath + "/ Logo_EN_US.jpg ");
break ;
default : // 默认版本
this .Text = FormTitle_Neutral ;
imgLogo.Image = new Bitmap( Application.StartupPath + "/ Logo_Neutral.jpg ");
break ;
}
}
这段代码有两个问题:
首先, Logo 文件是暴露给用户的,而且是以普通文件的格式存储的,这导致其他程序或是用户很容易修改这些文件;节省硬盘空间的用户还可能会选择删除它,这些都可能会导致应用程序出错。 确保图片或任何其他文件和代码在一起的唯一的安全方式是将它作为资源文件嵌入在程序集中并加载。 ** **
其次,这是一个 World-Ready 程序,如果需要新加入一个新的 Culture ,你可能不得不更改你的源代码,加入新的 case ,然后重新编译来适应新的 Culture 的需要,这对一个 World-Ready 程序来说是不现实的。 开发 ** World-Ready ** ** 程序很重要的一点就是要保证程序的逻辑界面和资源界面的隔离。 ** 任何时候加入一个新的 Culture 资源,我们都不应该重新编译源程序,相反,我们只需要把新的资源文件准备好,然后发布给用户并部署在合适的目录下就可以了。应用程序应该能够根据不同的 Culture 来自动寻找合适的资源。
本文的目的就是通过实例来帮助读者了解什么是 Resources ,以及如何使用 Resources 来消除上面所提到的两个问题。
全文分为四部分:
第一部分是一些和资源相关的概念。
第二部分是一个实例程序( ResourceGenerator ),用来说明如何创建资源文件。
第三部分是另外一个实例程序( WorldAPP ),用来说明如何在程序中使用资源文件
第四部分是关于资源文件的命名和部署。分别介绍 .NET 中资源文件的命名方式和如何在 World-Ready 程序中配置资源文件。
** 第一部分 ** ** ** ** 概念 ** ** **
先来了解一些概念:
** 1. ** ** 什么是资源文件 ** ** **
顾名思义,资源文件当然包含的全是资源。不过,什么是资源?这里所谓的资源就是程序中可利用的任何数据,譬如:字符串、图片或任何二进制格式的数据。一个资源文件可以有多种语言文化版本,比如,一个 Culture.resources 文件可以有英语版、简体中文版日文版等。 ResourceManager 可以自动根据 Culture 和资源文件名来确认调用哪个版本。只不过不同的资源版本需要在文件名中加入语言文化信息( ** .resource ** ** 文件有一套严格的命名规范,参考 ** ** 第四部分:资源文件的命名和部署 ** ** )。 ** ** **
** 2. ** ** 资源文件的类型 ** ** **
System.Resources 名称空间支持三种类型的资源:
.txt 文件,只能有字符串资源。因为不能被嵌入到 Assembly 中,所以很容易暴露,被其他程序或用户修改。最大缺点是仅支持字符串资源,不推荐使用。
. resx 文件,由 XML 组成,可以加入任何资源,包括二进制格式的。同样不能被嵌入到 Assembly 中。在 System.Resources 名称空间中有专用读写的类。 VS.NET 中创建的这种文件也是将其转成 .resources 文件然后根据设置将其嵌入到 Assembly 中。
.resources 文件, PE 格式,可以加入任何资源。 是唯一可以被嵌入到 ** Assembly ** ** 的文件 ** ,在 System.Resources 名称空间中有专用读写的类( ResourceManager )。
** 3. ** ** 调用资源文件的几种方法 ** ** **
ResourceManager 可以根据不同的 UICulture 设置返回不同的本地资源, 不同 ** Culture ** ** 的资源文件有一套严格的命名规则,只有按照这个规则命名, ** ** CRL ** ** 才可以根据 ** ** Culture ** ** 找到这个本地资源。 ** ** PS ** ** :因为这个很重要,所以才一再出现 ** J 。 参考 ** 第四部分:资源文件的命名和部署 ** )
.txt 文件:
不可以直接调用,得先将其转换成 .resources 文件才能使用。
. resx 文件:
可以用 ResXResourceReader 来读取,但是这种方法不直观也不安全,不推荐直接调用 . resx 文件。正确的方法是将其转换成 .resources 文件,然后用 ResourceManager 读取。注意,如果是在 VS.NET 中添加的 . resx 文件,那么它们自动被设为 Embedded Resource ,然后被转成 .resources 文件后嵌入到 Assembly 中。
.resources 文件:
分成两种情况:
· 被嵌入或编译成卫星程序集( Satellite Assembly ):
用 ResourceManager 的各种 constructor 来获得在 Assembly 中的资源。
· 单独文件,没有被编译或嵌入到 Assembly 中:
可以用 ResourceManager.CreateFileBasedResourceManager 来获得资源集( ResourceSet ),就是所有的资源。
** 特殊情况: ** ** **
还有一种特殊情况,那就是当你直接嵌入一资源时,也就是说,不通过一个资源文件( .resources )而直接将一 资源 ( Object )嵌入到 Assembly 中。这可以通过 AL.exe ( Assembly Linker )的参数 /embed:
1<object> 把资源嵌入在 Assembly 中。在这种情况下 ResourceManager 就没有用了,因为它只能获取 .resources 资源文件(在或不在 Assembly 中)。
2
3调用这类直接嵌入在 Assembly 中的资源,我们就需要利用 Reflection 的一些特性来完成。在 System.Reflection.Assembly 类中有一些相关函数可以帮助我们拿到这些资源。通过 Assembly.GetManifestResourceNames 可以拿到所有的资源的名字,然后我们就可以通过 Assembly.GetManifestResourceStream ( < object_name > )这个函数拿到对应的资源并以 stream 的方式返回,然后我们可以将这个 stream 转成在 .NET 中可用的对象。比如,如果嵌入资源是一图片,那么我们可以利用 New Bitmap ( Stream )的 constructor 获得这个图片资源的 Bitmap 对象。
4
5** 第二部分 ** ** ** ** 创建资源文件 ** ** **
6
7创建资源文件有两种方式,一种是使用 .NET SDK 自带的 resgen 工具来创建,另外一种是自己写 code 来创建。分别来介绍:
8
9** 1\. ** ** Resgen ** ** : ** ** **
10
11这个工具是 .NET 自带的,它可以把 .txt , . resX ,转换为 .resources 文件。 .resources 文件是以一种以键 \- 值方式对应存储的 XML 格式文件,每一个键 <data> 对应一个值 <value> ,这个 <value> 可以是任何的二进制格式。如果是格式为(键 = 值)对应得 .txt 文件, resgen 会自动生成键 \- 值对应的 XML 文件。但是 resgen 有一个局限性,它不能直接嵌入其他格式的文件,比如你就不能把 .bmp 以键 \- 值得方式对应起来,因为你首先不能很容易得把 .bmp 以(键 = 值)对应的格式储存在 .txt 文件中。所以 resgen 主要是针对 txt 文件使用。
12
13一个例子: company1.txt 文件内容为:
14
15Title = Company1
16
17Address = Company1 Address
18
19Phone = 12345678
20
21\----------------------------------------------------------------
22
23_ Resgen _ _ company.txt < outputfilename >.resources _
24
25如果不指定 < outputfilename > ,默认会生成 company1.resources 。
26
27然后就可以通过 ResourceManager 来使用了。
28
29还可以再进一步,通过 AL.exe 把 resources 文件变为一个 assembly (使用 assembly 有很多好处(比如可以加入版本信息和 Culture 信息等)详见( .NET 系统学习 \----Assembly )。
30
31_ Al /out:company1.dll /embed:company1.resources _
32
33通过设置 ResourcesManager 的不同的 constructor 就可以访问 Assembly 中包含的 .resources 文件(下面的例子会讲到)。
34
35<p</value></value></data></object>