共用方式為


以程式設計方式使用 .resx 檔案

備註

本文適用於 .NET Framework。 如需適用於 .NET 5+ 的資訊(包括 .NET Core),請參閱 .resx 檔案中的資源

因為 XML 資源 (.resx) 檔案必須包含妥善定義的 XML,包括必須遵循特定架構的標頭,後面接著名稱/值組中的數據,您可能會發現手動建立這些檔案是容易出錯的。 或者,您可以使用 .NET 類別庫中的類型和成員,以程序設計方式建立 .resx 檔案。 您也可以使用 .NET 類別庫來擷取儲存在 .resx 檔案中的資源。 本文說明如何使用 命名空間中的 System.Resources 類型和成員來處理 .resx 檔案。

本文討論使用包含資源的 XML (.resx) 檔案。 如需使用已內嵌在元件中的二進位資源檔案的詳細資訊,請參閱 ResourceManager

警告

除了以程序設計方式以外,還有一些使用 .resx 檔案的方法。 當您將資源檔新增至 Visual Studio 專案時,Visual Studio 會提供介面來建立和維護 .resx 檔案,並在編譯時期自動將 .resx 檔案轉換成 .resources 檔案。 您也可以使用文字編輯器直接編輯 .resx 檔案。 不過,若要避免檔案損毀,請小心不要修改儲存在檔案中的任何二進位資訊。

建立 .resx 檔案

您可以依照下列步驟,使用 類別 System.Resources.ResXResourceWriter 以程式設計方式建立 .resx 檔案:

  1. 藉由呼叫 ResXResourceWriter 方法來具現化 ResXResourceWriter(String) 物件,並提供 .resx 檔案的名稱。 檔名必須包含 .resx 擴展名。 如果您在ResXResourceWriter區塊中具現化using物件,則不需要在步驟 3 中明確呼叫ResXResourceWriter.Close方法。

  2. 呼叫ResXResourceWriter.AddResource方法來處理您想要新增到檔案的每個資源。 使用此方法的多載來新增字串、物件和二進位 (位元元組) 資料。 如果資源是 物件,它必須可串行化。

  3. ResXResourceWriter.Close呼叫 方法來產生資源檔,並釋放所有資源。 ResXResourceWriter如果物件是在區塊內using建立的,則會將資源寫入 .resx 檔案,而物件所使用的ResXResourceWriter資源會在區塊結尾using釋放。

產生的 .resx 檔案具有適當的標頭,並對每個由data方法新增的資源加入ResXResourceWriter.AddResource標記。

警告

請勿使用資源檔儲存密碼、安全機密資訊或私用資料。

下列範例會建立名為 CarResources.resx 的 .resx 檔案,其會儲存六個字串、一個圖示,以及兩個應用程式定義的物件(兩 Automobile 個物件)。 在 Automobile 範例中定義和具現化的 類別會以 SerializableAttribute 屬性標記。

using System;
using System.Drawing;
using System.Resources;

[Serializable()] public class Automobile
{
   private string carMake;
   private string carModel;
   private int carYear;
   private int carDoors;
   private int carCylinders;

   public Automobile(string make, string model, int year) :
                     this(make, model, year, 0, 0)
   { }

   public Automobile(string make, string model, int year,
                     int doors, int cylinders)
   {
      this.carMake = make;
      this.carModel = model;
      this.carYear = year;
      this.carDoors = doors;
      this.carCylinders = cylinders;
   }

   public string Make {
      get { return this.carMake; }
   }

   public string Model {
      get {return this.carModel; }
   }

   public int Year {
      get { return this.carYear; }
   }

   public int Doors {
      get { return this.carDoors; }
   }

   public int Cylinders {
      get { return this.carCylinders; }
   }
}

