How to read embedded resource text file

704,092

Solution 1

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();
    }
}

Solution 2

You can add a file as a resource using two separate methods.

The C# code required to access the file is different, depending on the method used to add the file in the first place.

Method 1: Add existing file, set property to Embedded Resource

Add the file to your project, then set the type to Embedded Resource.

NOTE: If you add the file using this method, you can use GetManifestResourceStream to access it (see answer from @dtb).

enter image description here

Method 2: Add file to Resources.resx

Open up the Resources.resx file, use the dropdown box to add the file, set Access Modifier to public.

NOTE: If you add the file using this method, you can use Properties.Resources to access it (see answer from @Night Walker).

enter image description here

Solution 3

Basically, you use System.Reflection to get a reference to the current Assembly. Then, you use GetManifestResourceStream().

Example, from the page I posted:

Note: need to add using System.Reflection; for this to work

   Assembly _assembly;
   StreamReader _textStreamReader;
   try
   {
      _assembly = Assembly.GetExecutingAssembly();
      _textStreamReader = new StreamReader(_assembly.GetManifestResourceStream("MyNamespace.MyTextFile.txt"));
   }
   catch
   {
      MessageBox.Show("Error accessing resources!");
   }

Solution 4

In Visual Studio you can directly embed access to a file resource via the Resources tab of the Project properties ("Analytics" in this example). visual studio screen shot - Resources tab

The resulting file can then be accessed as a byte array by

byte[] jsonSecrets = GoogleAnalyticsExtractor.Properties.Resources.client_secrets_reporter;

