27程序集资源
程序集资源可以看作是Dictionary<string,byte[]>的字节数组。可以将资源直接嵌入到程序集中;也可以将资源单独嵌入到一个程序集,然后由主程序集引用包含资源的程序集,包含资源的程序集也叫卫星程序集(Satellite Assembly)。一个运用场景是:当开发多语言版本应用程序时,把不同的语言包作为资源签入到各个卫星程序集中,供主程序集调用。
通过VS可视化界面把资源嵌入到程序集,并浏览资源文件
在VS下创建Images/1.jpg→右键1.jpg→属性→生成操作的值设置为"签入的资源"
通过Assembly的实例方法获取资源名称:
static void Main(string[] args)
{
ShowResources();
Console.ReadKey();
}
private static void ShowResources()
{
Assembly asm = Assembly.GetExecutingAssembly();
string[] nameArray = asm.GetManifestResourceNames();
foreach (string name in nameArray)
{
Console.WriteLine(name);
using (Stream s = asm.GetManifestResourceStream(name))
{
Console.WriteLine("资源字节流的长度为:{0}",s.Length);
}
}
}
通过C#编译器将资源嵌入到程序集,并浏览资源文件
→把上面的Program.cs和1.jpg复制到F:\m文件夹下。
通过在VS中创建.resx文件把资源嵌入到程序集
→在VS项目下创建Resource1.resx文件,输入资源:
→把Resource1.resx和2.jpg一同复制到F:\m文件夹中。
→使用resgen.exe工具,根据Resource1.resx生成后缀为.resources的资源文件(这个才是真正的资源文件,包含了二进制内容)
生成完后,在F:\m文件夹中多了Resource1.resources资源文件
→写一段主程序Program1.cs来浏览Resource1.resources资源文件
using System;
using System.Reflection;
using System.IO;
class Program1{
static void Main(string[] args){
Assembly asm = Assembly.GetExecutingAssembly();
string[] nameArray = asm.GetManifestResourceNames();
foreach(string name in nameArray){
Console.WriteLine(name);
using(Stream s = asm.GetManifestResourceStream(name)){
StreamReader reader = new StreamReader(s);
string text = reader.ReadToEnd();
if(text.Length > 1000) text = text.Substring(0,1000);
Console.WriteLine(text);
Console.ReadKey();
}
}
}
}
→把Resource1.resources资源文件嵌入到程序集,生成Program1.exe
生成完后,在F:\m文件夹中多了Program1.exe文件
→运行Program1.exe
可见,Resource1.resources资源文件的内容的确是二进制的。
→把可视化Resource1.resx文件签入到程序集,生成Program1.exe
生成完后,在F:\m文件夹中Program1.exe文件进行了更新
→再次运行Program1.exe
可见,在VS中创建的可视化Resource1.resx和通过resgen.exe工具生成的Resource1.resources是有本质区别的,前者是xml文件,后者的内容是二进制。
通过反射获取后缀为.resources的资源文件信息
→主程序中通过ResourceManager来获取资源信息
using System;
using System.Reflection;
using System.IO;
using System.Resources;
using System.Drawing;
class Program1{
static void Main(string[] args){
ResourceManager r = new ResourceManager("Resource1", Assembly.GetExecutingAssembly());
string address = r.GetString("address");
Console.WriteLine("address:" + address);
Console.ReadKey();
}
}
→输入命令
生成完后,在F:\m文件夹中Program1.exe文件进行了更新
→再次运行Program1.exe
把资源嵌入到独立程序集中,让主程序来调用
→输入命令,把Resource1.resources资源文件签入到res.dll程序集中
→主程序中引用res.dll程序集
using System;
using System.Reflection;
using System.IO;
using System.Resources;
using System.Drawing;
class Program1{
static void Main(string[] args){
Assembly asm = Assembly.Load("res");
ResourceManager r = new ResourceManager("Resource1", asm);
string address = r.GetString("address");
Console.WriteLine("address:" + address);
Console.ReadKey();
}
}
→输入命令
→再次运行Program1.exe
开发多语言版本应用程序
→创建Resource.en.resx文件
→重新生成项目,在bin\debug下多了en文件夹
→主程序区域性设置为en
Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
ResourceManager r = new ResourceManager("ConsoleApplication25.Resource",Assembly.GetExecutingAssembly());
string address = r.GetString("address");
Console.WriteLine("address:" + address);
Console.ReadKey();
→把设置区域性en注释掉,默认是中文
ResourceManager r = new ResourceManager("ConsoleApplication25.Resource",Assembly.GetExecutingAssembly());
string address = r.GetString("address");
Console.WriteLine("address:" + address);
Console.ReadKey();
总结
为什么需要把资源嵌入到程序集?
● 当设计多语言版本的应用程序,可以根据各个国家语言生成对应的资源文件。
● 当资源文件比较大时,把资源文件嵌入到卫星程序集,可以大大减少主程序集的负担。
把资源嵌入到程序集或卫星程序集有几种方式:
1、通过资源文件属性设置
2、通过C#编译器
3、通过.resx资源文件
VS可视化界面中的.resx资源文件和最终生成的.resources资源文件是有区别的:
前者的内容是xml文件。
后者的内容是二进制文件。
参考资料:
※ 《.NET之美》--张子阳,感谢写了这么好的书!