public class Example
{
   public static void Main()
   {
      // Instantiate an Automobile object.
      Automobile car1 = new Automobile("Ford", "Model N", 1906, 0, 4);
      Automobile car2 = new Automobile("Ford", "Model T", 1909, 2, 4);
      // Define a resource file named CarResources.resx.
      using (ResXResourceWriter resx = new ResXResourceWriter(@".\CarResources.resx"))
      {
         resx.AddResource("Title", "Classic American Cars");
         resx.AddResource("HeaderString1", "Make");
         resx.AddResource("HeaderString2", "Model");
         resx.AddResource("HeaderString3", "Year");
         resx.AddResource("HeaderString4", "Doors");
         resx.AddResource("HeaderString5", "Cylinders");
         resx.AddResource("Information", SystemIcons.Information);
         resx.AddResource("EarlyAuto1", car1);
         resx.AddResource("EarlyAuto2", car2);
      }
   }
}
Imports System.Drawing
Imports System.Resources

<Serializable()> Public Class Automobile
    Private carMake As String
    Private carModel As String
    Private carYear As Integer
    Private carDoors AS Integer
    Private carCylinders As Integer

    Public Sub New(make As String, model As String, year As Integer)
        Me.New(make, model, year, 0, 0)
    End Sub

    Public Sub New(make As String, model As String, year As Integer,
                   doors As Integer, cylinders As Integer)
        Me.carMake = make
        Me.carModel = model
        Me.carYear = year
        Me.carDoors = doors
        Me.carCylinders = cylinders
    End Sub

    Public ReadOnly Property Make As String
        Get
            Return Me.carMake
        End Get
    End Property

    Public ReadOnly Property Model As String
        Get
            Return Me.carModel
        End Get
    End Property

    Public ReadOnly Property Year As Integer
        Get
            Return Me.carYear
        End Get
    End Property

    Public ReadOnly Property Doors As Integer
        Get
            Return Me.carDoors
        End Get
    End Property

    Public ReadOnly Property Cylinders As Integer
        Get
            Return Me.carCylinders
        End Get
    End Property
End Class

Module Example
    Public Sub Main()
        ' Instantiate an Automobile object.
        Dim car1 As New Automobile("Ford", "Model N", 1906, 0, 4)
        Dim car2 As New Automobile("Ford", "Model T", 1909, 2, 4)
        ' Define a resource file named CarResources.resx.
        Using resx As New ResXResourceWriter(".\CarResources.resx")
            resx.AddResource("Title", "Classic American Cars")
            resx.AddResource("HeaderString1", "Make")
            resx.AddResource("HeaderString2", "Model")
            resx.AddResource("HeaderString3", "Year")
            resx.AddResource("HeaderString4", "Doors")
            resx.AddResource("HeaderString5", "Cylinders")
            resx.AddResource("Information", SystemIcons.Information)
            resx.AddResource("EarlyAuto1", car1)
            resx.AddResource("EarlyAuto2", car2)
        End Using
    End Sub
End Module

小提示

您也可以使用 Visual Studio 來建立 .resx 檔案。 在編譯時期,Visual Studio 會使用 資源檔產生器 (Resgen.exe) 將 .resx 檔案轉換成二進位資源 (.resources) 檔案,並將它內嵌在應用程式元件或附屬元件中。

您不能將 .resx 檔案嵌入運行時可執行檔,或將它編譯成衛星組件。 您必須使用 資源檔案產生器 (Resgen.exe) 將 .resx 檔案轉換成二進位資源 (.resources) 檔案。 產生的 .resources 檔案接著可以嵌入到應用程式組件或衛星組件中。 如需詳細資訊,請參閱 建立資源檔

列舉資源

在某些情況下,您可能會想要從 .resx 檔案擷取所有資源,而不是特定資源。 若要這樣做,您可以使用 System.Resources.ResXResourceReader 類別,為 .resx 檔案中的所有資源提供列舉值。 類別 System.Resources.ResXResourceReader 實作 IDictionaryEnumerator 方法,該方法返回一個 DictionaryEntry 物件,代表迴圈的每次反覆運算中的特定資源。 其 DictionaryEntry.Key 屬性會傳回資源的索引鍵,而其 DictionaryEntry.Value 屬性會傳回資源的值。

