다음을 통해 공유


프로그래밍 방식으로 .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 인스턴스화하는 경우 3단계에서 using 메서드를 ResXResourceWriter.Close 명시적으로 호출할 필요가 없습니다.

  2. ResXResourceWriter.AddResource 파일에 추가하려는 각 리소스에 대한 메서드를 호출합니다. 이 메서드의 오버로드를 사용하여 문자열, 개체 및 이진(바이트 배열) 데이터를 추가합니다. 리소스가 개체인 경우 직렬화할 수 있어야 합니다.

  3. 메서드를 ResXResourceWriter.Close 호출하여 리소스 파일을 생성하고 모든 리소스를 해제합니다. ResXResourceWriter 개체가 using 블록 내에서 생성된 경우, 리소스는 .resx 파일에 기록되고, ResXResourceWriter 개체가 사용하는 리소스는 using 블록의 끝에서 해제됩니다.

결과 .resx 파일에는 메서드에서 추가한 각 리소스에 대해 적절한 헤더와 data 태그가 있으며, ResXResourceWriter.AddResource 메서드에 의해 추가된 것입니다.

경고

암호, 보안이 중요한 정보 또는 개인 데이터를 저장할 때는 리소스 파일을 사용하지 마세요.

다음 예제에서는 6개의 문자열, 아이콘 및 두 개의 애플리케이션 정의 개체(두 Automobile 개체)를 저장하는 CarResources.resx라는 .resx 파일을 만듭니다. 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 파일에서 특정 리소스 대신 모든 리소스를 검색할 수 있습니다. 이렇게 하려면 .resx 파일의 System.Resources.ResXResourceReader 모든 리소스에 대한 열거자를 제공하는 클래스를 사용할 수 있습니다. 클래스 System.Resources.ResXResourceReaderIDictionaryEnumerator을 구현하며, 이 구현은 루프의 각 반복에서 특정 리소스를 나타내는 DictionaryEntry 객체를 반환합니다. 해당 속성은 DictionaryEntry.Key 리소스의 키를 반환하고 해당 DictionaryEntry.Value 속성은 리소스의 값을 반환합니다.

다음 예제에서는 이전 예제에서 만든 CarResources.resx 파일에 대한 ResXResourceReader 개체를 생성하고 리소스 파일을 순회합니다. 리소스 파일에 정의된 두 Automobile 개체를 개체에 System.Collections.Generic.List<T> 추가하고 6개의 문자열 중 5개를 개체에 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 파일이 포함된 위성 어셈블리 집합이 만들어진 경우 공용 언어 런타임은 리소스 대체 프로세스를 처리합니다.

.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

참고하십시오