如何使用 Visual C# 內嵌和存取資源

如需本文的 Microsoft Visual Basic .NET 版本,請參閱 319291

本文參照下列 Microsoft .NET Framework Class Library 命名空間:
  • System.Reflection
  • System.IO

本文內容

結論
本文將逐步告訴您,如何使用 Visual C# 將資源內嵌為組件的一部分,然後在執行階段存取資源。

回到頁首

概觀

.NET Framework 可以將檔案封裝為編譯組件的一部分。這些檔案也稱為內嵌資源。這些資源完全不同於與組件關聯的資源和 .resx 檔案。您可以透過 System.Reflection 命名空間的 Assembly 類別,在執行階段存取這些資源。

將資源內嵌至資訊清單的主要優點在於,由於檔案屬於編譯組件的一部分,因此使用者不會無意間刪除或錯置應用程式的關鍵檔案,在某些情況中,這種失誤可能會使程式無法執行。這個方法有個限制,那就是您必須重新編譯程式,才能將對這個檔案所做的任何變更儲存至組件。基於這個原因,請僅將在應用程式存留期不會變更的檔案加入做為內嵌資源。

回到頁首

逐步示範

如果要將內嵌資源加入至您的專案,您必須先加入檔案做為專案的一部分。將檔案加入至專案之後,您就可以透過 System.Reflection 命名空間存取和顯示資源。

回到頁首

加入內嵌資源

如果要將文字檔和影像檔加入至專案,做為內嵌資源,請依照下列步驟執行:
  1. 建立新的 Windows 應用程式專案,做為這次示範之用。這個表單是用來顯示可在執行階段從執行中組件存取的資源。
  2. 用滑鼠右鍵按一下專案名稱,按一下 [加入],然後按一下 [加入新項目]
  3. [新增項目] 對話方塊中,從功能表中選取 [文字檔],然後將檔案命名為 MyTextFile.txt。在整合式開發環境 (IDE) 開啟此檔案時,請加入一些文字,然後關閉檔案。
  4. 重複執行步驟 1 和 2,將點陣圖影像加入至專案,但是對於新增項目類型,不要選取 [文字檔],請選取 [點陣圖檔],然後將檔名變更為 MyImage.bmp。在 IDE 開啟此新影像時,請稍微繪製影像,然後關閉檔案。
  5. 用滑鼠右鍵按一下文字檔或點陣圖,然後選取 [屬性]
  6. [屬性] 對話方塊中,找出 [Build Action] 屬性。根據預設,這個屬性是設定為 [Content]。按一下此屬性,然後將 [Build Action] 屬性變更為 [Embedded Resource]
  7. 針對其他檔案重複執行步驟 4 和 5。
下次建置專案時,編譯器會將這些檔案加入至組件。編譯器會將專案的根命名空間加入至資源名稱 (若隨附於專案的話)。例如,如果專案的根命名空間為 MyNamespace,資源就會命名為 MyNamespace.MyTextFile.txt 和 MyNamespace.MyImage.bmp。

注意:資源檔名稱會區分大小寫。當您存取資源時,必須使用完全相符的檔名拼字和大小寫。如果您未使用完全相符的檔名拼字和大小寫,ManifestResourceStream 的方法呼叫就會傳回 Nothing,而且系統不會引發例外狀況。

注意:如果您要驗證資源名稱,可以使用 Microsoft Intermediate Language 反組譯工具 (ILDASM) 來檢視資訊清單資料,其中列出包含的資源。

回到頁首

存取資源

如果要存取已內嵌在組件資訊清單中的資源,請匯入 System.IOSystem.Reflection 命名空間,如下所示:
   using System.IO;   using System.Reflection;				
System.IO 命名空間提供資料流的定義,而 System.Reflection 命名空間會定義 Assembly 類別,此類別會提供方法,以存取內嵌在組件中的資源。

如果您在一般宣告區域宣告下列內容,當載入表單時,程式就會讀取組件中的資源:
   Assembly _assembly;   Stream _imageStream;   StreamReader _textStreamReader;				
注意:如果要在 [程式碼編輯器] 中存取表單的 Load 事件,請按兩下 [設計編輯器] 中的表單。

