다음을 통해 공유


System.Resources.ResourceReader 클래스

이 문서는 이 API에 대한 참조 설명서를 보충하는 추가 설명을 제공합니다.

중요합니다

신뢰할 수 없는 데이터를 사용하여 이 클래스에서 메서드를 호출하는 것은 보안 위험입니다. 신뢰할 수 있는 데이터로만 이 클래스의 메서드를 호출합니다. 자세한 내용은 모든 입력 유효성 검사참조하세요.

ResourceReader 클래스는 IResourceReader 인터페이스의 표준 구현을 제공합니다. ResourceReader 인스턴스는 독립 실행형 .resources 파일 또는 어셈블리에 포함된 .resources 파일을 나타냅니다. .resources 파일에서 리소스를 열거하고 해당 이름/값 쌍을 검색하는 데 사용됩니다. 어셈블리에 포함된 .resources 파일에서 지정된 명명된 리소스를 검색하는 데 사용되는 ResourceManager 클래스와 다릅니다. ResourceManager 클래스는 이름이 미리 알려진 리소스를 검색하는 데 사용되는 반면, ResourceReader 클래스는 컴파일 시간에 개수 또는 정확한 이름을 알 수 없는 리소스를 검색하는 데 유용합니다. 예를 들어 애플리케이션은 리소스 파일을 사용하여 섹션의 섹션 및 항목으로 구성된 구성 정보를 저장할 수 있습니다. 여기서 섹션의 섹션 또는 항목 수는 미리 알 수 없습니다. 그런 다음 Section1, Section1Item1, Section1Item2등과 같이 리소스의 이름을 일반적으로 지정하고 ResourceReader 개체를 사용하여 검색할 수 있습니다.

중요합니다

