.NET(C#):浅谈程序集清单资源和RESX资源
?
目錄
- 程序集清單資源
- RESX資源文件
- 使用ResourceReader和ResourceSet解析二進制資源文件
- 使用ResourceManager解析二進制資源文件
- 小看RESX資源文件的Designer.cs文件
?
?
返回目錄程序集清單資源
在程序集中嵌入資源的最簡單方法是什么?那就是使用Visual Studio中的“嵌入式資源(Embedded Resource)”創建選項,相當于使用csc的”/resource”參數。具體步驟,首先在Visual Studio的工程中選擇資源文件,然后選擇“屬性”,接著在屬性框中的Build Action中選擇Embedded Resource,如下圖,把a.file作為資源文件。
?
這個a.file成為嵌入資源后,它將會作為清單資源(Manifest Resource)存入程序集清單中(Assembly Manifest):
?
程序集清單是程序集不可缺少的元素,上圖來自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文件,再添加一個字符串,隨便寫個名稱。
?
完成后,你會發現工程里多了些文件:
?
a.file是上面我們手動加的程序集清單資源。而Resource1.resx中的文件被存到了一個叫Resources的文件夾內(圖中的b.file)。
?
檢查這兩個文件的屬性中的Build Action,你會發現,Resources內的文件的Build Action都是None,VS不會對他們進行任何操作的,就好像他們不在工程里似的。而RESX文件的Build Action則是Embedded Resource,它會成為程序員清單資源,不同于不同程序集清單資源,RESX在編譯時下面的Custom Tool是一個叫ResXFileCodeGenerator的工具:
?
這個工具會把所有RESX的資源連起來創建成一個二進制文件,VS最后把這個生成的文件最終作為程序集清單資源文件保存到程序集中。這個二進制資源文件的擴展名是.resources。
?
此時再運行上面講的Assembly.GetManifestResourceNames方法來枚舉程序集清單資源文件,輸出會成:
Mgen.a.file
Mgen.Resource1.resources
?
Resource1.resx文件會最終編譯成Mgen.Resource1.resources資源文件。
整個過程可以看這張圖:
?
?
返回目錄使用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文件。
?
它定義了資源讀取的一個類,比如資源文件名稱是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文件和程序集清單資源有更好的理解!
posted on 2014-04-03 00:53 NET未來之路 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/lonelyxmas/p/3642025.html
總結
以上是生活随笔為你收集整理的.NET(C#):浅谈程序集清单资源和RESX资源的全部內容,希望文章能夠幫你解決所遇到的問題。