Should you need it as a stream, then ( from https://stackoverflow.com/a/4736185/432976 )

Stream stream = new MemoryStream(jsonSecrets)

Solution 5

When you added the file to the resources, you should select its Access Modifiers as public than you can make something like following.

byte[] clistAsByteArray = Properties.Resources.CLIST01;

CLIST01 is the name of the embedded file.

Actually you can go to the resources.Designer.cs and see what is the name of the getter.

Share:
704,092
Me.Close
Author by

Me.Close

Updated on October 23, 2021

Comments

  • Me.Close
    Me.Close over 1 year

    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();
    }
    
  • Me.Close
    Me.Close over 12 years
    Great, thanks man. I had a second question regarding the save path, how would I specify it so it would save it to the desktop on any computer which would perhaps have different directory structure?
  • adrianbanks
    adrianbanks over 12 years
    @Me.Close: Have a look at Environment.SpecialFolder to get the desktop folder. You need to bear in mind that the resource will be namespaced based on its path within the project, so its name may not be just file1.txt.
  • Kirk Broadhurst
    Kirk Broadhurst over 11 years
    +1 For including the namespace as part of the resource name
  • Oscar Foley
    Oscar Foley over 11 years
    var auxList= System.Reflection.Assembly.GetExecutingAssembly().GetManifes‌​tResourceNames(); This method could be very useful when you want to learn the exact resource name. (Taken from question stackoverflow.com/questions/27757/…)
  • JYelton
    JYelton almost 11 years
    The argument for GetManifestResourceStream needs the path as @adrian indicates. If it helps anyone, that path is like what @SimpleCoder shows in the example: MyNamespace.Filename.Ext. I had previously tried MyNamespace.Resources.Filename.Ext but that results in a null.
  • Suzanne Soy
    Suzanne Soy almost 10 years
    Could you please explain this more? When i right-click->properties on a file in the solution explorer, and then set Action to Incorporated ressource, I don't have any Access Modifiers field in the properties panel. Also, I don't have a Propersites.Resources class, I get a The name 'Properties' does not exist in the current context error when compiling your code.
  • Sasha
    Sasha over 9 years
    If you have your resource not directly in the project root, but in some subfolder, don't forget to put this folder name in resourceName as well (e.g. "MyProjectNameSpace.MyProjectSubFolder.FileName.FileExtentio‌​n")
  • ouflak
    ouflak over 9 years
    You can also use this with a text file, in which case you would have: string jsonSecrets = YourNameSpace.Properties.Resources.YourFileName;
  • v.oddou
    v.oddou over 9 years
    that's weird for me Properties.Resources.myfile happens to be directly a string and usable in code.
  • Timmerz
    Timmerz about 9 years
    are you sure about that? according this this link it looks like I am....stackoverflow.com/questions/1065168/…
  • Contango
    Contango over 8 years
    This will only work if you embed the file into Resources.resx, see my answer on the different methods to embed files into a project.
  • Illidan
    Illidan about 8 years
    Worth to say that resource "Build Action" has to be set as "Embedded Resource"
  • Contango
    Contango over 7 years
    A third method is to add the file to the project, then set "Copy to Output Directory" to "True". On compile, the file is copied into the output dir, and you can read the file using normal means. Example: in a WPF app when you want to display an image.
  • Felix Keil
    Felix Keil over 7 years
    Sorry. This is wrong. Dots work. (at least it worked for me, NET4.5) I don't know why you had this bug.
  • Peter Gfader
    Peter Gfader over 7 years
    Yes they work but they act as Directory separator. Templates.plainEmailBodyTemplate.en.txt will look for "\Templates\plainEmailBodyTemplate\en.txt" resource
  • Felix Keil
    Felix Keil over 7 years
    No. I tried it. GetManifestResourceStream can access embedded resources with more than one dot in the filename. (NET4.5)
  • Nicolas Fall
    Nicolas Fall over 7 years
    so setting the build action to Resource does nothing that allows you to read out the item as a resource? you have to use EmbeddedResource or add to a Resources.resx file?
  • Contango
    Contango over 7 years
    @Maslow Setting the build action to 'Resource' creates a linked resource, whereas setting the build action to 'Embedded Resource' compiles the resource into the output assembly. The term 'linked resource' is a fancy term for 'copy the file into the output directory on compile' (you can then read the file at runtime using any normal method). For more on the difference between these two types, see Adding and Editing Resources (Visual C#) at msdn.microsoft.com/en-us/library/7k989cfy(v=vs.90).aspx.
  • Kinetic
    Kinetic about 7 years
    One important point not covered here. If you saved your file as an alternative encoding type to cope with odd characters (in my case UTF8), you may get an empty file back when you read the stream. Fix this by specifying the encoding type in the constructor of the stream reader: using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
  • ff8mania
    ff8mania about 7 years
    I did it in a dll (not an executable) and stream is always empty. Do I have to use the signature with the explicit type?
  • Harry
    Harry about 7 years
    And what about super simple solution: var resName = assembly.GetManifestResourceNames().Where(i => i.EndsWith(fileName)).FirstOrDefault(); It won't work if you place whole directories into assembly, but otherwise it's just one line ;)
  • Felix Keil
    Felix Keil about 7 years
    @Harry sure you can do this. How does this correlate with my answer? Do you want to improve the GetStream Method? And how do you handle ambiguity then?
  • Harry
    Harry about 7 years
    Yes, I wanted to do a little improvement. OK: var a = Assembly.GetExecutingAssembly(); using (var s = a.GetManifestResourceStream($"{a.EntryPoint.ReflectedType.Na‌​mespace}.{name}")) { /* here use the stream */ } - here's the way to handle ambiguity, seems like we have to use Namespace somewhere. I just looked for shorter and more compact way to get to MRS, you know, with best no dependency outside the method. I'm not sure if it's useful though, anyway I used in my self-extractor so I share.
  • Estevez
    Estevez almost 6 years
    What references do you have for 'EmbeddedResources'? using System... ; ???
  • Felix Keil
    Felix Keil almost 6 years
    @Estevez using System; using System.IO; using System.Linq; using System.Reflection;
  • a.farkas2508
    a.farkas2508 over 5 years
    I had a same problem in .NET 4.5. Files with dots in name were not even added to resource collection. Method assembly.GetManifestResourceNames() returns empty list to me.Later I've found out that problem was only with language code. ca.abcd.sk.crt was not added to resources while ca.abcd.crt was added without problem.
  • Alok
    Alok about 5 years
    plus one for captain planet :P
  • Ievgen
    Ievgen almost 5 years
    To fix that you should use "._" instead of ".". Check this out: Templates.plainEmailBodyTemplate._en.txt
  • Mike Gledhill
    Mike Gledhill almost 5 years
    Yup, it's now 3 years later, and this restriction still exists in VS2017. If you have an "Embedded Resource" called "captions.en.json", it simply doesn't get included. Changing the filename to "captions-en.json" solves the problem. Grrrr....
  • Curly Brace
    Curly Brace about 4 years
    For some reason class doesn't work when placed in another project. Calling and Executing assemblies are both refer to the assembly with this class, not the one that actually executes tests. Without static and lazy initialization all good, tho.
  • Felix Keil
    Felix Keil about 4 years
    @CurlyBrace Thank you. The lazy evaluation is a real flaw in this answer, because the calling & executing assemblies change dependending on the context. They need to be resolved on every access.
  • Mark
    Mark almost 4 years
    Hyphens ("-") in names will be replaced with underscores ("_").
  • Admin
    Admin almost 4 years
    It will return byte[] , for text files use ` Encoding.UTF8.GetString(Properties.Resources.Testfile)`
  • Kaido
    Kaido over 3 years
    Use assembly.GetManifestResourceNames to find the generated name
  • TinyRacoon
    TinyRacoon over 3 years
    If you haven't set the AssemblyCompany field in AssemblyInfo.cs then you can omit it. i.e. "MyProduct.MyFile.txt"
  • noelicus
    noelicus about 3 years
    Er ... SignificantDrawerCompiler ?
  • Abdul Saleem
    Abdul Saleem about 3 years
    Very well explained. Thank you
  • JoeTomks
    JoeTomks almost 3 years
    Also confused as to what SignificantDrawerCompiler is?
  • Lkor
    Lkor almost 3 years
    If you would like to use resources this way, but dynamically, just instead of this: Properties.Resources.Your_resource_name write this: Properties.Resources.ResourceManager.GetObject("Your_resourc‌​e_name").
  • ZeRemz
    ZeRemz almost 3 years
    Still correct in 2020. Thanks a lot for this, I was getting crazy with this.
  • Ian C Tubman
    Ian C Tubman over 2 years
    To get assembly name to prefix, I use: Assembly.GetExecutingAssembly().GetName().Name.ToString()
  • BullyWiiPlaza
    BullyWiiPlaza over 2 years
    @Krythic: It's obvious if you copy the whole class into your source code. Your IDE will resolve everything automatically then. I already included the using statements so the information was not missing from the answer.
  • BullyWiiPlaza
    BullyWiiPlaza over 2 years
    @Krythic: It's edited now to remove the static usings
  • Elnoor
    Elnoor about 2 years
    That will return byte array not string
  • Fabian
    Fabian almost 2 years
    There is now an overload for GetManifestResourceStream that allows to pass a type. So the specification of the namespace is not necessary anymore. This allows to remove the GetManifestResourceNames look up. See answer by Saeb Amini
  • Mike W
    Mike W almost 2 years
    where is Properties defined?
  • quemeful
    quemeful almost 2 years
    When designing this part of Xamarin, who was sitting there and thought, "hey! this could would make sense for reading from a text file!" Assembly.GetExecutingAssembly().GetManifestResourceStream(re‌​sourceName)
  • quemeful
    quemeful almost 2 years
    once I read the code SignificantDrawerCompiler seems optional
  • quemeful
    quemeful almost 2 years
    in order to use .Single() I think you need to use .toList()
  • David Bentley
    David Bentley over 1 year
    @Elnoor I do not believe this is true or at least not true with all versions. of .NetCore/Framework. I tested this with .Net 4.0 and fileNameSpace.Properties.Resources.fileName; is a string type.
  • Elnoor
    Elnoor over 1 year
    I have tested in Core. Maybe in Net standard yeah will return string
  • Kira Resari
    Kira Resari over 1 year
    This answer actually helped me figure out what I was still missing: setting "Build Action: Embedded Resource" in the files. I was wondering why they didn't show up. Now I'm wondering why this isn't the default setting. Is there any reason why you would add a file as a resource and not have it embedded?
  • SendETHToThisAddress
    SendETHToThisAddress over 1 year
    Thank you! This was the only answer that worked for me, which had intelligible steps I could understand. My app did not have a resource file and I had to create one. Only thing was on step 1 for me there was no Add button, I had to click save instead.
  • Barkermn01
    Barkermn01 over 1 year
    Thanks so much for this just a polite notice it's missing a using System.Reflection; :D
  • H3sDW11e
    H3sDW11e 8 months
    so much Garbage Collector this C#( that is the joke on you ) :: how to only load it like :: return new System.Uri(@"pack://application:,,,/RESOURCES/MyText.txt",Sy‌​stem.UriKind.Relativ‌​eOrAbsolute);