이 형식은 IDisposable 인터페이스를 구현합니다. 형식 사용을 마쳤으면 직접 또는 간접적으로 삭제해야 합니다. 형식을 직접 삭제하려면 Disposetry/ 블록에서 해당 catch 메서드를 호출합니다. 간접적으로 삭제하려면 using(C#) 또는 Using(Visual Basic)와 같은 언어 구문을 사용합니다. 자세한 내용은 IDisposable 인터페이스 설명서의 "IDisposable을 구현하는 개체 사용" 섹션을 참조하세요.

ResourceReader 개체 인스턴스화

.resources 파일은 Resgen.exe(리소스 파일 생성기)텍스트 파일 또는 XML .resx 파일에서 컴파일된 이진 파일입니다. ResourceReader 개체는 독립 실행형 .resources 파일 또는 어셈블리에 포함된 .resources 파일을 나타낼 수 있습니다.

독립 실행형 .resources 파일에서 읽는 ResourceReader 개체를 인스턴스화하려면 입력 스트림 또는 .resources 파일 이름이 포함된 문자열과 함께 ResourceReader 클래스 생성자를 사용합니다. 다음 예제에서는 두 가지 방법을 모두 보여 줍니다. 첫 번째는 파일 이름을 사용하여 ResourceReader .resources 파일을 나타내는 Resources1.resources 개체를 인스턴스화합니다. 두 번째는 파일에서 만든 스트림을 사용하여 ResourceReader .resources 파일을 나타내는 Resources2.resources 개체를 인스턴스화합니다.

// Instantiate a standalone .resources file from its filename.
var rr1 = new System.Resources.ResourceReader("Resources1.resources");

// Instantiate a standalone .resources file from a stream.
var fs = new System.IO.FileStream(@".\Resources2.resources",
                                  System.IO.FileMode.Open);
var rr2 = new System.Resources.ResourceReader(fs);
' Instantiate a standalone .resources file from its filename.
Dim rr1 As New System.Resources.ResourceReader("Resources1.resources")

' Instantiate a standalone .resources file from a stream.
Dim fs As New System.IO.FileStream(".\Resources2.resources",
                                   System.IO.FileMode.Open)
Dim rr2 As New System.Resources.ResourceReader(fs)

포함된 .resources 파일을 나타내는 ResourceReader 개체를 만들려면 .resources 파일이 포함된 어셈블리에서 Assembly 개체를 인스턴스화합니다. 해당 Assembly.GetManifestResourceStream 메서드는 Stream 생성자에 전달할 수 있는 ResourceReader(Stream) 개체를 반환합니다. 다음 예제에서는 포함된 .resources 파일을 나타내는 ResourceReader 개체를 인스턴스화합니다.

System.Reflection.Assembly assem =
             System.Reflection.Assembly.LoadFrom(@".\MyLibrary.dll");
System.IO.Stream fs =
             assem.GetManifestResourceStream("MyCompany.LibraryResources.resources");
var rr = new System.Resources.ResourceReader(fs);
Dim assem As System.Reflection.Assembly = 
             System.Reflection.Assembly.LoadFrom(".\MyLibrary.dll") 
Dim fs As System.IO.Stream = 
             assem.GetManifestResourceStream("MyCompany.LibraryResources.resources")
Dim rr As New System.Resources.ResourceReader(fs)

ResourceReader 개체의 리소스 열거

.resources 파일에서 리소스를 열거하려면 GetEnumerator 개체를 반환하는 System.Collections.IDictionaryEnumerator 메서드를 호출합니다. IDictionaryEnumerator.MoveNext 메서드를 호출하여 한 리소스에서 다음 리소스로 이동합니다. .resources 파일의 모든 리소스가 열거되면 메서드는 false 반환합니다.

비고

ResourceReader 클래스는 IEnumerable 인터페이스 및 IEnumerable.GetEnumerator 메서드를 구현하지만 ResourceReader.GetEnumerator 메서드는 IEnumerable.GetEnumerator 구현을 제공하지 않습니다. 대신 ResourceReader.GetEnumerator 메서드는 각 리소스의 이름/값 쌍에 대한 액세스를 제공하는 IDictionaryEnumerator 인터페이스 개체를 반환합니다.

다음 두 가지 방법으로 컬렉션의 개별 리소스를 검색할 수 있습니다.

  • System.Collections.IDictionaryEnumerator 컬렉션의 각 리소스를 반복하고 System.Collections.IDictionaryEnumerator 속성을 사용하여 리소스 이름과 값을 검색할 수 있습니다. 모든 리소스가 동일한 형식이거나 각 리소스의 데이터 형식을 알고 있는 경우 이 기술을 사용하는 것이 좋습니다.

  • System.Collections.IDictionaryEnumerator 컬렉션을 반복하고 GetResourceData 메서드를 호출하여 리소스의 데이터를 검색할 때 각 리소스의 이름을 검색할 수 있습니다. 데이터 형식을 알지 못하거나 이전 방법에서 예외가 발생할 경우 이 방식을 사용하는 것이 좋습니다.

IDictionaryEnumerator 속성을 사용하여 리소스 검색

.resources 파일에서 리소스를 열거하는 첫 번째 방법은 각 리소스의 이름/값 쌍을 직접 검색하는 것입니다. IDictionaryEnumerator.MoveNext 메서드를 호출하여 컬렉션의 각 리소스로 이동한 후 IDictionaryEnumerator.Key 속성에서 리소스 이름과 IDictionaryEnumerator.Value 속성의 리소스 데이터를 검색할 수 있습니다.

다음 예제에서는 IDictionaryEnumerator.KeyIDictionaryEnumerator.Value 속성을 사용하여 .resources 파일에서 각 리소스의 이름과 값을 검색하는 방법을 보여 줍니다. 예제를 실행하려면 문자열 리소스를 정의하기 위해 ApplicationResources.txt이라는 다음 텍스트 파일을 만듭니다.

Title="Contact Information"
Label1="First Name:"
Label2="Middle Name:"
Label3="Last Name:"
Label4="SSN:"
Label5="Street Address:"
Label6="City:"
Label7="State:"
Label8="Zip Code:"
Label9="Home Phone:"
Label10="Business Phone:"
Label11="Mobile Phone:"
Label12="Other Phone:"
Label13="Fax:"
Label14="Email Address:"
Label15="Alternate Email Address:"

그런 다음, 다음 명령을 사용하여 텍스트 리소스 파일을 ApplicationResources.resources라는 이진 파일로 변환할 수 있습니다.

resgen ApplicationResources.txt

다음 예제에서는 ResourceReader 클래스를 사용하여 독립 실행형 이진 .resources 파일의 각 리소스를 열거하고 해당 키 이름과 해당 값을 표시합니다.

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

public class Example1
{
   public static void Run()
   {
      Console.WriteLine("Resources in ApplicationResources.resources:");
      ResourceReader res = new ResourceReader(@".\ApplicationResources.resources");
      IDictionaryEnumerator dict = res.GetEnumerator();
      while (dict.MoveNext())
         Console.WriteLine($"   {dict.Key}: '{dict.Value}' (Type {dict.Value.GetType().Name})");
      res.Close();
   }
}
// The example displays the following output:
//       Resources in ApplicationResources.resources:
//          Label3: '"Last Name:"' (Type String)
//          Label2: '"Middle Name:"' (Type String)
//          Label1: '"First Name:"' (Type String)
//          Label7: '"State:"' (Type String)
//          Label6: '"City:"' (Type String)
//          Label5: '"Street Address:"' (Type String)
//          Label4: '"SSN:"' (Type String)
//          Label9: '"Home Phone:"' (Type String)
//          Label8: '"Zip Code:"' (Type String)
//          Title: '"Contact Information"' (Type String)
//          Label12: '"Other Phone:"' (Type String)
//          Label13: '"Fax:"' (Type String)
//          Label10: '"Business Phone:"' (Type String)
//          Label11: '"Mobile Phone:"' (Type String)
//          Label14: '"Email Address:"' (Type String)
//          Label15: '"Alternate Email Address:"' (Type String)
Imports System.Collections
Imports System.Resources

Module Example2
    Public Sub Main()
        Console.WriteLine("Resources in ApplicationResources.resources:")
        Dim res As New ResourceReader(".\ApplicationResources.resources")
        Dim dict As IDictionaryEnumerator = res.GetEnumerator()
        Do While dict.MoveNext()
            Console.WriteLine("   {0}: '{1}' (Type {2})", dict.Key, dict.Value, dict.Value.GetType().Name)
        Loop
        res.Close()
    End Sub
End Module
' The example displays output like the following:
'       Resources in ApplicationResources.resources:
'          Label3: '"Last Name:"' (Type String)
'          Label2: '"Middle Name:"' (Type String)
'          Label1: '"First Name:"' (Type String)
'          Label7: '"State:"' (Type String)
'          Label6: '"City:"' (Type String)
'          Label5: '"Street Address:"' (Type String)
'          Label4: '"SSN:"' (Type String)
'          Label9: '"Home Phone:"' (Type String)
'          Label8: '"Zip Code:"' (Type String)
'          Title: '"Contact Information"' (Type String)
'          Label12: '"Other Phone:"' (Type String)
'          Label13: '"Fax:"' (Type String)
'          Label10: '"Business Phone:"' (Type String)
'          Label11: '"Mobile Phone:"' (Type String)
'          Label14: '"Email Address:"' (Type String)
'          Label15: '"Alternate Email Address:"' (Type String)

IDictionaryEnumerator.Value 속성에서 리소스 데이터를 검색하려고 하면 다음과 같은 예외가 발생할 수 있습니다.

일반적으로 .resources 파일이 수동으로 수정되었거나, 형식이 정의된 어셈블리가 애플리케이션에 포함되지 않았거나 실수로 삭제되었거나, 어셈블리가 형식보다 이전 버전인 경우 이러한 예외가 throw됩니다. 이러한 예외 중 하나가 throw되면 다음 섹션과 같이 각 리소스를 열거하고 GetResourceData 메서드를 호출하여 리소스를 검색할 수 있습니다. 이 방법은 IDictionaryEnumerator.Value 속성이 반환하려고 시도한 데이터 형식에 대한 몇 가지 정보를 제공합니다.

GetResourceData를 사용하여 이름으로 리소스 검색

.resources 파일에서 리소스를 열거하는 두 번째 방법은 IDictionaryEnumerator.MoveNext 메서드를 호출하여 파일의 리소스를 탐색하는 작업도 포함합니다. 각 리소스에 대해 IDictionaryEnumerator.Key 속성에서 리소스의 이름을 검색한 다음 GetResourceData(String, String, Byte[]) 메서드에 전달하여 리소스의 데이터를 검색합니다. 이 값은 resourceData 인수에서 바이트 배열로 반환됩니다.

이 방법은 리소스 값을 형성하는 실제 바이트를 반환하기 때문에 IDictionaryEnumerator.KeyIDictionaryEnumerator.Value 속성에서 리소스 이름과 값을 검색하는 것보다 더 어색합니다. 그러나 리소스를 검색하려고 하면 예외가 throw되는 경우 GetResourceData 메서드는 리소스의 데이터 형식에 대한 정보를 제공하여 예외의 원본을 식별하는 데 도움이 될 수 있습니다. 리소스의 데이터 형식을 나타내는 문자열에 대한 자세한 내용은 GetResourceData참조하세요.

다음 예제에서는 이 방법을 사용하여 리소스를 검색하고 throw되는 예외를 처리하는 방법을 보여 줍니다. 프로그래밍적으로 4개의 문자열, 1개의 부울, 1개의 정수, 1개의 비트맵이 포함된 .resources 이진 파일을 만듭니다. 예제를 실행하려면 다음을 수행합니다.

  1. ContactResources.resources라는 .resources 파일을 만드는 다음 소스 코드를 컴파일하고 실행합니다.

    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Resources;
    using System.Runtime.Versioning;
    
    public class Example5
    {
        [SupportedOSPlatform("windows")]
        public static void Run()
        {
            // Bitmap as stream.
            MemoryStream bitmapStream = new MemoryStream();
            Bitmap bmp = new Bitmap(@".\ContactsIcon.jpg");
            bmp.Save(bitmapStream, ImageFormat.Jpeg);
    
            // Define resources to be written.
            using (ResourceWriter rw = new ResourceWriter(@".\ContactResources.resources"))
            {
                rw.AddResource("Title", "Contact List");
                rw.AddResource("NColumns", 5);
                rw.AddResource("Icon", bitmapStream);
                rw.AddResource("Header1", "Name");
                rw.AddResource("Header2", "City");
                rw.AddResource("Header3", "State");
                rw.AddResource("ClientVersion", true);
                rw.Generate();
            }
        }
    }
    

    소스 코드 파일의 이름은 CreateResources.cs. 다음 명령을 사용하여 C#에서 컴파일할 수 있습니다.

    csc CreateResources.cs /r:library.dll
    
  2. 다음 코드를 컴파일하고 실행하여 ContactResources.resources 파일의 리소스를 열거합니다.

    using System;
    using System.Collections;
    using System.Drawing;
    using System.IO;
    using System.Resources;
    using System.Runtime.Versioning;
    
    public class Example6
    {
        [SupportedOSPlatform("windows")]
        public static void Run()
        {
            ResourceReader rdr = new ResourceReader(@".\ContactResources.resources");
            IDictionaryEnumerator dict = rdr.GetEnumerator();
            while (dict.MoveNext())
            {
                Console.WriteLine($"Resource Name: {dict.Key}");
                try
                {
                    Console.WriteLine($"   Value: {dict.Value}");
                }
                catch (FileNotFoundException)
                {
                    Console.WriteLine("   Exception: A file cannot be found.");
                    DisplayResourceInfo(rdr, (string)dict.Key, false);
                }
                catch (FormatException)
                {
                    Console.WriteLine("   Exception: Corrupted data.");
                    DisplayResourceInfo(rdr, (string)dict.Key, true);
                }
                catch (TypeLoadException)
                {
                    Console.WriteLine("   Exception: Cannot load the data type.");
                    DisplayResourceInfo(rdr, (string)dict.Key, false);
                }
            }
        }
    
        [SupportedOSPlatform("windows")]
        private static void DisplayResourceInfo(ResourceReader rr,
                                        string key, bool loaded)
        {
            string dataType = null;
            byte[] data = null;
            rr.GetResourceData(key, out dataType, out data);
    
            // Display the data type.
            Console.WriteLine($"   Data Type: {dataType}");
            // Display the bytes that form the available data.      
            Console.Write("   Data: ");
            int lines = 0;
            foreach (var dataItem in data)
            {
                lines++;
                Console.Write("{0:X2} ", dataItem);
                if (lines % 25 == 0)
                    Console.Write("\n         ");
            }
            Console.WriteLine();
            // Try to recreate current state of data.
            // Do: Bitmap, DateTimeTZI
            switch (dataType)
            {
                // Handle internally serialized string data (ResourceTypeCode members).
                case "ResourceTypeCode.String":
                    BinaryReader reader = new BinaryReader(new MemoryStream(data));
                    string binData = reader.ReadString();
                    Console.WriteLine($"   Recreated Value: {binData}");
                    break;
                case "ResourceTypeCode.Int32":
                    Console.WriteLine($"   Recreated Value: {BitConverter.ToInt32(data, 0)}");
                    break;
                case "ResourceTypeCode.Boolean":
                    Console.WriteLine($"   Recreated Value: {BitConverter.ToBoolean(data, 0)}");
                    break;
                // .jpeg image stored as a stream.
                case "ResourceTypeCode.Stream":
                    const int OFFSET = 4;
                    int size = BitConverter.ToInt32(data, 0);
                    Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
                    Console.WriteLine($"   Recreated Value: {value1}");
                    break;
                default:
                    break;
            }
            Console.WriteLine();
        }
    }
    

    소스 코드를 수정한 후(예: FormatException 블록 끝에 try 의도적으로 throw) 예제를 실행하여 GetResourceData 호출을 통해 일부 리소스 정보를 검색하거나 다시 만드는 방법을 확인할 수 있습니다.