Search code examples
.netvisual-studiostreamreaderembedded-resource

How to read embedded resource text file


How do I read an embedded resource (text file) using StreamReader and return it as a string? My current script uses a Windows form and textbox that allows the user to find and replace text in a text file that is not embedded.

private void button1_Click(object sender, EventArgs e)
{
    StringCollection strValuesToSearch = new StringCollection();
    strValuesToSearch.Add("Apple");
    string stringToReplace;
    stringToReplace = textBox1.Text;

    StreamReader FileReader = new StreamReader(@"C:\MyFile.txt");
    string FileContents;
    FileContents = FileReader.ReadToEnd();
    FileReader.Close();
    foreach (string s in strValuesToSearch)
    {
        if (FileContents.Contains(s))
            FileContents = FileContents.Replace(s, stringToReplace);
    }
    StreamWriter FileWriter = new StreamWriter(@"MyFile.txt");
    FileWriter.Write(FileContents);
    FileWriter.Close();
}

Solution

  • You can use the Assembly.GetManifestResourceStream Method:

    1. Add the following usings

       using System.IO;
       using System.Reflection;
      
    2. Set property of relevant file:
      Parameter Build Action with value Embedded Resource

    3. Use the following code

       var assembly = Assembly.GetExecutingAssembly();
       var resourceName = "MyCompany.MyProduct.MyFile.txt";
      
       using (Stream stream = assembly.GetManifestResourceStream(resourceName))
       using (StreamReader reader = new StreamReader(stream))
       {
           string result = reader.ReadToEnd();
       }
      

      resourceName is the name of one of the resources embedded in assembly. For example, if you embed a text file named "MyFile.txt" that is placed in the root of a project with default namespace "MyCompany.MyProduct", then resourceName is "MyCompany.MyProduct.MyFile.txt". You can get a list of all resources in an assembly using the Assembly.GetManifestResourceNames Method.


    A no brainer astute to get the resourceName from the file name only (by pass the namespace stuff):

    string resourceName = assembly.GetManifestResourceNames()
      .Single(str => str.EndsWith("YourFileName.txt"));
    

    A complete example:

    public string ReadResource(string name)
    {
        // Determine path
        var assembly = Assembly.GetExecutingAssembly();
        string resourcePath = name;
        // Format: "{Namespace}.{Folder}.{filename}.{Extension}"
        if (!name.StartsWith(nameof(SignificantDrawerCompiler)))
        {
            resourcePath = assembly.GetManifestResourceNames()
                .Single(str => str.EndsWith(name));
        }
    
        using (Stream stream = assembly.GetManifestResourceStream(resourcePath))
        using (StreamReader reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }
    

    or as an async extension method:

    internal static class AssemblyExtensions
    {
        public static async Task<string> ReadResourceAsync(this Assembly assembly, string name)
        {
            // Determine path
            string resourcePath = name;
            // Format: "{Namespace}.{Folder}.{filename}.{Extension}"
            if (!name.StartsWith(nameof(SignificantDrawerCompiler)))
            {
                resourcePath = assembly.GetManifestResourceNames()
                    .Single(str => str.EndsWith(name));
            }
    
            using Stream stream = assembly.GetManifestResourceStream(resourcePath)!;
            using StreamReader reader = new(stream);
            return await reader.ReadToEndAsync();
        }
    }
    
    // Usage
    string resourceText = await Assembly.GetExecutingAssembly().ReadResourceAsync("myResourceName");