如果要從正在執行目前程式碼的組件中讀取資源,您必須取得該組件的執行個體。如果要執行這項操作,請使用組件的 GetExecutingAssembly 方法,如下所示:
   _assembly = Assembly.GetExecutingAssembly();				
讀取資源中的資訊是以 GetManifestResourceStream 的方法呼叫來執行。傳遞至這個方法的參數,即為所要存取之資源的名稱。接著,當執行表單的 Load 事件時,程式會將這兩個資源讀取至其對應的資料流。
   _imageStream = _assembly.GetManifestResourceStream("MyNameSpace.MyImage.bmp");   _textStreamReader = new StreamReader(_assembly.GetManifestResourceStream("MyNameSpace.MyTextFile.txt"));				
表單的 Load 事件中的程式碼類似下列:
   try   {      _assembly = Assembly.GetExecutingAssembly();      _imageStream = _assembly.GetManifestResourceStream("MyNamespace.MyImage.bmp");      _textStreamReader = new StreamReader(_assembly.GetManifestResourceStream("MyNamespace.MyTextFile.txt"));   }   catch   {      MessageBox.Show("Error accessing resources!");   }				
Try-Catch 陳述式 (即為 .NET 中的結構化錯誤處理) 可用來攔截當 Assembly 類別的執行個體存取資源時可能發生的任何錯誤。

回到頁首

顯示資源

這個範例使用兩個按鈕來顯示內嵌資源。當您按一下第一個按鈕時,程式就會建立根據從組件讀取而來的資源為基礎的點陣圖影像,並以表單的 PictureBox 控制項顯示點陣圖影像。第二個按鈕會從文字資源讀取,並將文字顯示在文字方塊中。

如果要顯示內嵌資源,請依照下列步驟執行:
  1. 在表單中加入 [PictureBox] 控制項。
  2. 在表單中加入新的 [Button] 控制項,然後將它的 [Text] 屬性變更為 [Show Image]
  3. 按兩下按鈕,在程式碼檢視器中開啟它的 [Click] 事件,然後將下列程式碼貼入這個事件中:
       try   {      pictureBox1.Image = new Bitmap(_imageStream);			       }   catch    {      MessageBox.Show("Error creating image!");   }					
    這個程式碼會產生新的點陣圖執行個體,此執行個體是以在表單 [Load] 事件中讀取到的資源資料流為基礎。

  4. 在表單中加入 [TextBox] 控制項。
  5. 在表單中加入其他 [Button] 控制項,然後將它的 [Text] 屬性變更為 [Get Text]
  6. 按兩下 [設計編輯器] 中的按鈕,以開啟按鈕的 [Click_Event],然後將下列程式碼貼入此事件中:
       try   {      if(_textStreamReader.Peek() != -1)      {         textBox1.Text = _textStreamReader.ReadLine();      }   }   catch   {      MessageBox.Show("Error writing text!");   }					
    這個程式碼會判斷所要讀取的字元是否仍然存在於資料流中。如果找到字元,文字方塊就會讀入一行。

  7. 按下 F5 以執行此應用程式。
回到頁首