下列範例會針對在上一個 ResXResourceReader 範例中建立的 CarResources.resx 檔案建立 物件,並逐一查看資源檔。 它將資源檔中定義的兩個 Automobile 物件新增至 System.Collections.Generic.List<T> 物件,並將六個字串中的五個新增至 SortedList 物件。 物件中的 SortedList 值會轉換成參數數位,用來向主控台顯示資料行標題。 Automobile屬性值也會顯示至主控台。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Resources;

public class Example
{
   public static void Main()
   {
      string resxFile = @".\CarResources.resx";
      List<Automobile> autos = new List<Automobile>();
      SortedList headers = new SortedList();

      using (ResXResourceReader resxReader = new ResXResourceReader(resxFile))
      {
         foreach (DictionaryEntry entry in resxReader) {
            if (((string) entry.Key).StartsWith("EarlyAuto"))
               autos.Add((Automobile) entry.Value);
            else if (((string) entry.Key).StartsWith("Header"))
               headers.Add((string) entry.Key, (string) entry.Value);
         }
      }
      string[] headerColumns = new string[headers.Count];
      headers.GetValueList().CopyTo(headerColumns, 0);
      Console.WriteLine("{0,-8} {1,-10} {2,-4}   {3,-5}   {4,-9}\n",
                        headerColumns);
      foreach (var auto in autos)
         Console.WriteLine("{0,-8} {1,-10} {2,4}   {3,5}   {4,9}",
                           auto.Make, auto.Model, auto.Year,
                           auto.Doors, auto.Cylinders);
   }
}
// The example displays the following output:
//       Make     Model      Year   Doors   Cylinders
//
//       Ford     Model N    1906       0           4
//       Ford     Model T    1909       2           4
Imports System.Collections
Imports System.Collections.Generic
Imports System.Resources

Module Example
    Public Sub Main()
        Dim resxFile As String = ".\CarResources.resx"
        Dim autos As New List(Of Automobile)
        Dim headers As New SortedList()

        Using resxReader As New ResXResourceReader(resxFile)
            For Each entry As DictionaryEntry In resxReader
                If CType(entry.Key, String).StartsWith("EarlyAuto") Then
                    autos.Add(CType(entry.Value, Automobile))
                Else If CType(entry.Key, String).StartsWith("Header") Then
                    headers.Add(CType(entry.Key, String), CType(entry.Value, String))
                End If
            Next
        End Using
        Dim headerColumns(headers.Count - 1) As String
        headers.GetValueList().CopyTo(headerColumns, 0)
        Console.WriteLine("{0,-8} {1,-10} {2,-4}   {3,-5}   {4,-9}",
                          headerColumns)
        Console.WriteLine()
        For Each auto In autos
            Console.WriteLine("{0,-8} {1,-10} {2,4}   {3,5}   {4,9}",
                              auto.Make, auto.Model, auto.Year,
                              auto.Doors, auto.Cylinders)
        Next
    End Sub
End Module
' The example displays the following output:
'       Make     Model      Year   Doors   Cylinders
'       
'       Ford     Model N    1906       0           4
'       Ford     Model T    1909       2           4

擷取特定資源

除了列舉 .resx 檔案中的專案之外,您還可以使用 System.Resources.ResXResourceSet 類別依名稱擷取特定資源。 方法 ResourceSet.GetString(String) 會擷取具名字符串資源的值。 方法 ResourceSet.GetObject(String) 會擷取具名物件或二進位數據的值。 方法會傳回一個物件,然後必須在 C# 中強制轉型或在 Visual Basic 中轉換為適當類型的物件。

下列範例會依其資源名稱擷取表單的標題字串和圖示。 它也會擷取上一個Automobile範例中使用的應用程式定義DataGridView物件,並在控件中顯示它們。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Resources;
using System.Windows.Forms;

public class CarDisplayApp : Form
{
   private const string resxFile = @".\CarResources.resx";
   Automobile[] cars;

   public static void Main()
   {
      CarDisplayApp app = new CarDisplayApp();
      Application.Run(app);
   }

