.NET(C#):淺談資訊清單資源和RESX資源

來源:互聯網
上載者:User

 

目錄

  • 資訊清單資源
  • 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檔案和資訊清單資源有更好的理解!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.