完整程式碼

   using System;   using System.Drawing;   using System.Collections;   using System.ComponentModel;   using System.Windows.Forms;   using System.Data;   using System.IO;   using System.Reflection;   namespace MyNamespace   {      /// <summary>      /// Summary description for Form1.      /// </summary>      public class Form1 : System.Windows.Forms.Form      {         private System.Windows.Forms.PictureBox pictureBox1;         private System.Windows.Forms.TextBox textBox1;         private System.Windows.Forms.Button button1;         private System.Windows.Forms.Button button2;         /// <summary>         /// Required designer variable.         /// </summary>         private System.ComponentModel.Container components = null;         public Form1()         {            //             // Required for Windows Form Designer support.            //             InitializeComponent();            //             // TODO: Add any constructor code after InitializeComponent call.            //          }         /// <summary>         /// Clean up any resources being used.         /// </summary>         protected override void Dispose( bool disposing )         {            if( disposing )            {               if (components != null)                {                  components.Dispose();               }            }            base.Dispose( disposing );         }      #region Windows Form Designer generated code         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {            this.pictureBox1 = new System.Windows.Forms.PictureBox();            this.textBox1 = new System.Windows.Forms.TextBox();            this.button1 = new System.Windows.Forms.Button();            this.button2 = new System.Windows.Forms.Button();            this.SuspendLayout();            //             // pictureBox1            //             this.pictureBox1.Location = new System.Drawing.Point(4, 8);            this.pictureBox1.Name = "pictureBox1";            this.pictureBox1.Size = new System.Drawing.Size(284, 192);            this.pictureBox1.TabIndex = 0;            this.pictureBox1.TabStop = false;            //             // textBox1            //             this.textBox1.Location = new System.Drawing.Point(92, 236);            this.textBox1.Name = "textBox1";            this.textBox1.Size = new System.Drawing.Size(192, 20);            this.textBox1.TabIndex = 1;            this.textBox1.Text = "textBox1";            //             // button1            //             this.button1.Location = new System.Drawing.Point(8, 208);            this.button1.Name = "button1";            this.button1.TabIndex = 2;            this.button1.Text = "Show Image";            this.button1.Click += new System.EventHandler(this.button1_Click);            //             // button2            //             this.button2.Location = new System.Drawing.Point(8, 236);            this.button2.Name = "button2";            this.button2.TabIndex = 3;            this.button2.Text = "Get Text";            this.button2.Click += new System.EventHandler(this.button2_Click);            //             // Form1            //             this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);            this.ClientSize = new System.Drawing.Size(292, 266);            this.Controls.AddRange(new System.Windows.Forms.Control[]{                                                                     this.button2,                                                                     this.button1,                                                                     this.textBox1,                                                                     this.pictureBox1});            this.Name = "Form1";            this.Text = "Form1";            this.Load += new System.EventHandler(this.Form1_Load);            this.ResumeLayout(false);         }      #endregion         Assembly _assembly;         Stream _imageStream;         StreamReader _textStreamReader;         /// <summary>         /// The main entry point for the application.         /// </summary>         [STAThread]         static void Main()          {            Application.Run(new Form1());         }         private void Form1_Load(object sender, System.EventArgs e)         {            try            {               _assembly = Assembly.GetExecutingAssembly();               _imageStream = _assembly.GetManifestResourceStream("MyNamespace.MyImage.bmp");              _textStreamReader = new StreamReader(_assembly.GetManifestResourceStream("MyNamespace.MyTextFile.txt"));            }            catch            {               MessageBox.Show("Error accessing resources!");            }		         }         private void button1_Click(object sender, System.EventArgs e)         {            try            {               pictureBox1.Image = new Bitmap(_imageStream);            }            catch             {               MessageBox.Show("Error creating image!");            }         }         private void button2_Click(object sender, System.EventArgs e)         {            try            {               if(_textStreamReader.Peek() != -1)               {                  textBox1.Text = _textStreamReader.ReadLine();               }            }            catch            {               MessageBox.Show("Error writing text!");            }		         }      }   }				
注意 在 Visual Studio 2005 中,程式碼應有所變更。當您建立 Windows Form 專案時,Visual C# 預設會在專案中建立一個表單。這個表單名為 Form1。這兩個表示表單的檔案會命名為 Form1.cs 和 Form1.designer.cs,而您在 Form1.cs 中撰寫程式碼。Designer.cs 檔即為 Windows Form 設計工具寫入程式碼的位置,而所寫入的程式碼會實作您藉由加入控制項來執行的所有動作。如需有關 Visual C# 2005 中的 Windows Forms 設計工具的詳細資訊,請造訪下列 Microsoft 網站:回到頁首

疑難排解

由於資源名稱會區分大小寫,因此,請確認您使用正確的資源名稱拼字和大小寫來存取資源。您可以使用 ILDASM 來讀取資訊清單資料,以確認資源的拼字完全相符。

回到頁首
参考
如需詳細資訊,請參閱下列 Microsoft Developer Network (MSDN) 網站:回到頁首
內容

文章識別碼:319292 - 最後檢閱時間:02/29/2008 09:48:42 - 修訂: 2.10

Microsoft Visual C# .NET 2002 Standard Edition, Microsoft Visual C# 2005 Express Edition

  • kbhowtomaster KB319292
意見反應