   public CarDisplayApp()
   {
      // Instantiate controls.
      PictureBox pictureBox = new PictureBox();
      pictureBox.Location = new Point(10, 10);
      this.Controls.Add(pictureBox);
      DataGridView grid = new DataGridView();
      grid.Location = new Point(10, 60);
      this.Controls.Add(grid);

      // Get resources from .resx file.
      using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
      {
         // Retrieve the string resource for the title.
         this.Text = resxSet.GetString("Title");
         // Retrieve the image.
         Icon image = (Icon) resxSet.GetObject("Information", true);
         if (image != null)
            pictureBox.Image = image.ToBitmap();

         // Retrieve Automobile objects.
         List<Automobile> carList = new List<Automobile>();
         string resName = "EarlyAuto";
         Automobile auto;
         int ctr = 1;
         do {
            auto = (Automobile) resxSet.GetObject(resName + ctr.ToString());
            ctr++;
            if (auto != null)
               carList.Add(auto);
         } while (auto != null);
         cars = carList.ToArray();
         grid.DataSource = cars;
      }
   }
}
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Resources
Imports System.Windows.Forms

Public Class CarDisplayApp : Inherits Form
    Private Const resxFile As String = ".\CarResources.resx"
    Dim cars() As Automobile

    Public Shared Sub Main()
        Dim app As New CarDisplayApp()
        Application.Run(app)
    End Sub

    Public Sub New()
        ' Instantiate controls.
        Dim pictureBox As New PictureBox()
        pictureBox.Location = New Point(10, 10)
        Me.Controls.Add(pictureBox)
        Dim grid As New DataGridView()
        grid.Location = New Point(10, 60)
        Me.Controls.Add(grid)

        ' Get resources from .resx file.
        Using resxSet As New ResXResourceSet(resxFile)
            ' Retrieve the string resource for the title.
            Me.Text = resxSet.GetString("Title")
            ' Retrieve the image.
            Dim image As Icon = CType(resxSet.GetObject("Information", True), Icon)
            If image IsNot Nothing Then
                pictureBox.Image = image.ToBitmap()
            End If

            ' Retrieve Automobile objects.  
            Dim carList As New List(Of Automobile)
            Dim resName As String = "EarlyAuto"
            Dim auto As Automobile
            Dim ctr As Integer = 1
            Do
                auto = CType(resxSet.GetObject(resName + ctr.ToString()), Automobile)
                ctr += 1
                If auto IsNot Nothing Then carList.Add(auto)
            Loop While auto IsNot Nothing
            cars = carList.ToArray()
            grid.DataSource = cars
        End Using
    End Sub
End Class

將 .resx 檔案轉換為二進位 .resources 檔案

將 .resx 檔案轉換為內嵌的二進位資源 (.resources) 檔案具有顯著優勢。 雖然 .resx 檔案在應用程式開發期間很容易讀取和維護,但它們很少隨附於已完成的應用程式。 如果它們與應用程式一起散發,它們會以個別檔案的形式存在,除了應用程式可執行檔及其隨附的連結庫。 相反地, .resources 檔案會內嵌在應用程式可執行檔或其隨附元件中。 此外,對於本地化應用程式而言,執行時依賴 .resx 檔案,資源回備的責任則落在開發者身上。 相反地,如果已建立一組包含內嵌 .resources 檔案的衛星組件,Common Language Runtime 就會處理資源回退機制。

若要將 .resx 檔案轉換成 .resources 檔案,請使用 資源文件產生器 (resgen.exe,其具有下列基本語法:

 resgen.exe .resxFilename

結果是二進位資源檔,其根檔名與 .resx 檔案和 .resources 擴展名相同。 接著,此檔案可以在編譯時期編譯成可執行檔或程式庫。 如果您使用 Visual Basic 編譯程式,請使用下列語法在應用程式的可執行檔中內嵌 .resources 檔案:

vbc filename .vb -resource: .resourcesFilename

如果您使用 C#,語法如下所示:

 csc filename .cs -resource: .resourcesFilename

.resources 檔案也可以使用組件連結器(al.exe內嵌在衛星組件中,其基本語法如下:

al resourcesFilename -out: assemblyFilename

另請參閱