Compartilhar via


Trabalhar com arquivos .resx de forma programática

Observação

Este artigo se aplica ao .NET Framework. Para obter informações que se aplicam ao .NET 5+ (incluindo o .NET Core), consulte Recursos em arquivos .resx.

Como os arquivos de recurso XML (.resx) devem consistir em XML bem definido, incluindo um cabeçalho que deve seguir um esquema específico seguido de dados em pares nome/valor, você pode descobrir que criar esses arquivos manualmente é propenso a erros. Como alternativa, você pode criar arquivos .resx programaticamente usando tipos e membros na Biblioteca de Classes do .NET. Você também pode usar a Biblioteca de Classes do .NET para recuperar recursos armazenados em arquivos .resx. Este artigo explica como você pode usar os tipos e membros no System.Resources namespace para trabalhar com arquivos .resx.

Este artigo discute como trabalhar com arquivos XML (.resx) que contêm recursos. Para obter informações sobre como trabalhar com arquivos de recursos binários que foram inseridos em assemblies, consulte ResourceManager.

Aviso

Também há maneiras de trabalhar com arquivos .resx diferentes de programaticamente. Quando você adiciona um arquivo de recurso a um projeto do Visual Studio , o Visual Studio fornece uma interface para criar e manter um arquivo .resx e converte automaticamente o arquivo .resx em um arquivo .resources em tempo de compilação. Você também pode usar um editor de texto para manipular um arquivo .resx diretamente. No entanto, para evitar corromper o arquivo, tenha cuidado para não modificar nenhuma informação binária armazenada no arquivo.

Criar um arquivo .resx

Você pode usar a System.Resources.ResXResourceWriter classe para criar um arquivo .resx programaticamente seguindo estas etapas:

  1. Instancie um ResXResourceWriter objeto chamando o ResXResourceWriter(String) método e fornecendo o nome do arquivo .resx. O nome do arquivo deve incluir a extensão .resx. Se você instanciar o ResXResourceWriter objeto em um using bloco, não precisará chamar explicitamente o ResXResourceWriter.Close método na etapa 3.

  2. Chame o ResXResourceWriter.AddResource método para cada recurso que você deseja adicionar ao arquivo. Use as sobrecargas desse método para adicionar cadeia de caracteres, objetos e dados binários (matriz de bytes). Se o recurso for um objeto, ele deverá ser serializável.

  3. Chame o ResXResourceWriter.Close método para gerar o arquivo de recurso e liberar todos os recursos. Se o ResXResourceWriter objeto tiver sido criado em um using bloco, os recursos serão gravados no arquivo .resx e os recursos usados pelo ResXResourceWriter objeto serão liberados no final do using bloco.

O arquivo .resx resultante tem o cabeçalho apropriado e uma data marca para cada recurso adicionado pelo ResXResourceWriter.AddResource método.

Aviso

Não use arquivos de recurso para armazenar senhas, informações confidenciais ou dados privados.

O exemplo a seguir cria um arquivo .resx chamado CarResources.resx que armazena seis cadeias de caracteres, um ícone e dois objetos definidos pelo aplicativo (dois Automobile objetos). A Automobile classe, que é definida e instanciada no exemplo, é marcada com o SerializableAttribute atributo.

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

Dica

Você também pode usar o Visual Studio para criar arquivos .resx. No tempo de compilação, o Visual Studio usa o Gerador de Arquivos de Recurso (Resgen.exe) para converter o arquivo .resx em um arquivo de recurso binário (.resources) e também o insere em um assembly de aplicativo ou em um assembly satélite.

Não é possível inserir um arquivo .resx em um executável do runtime ou compilá-lo em um assembly satélite. Você deve converter seu arquivo .resx em um arquivo de recurso binário (.resources) usando o Gerador de Arquivos de Recurso (Resgen.exe). O arquivo .resources resultante poderá então ser inserido em um assembly de aplicativo ou um assembly satélite. Para obter mais informações, consulte Criar arquivos de recurso.

Enumerar recursos

Em alguns casos, talvez você queira recuperar todos os recursos, em vez de um recurso específico, de um arquivo .resx. Para fazer isso, você pode usar a System.Resources.ResXResourceReader classe, que fornece um enumerador para todos os recursos no arquivo .resx. A System.Resources.ResXResourceReader classe implementa IDictionaryEnumerator, que retorna um DictionaryEntry objeto que representa um recurso específico para cada iteração do loop. Sua DictionaryEntry.Key propriedade retorna a chave do recurso e sua DictionaryEntry.Value propriedade retorna o valor do recurso.

O exemplo a seguir cria um ResXResourceReader objeto para o arquivo CarResources.resx criado no exemplo anterior e itera por meio do arquivo de recurso. Ele adiciona os dois Automobile objetos definidos no arquivo de recurso a um System.Collections.Generic.List<T> objeto e adiciona cinco das seis cadeias de caracteres a um SortedList objeto. Os valores no SortedList objeto são convertidos em uma matriz de parâmetros, que é usada para exibir títulos de coluna no console. Os valores da propriedade Automobile também são exibidos no console.

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

Recuperar um recurso específico

Além de enumerar os itens em um arquivo .resx, você pode recuperar um recurso específico pelo nome usando a System.Resources.ResXResourceSet classe. O ResourceSet.GetString(String) método recupera o valor de um recurso de cadeia de caracteres nomeado. O ResourceSet.GetObject(String) método recupera o valor de um objeto nomeado ou dados binários. O método retorna um objeto que deve ser convertido (em C# ou no Visual Basic) em um objeto do tipo apropriado.

O exemplo a seguir recupera o ícone e a cadeia de caracteres de legenda de um formulário pelos nomes dos recursos. Ele também recupera os objetos definidos Automobile pelo aplicativo usados no exemplo anterior e os exibe em um DataGridView controle.

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

Converter arquivos .resx em arquivos .resources binários

A conversão de arquivos .resx em arquivos de recurso binário inserido (.resources) tem vantagens significativas. Embora os arquivos .resx sejam fáceis de ler e manter durante o desenvolvimento de aplicativos, eles raramente são incluídos com aplicativos concluídos. Se eles forem distribuídos com um aplicativo, eles existirão como arquivos separados, além do executável do aplicativo e de suas bibliotecas que acompanham. Por outro lado, os arquivos .resources são inseridos no executável do aplicativo ou em seus assemblies auxiliares. Além disso, para aplicativos localizados, contar com arquivos .resx no runtime coloca a responsabilidade de lidar com o fallback de recursos no desenvolvedor. Por outro lado, se um conjunto de assemblies de satélite que contêm arquivos .resources inseridos tiver sido criado, o Common Language Runtime manipula o processo de fallback de recurso.

Para converter um arquivo .resx em um arquivo .resources , use o Gerador de Arquivos de Recurso (resgen.exe), que tem a seguinte sintaxe básica:

 resgen.exe .resxFilename

O resultado é um arquivo de recurso binário que tem o mesmo nome de arquivo raiz que o arquivo .resx e uma extensão de arquivo .resources. Em seguida, esse arquivo pode ser compilado em um executável ou em uma biblioteca no momento da compilação. Se você estiver usando o compilador do Visual Basic, use a seguinte sintaxe para inserir um arquivo .resources no executável de um aplicativo:

vbc filename .vb -resource: .resourcesFilename

Se você estiver usando C#, a sintaxe será a seguinte:

 csc filename .cs -resource: .resourcesFilename

O arquivo .resources também pode ser incorporado em um assembly de satélite usando Assembly Linker (al.exe), que tem a seguinte sintaxe básica:

al resourcesFilename -out: assemblyFilename

Consulte também