848

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();
}
AA Shakil
  • 538
  • 4
  • 14
Me.Close
  • 8,531
  • 4
  • 17
  • 6

24 Answers24

1498

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");
Mikael Dúi Bolinder
  • 2,080
  • 2
  • 19
  • 44
dtb
  • 213,145
  • 36
  • 401
  • 431
  • 1
    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? – Me.Close Jul 22 '10 at 23:12
  • 5
    @Me.Close: Have a look at [`Environment.SpecialFolder`](http://msdn.microsoft.com/en-us/library/system.environment.specialfolder.aspx) 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`. – adrianbanks Jul 22 '10 at 23:21
  • 17
    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. – JYelton May 18 '12 at 19:35
  • 75
    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.FileExtention") – Sasha Sep 30 '13 at 11:46
  • 1
    that's weird for me `Properties.Resources.myfile` happens to be directly a string and usable in code. – v.oddou Nov 19 '13 at 08:58
  • 31
    Worth to say that resource "Build Action" has to be set as "Embedded Resource" – Illidan Feb 16 '15 at 13:51
  • 11
    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))` – Kinetic Dec 08 '15 at 16:18
  • 2
    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? – ff8mania Feb 03 '16 at 20:49
  • Hyphens ("-") in names will be replaced with underscores ("_"). – Mark Mar 13 '19 at 15:50
  • Use assembly.GetManifestResourceNames to find the generated name – Kaido May 31 '19 at 09:21
  • If you haven't set the AssemblyCompany field in AssemblyInfo.cs then you can omit it. i.e. "MyProduct.MyFile.txt" – TinyRacoon Sep 13 '19 at 10:37
  • 26
    Er ... `SignificantDrawerCompiler` ? – noelicus Feb 13 '20 at 10:22
  • 14
    Also confused as to what SignificantDrawerCompiler is? – JoeTomks Apr 02 '20 at 09:36
  • 2
    To get assembly name to prefix, I use: Assembly.GetExecutingAssembly().GetName().Name.ToString() – Ian Tubman Aug 19 '20 at 03:08
  • 2
    There is now an overload for [GetManifestResourceStream](https://learn.microsoft.com/de-de/dotnet/api/system.reflection.assembly.getmanifestresourcestream?view=net-5.0#System_Reflection_Assembly_GetManifestResourceStream_System_Type_System_String_) 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](https://stackoverflow.com/a/62988655/4226080) – Fabian Mar 01 '21 at 09:57
  • 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(resourceName)` – quemeful Apr 15 '21 at 14:50
  • once I read the code `SignificantDrawerCompiler` seems optional – quemeful Apr 15 '21 at 14:53
  • in order to use `.Single()` I think you need to use `.toList()` – quemeful Apr 15 '21 at 14:58
  • 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",System.UriKind.RelativeOrAbsolute); – H3sDW11e Jul 01 '22 at 02:04
  • Also something to important about this solution is that is uses a `StreamReader` -- this is important because a more naive use of the simple `Encoding.UTF8.GetString()` does NOT handle byte-order-mark (BOM) correctly so things like `JObject.Parse()` may fail due to unexpected BOM, but the use of `StreamReader` provides more robust/reliable handling of text content. – CajunCoding Nov 18 '22 at 20:34
190

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

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Contango
  • 76,540
  • 58
  • 260
  • 305
  • 10
    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. – Contango Jul 08 '15 at 06:52
  • 1
    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? – Maslow Nov 11 '15 at 17:31
  • 3
    @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 https://msdn.microsoft.com/en-us/library/7k989cfy(v=vs.90).aspx. – Contango Nov 12 '15 at 08:19
  • 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_resource_name")`. – Lkor Apr 21 '20 at 10:25
  • 1
    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? – Kira Resari Jul 28 '21 at 14:27
98

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!");
   }
Steve
  • 2,988
  • 2
  • 30
  • 47
Chris Laplante
  • 29,338
  • 17
  • 103
  • 134
  • 46
    `var auxList= System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();` This method could be very useful when you want to learn the exact resource name. (Taken from question http://stackoverflow.com/questions/27757/how-can-i-discover-the-path-of-an-embedded-resource) – Oscar Foley Oct 13 '11 at 13:51
81

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)
Community
  • 1
  • 1
Andrew Hill
  • 1,921
  • 1
  • 25
  • 31
  • 13
    You can also use this with a text file, in which case you would have: string jsonSecrets = YourNameSpace.Properties.Resources.YourFileName; – ouflak Nov 14 '13 at 17:55
39

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.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
Night Walker
  • 20,638
  • 52
  • 151
  • 228
  • 5
    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. – Suzanne Soy Mar 19 '13 at 10:02
  • 2
    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. – Contango Oct 27 '14 at 10:01
  • where is Properties defined? – Mike W Mar 29 '21 at 16:38
19

adding e.g. Testfile.sql Project Menu -> Properties -> Resources -> Add Existing file

    string queryFromResourceFile = Properties.Resources.Testfile.ToString();

enter image description here

miciry89
  • 196
  • 1
  • 5
  • 4
    It will return byte[] , for text files use ` Encoding.UTF8.GetString(Properties.Resources.Testfile)` –  May 06 '19 at 19:02
13

I know it is an old thread, but this is what worked for me :

  1. add the text file to the project resources
  2. set the access modifier to public, as showed above by Andrew Hill
  3. read the text like this :

    textBox1 = new TextBox();
    textBox1.Text = Properties.Resources.SomeText;
    

The text that I added to the resources: 'SomeText.txt'

Amber
  • 812
  • 8
  • 21
S_Teo
  • 131
  • 1
  • 3
11

Something I learned just now is that your file is not allowed to have a "." (dot) in the filename.

A "." in filename is no good.

Templates.plainEmailBodyTemplate-en.txt --> Works!!!
Templates.plainEmailBodyTemplate.en.txt --> doesn't work via GetManifestResourceStream()

Probably because the framework gets confused over namespaces vs filename...

Peter Gfader
  • 7,673
  • 8
  • 55
  • 56
  • 4
    Sorry. This is wrong. Dots work. (at least it worked for me, NET4.5) I don't know why you had this bug. – Felix Keil Sep 11 '15 at 11:10
  • Yes they work but they act as Directory separator. Templates.plainEmailBodyTemplate.en.txt will look for "\Templates\plainEmailBodyTemplate\en.txt" resource – Peter Gfader Sep 16 '15 at 12:41
  • No. I tried it. GetManifestResourceStream can access embedded resources with more than one dot in the filename. (NET4.5) – Felix Keil Sep 16 '15 at 12:47
  • 1
    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. – a.farkas2508 Jun 06 '17 at 09:03
  • To fix that you should use "._" instead of ".". Check this out: Templates.plainEmailBodyTemplate._en.txt – Ievgen Apr 06 '18 at 12:04
  • 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.... – Mike Gledhill May 16 '18 at 07:36
10

You can also use this simplified version of @dtb's answer:

public string GetEmbeddedResource(string ns, string res)
{
    using (var reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(string.Format("{0}.{1}", ns, res))))
    {
        return reader.ReadToEnd();
    }
}
Timmerz
  • 6,090
  • 5
  • 36
  • 49
  • are you sure about that? according this this link it looks like I am....http://stackoverflow.com/questions/1065168/does-disposing-streamreader-close-the-stream – Timmerz Feb 03 '14 at 20:20
9

By all your powers combined I use this helper class for reading resources from any assembly and any namespace in a generic way.

public class ResourceReader
{
    public static IEnumerable<string> FindEmbededResources<TAssembly>(Func<string, bool> predicate)
    {
        if (predicate == null) throw new ArgumentNullException(nameof(predicate));

        return
            GetEmbededResourceNames<TAssembly>()
                .Where(predicate)
                .Select(name => ReadEmbededResource(typeof(TAssembly), name))
                .Where(x => !string.IsNullOrEmpty(x));
    }

    public static IEnumerable<string> GetEmbededResourceNames<TAssembly>()
    {
        var assembly = Assembly.GetAssembly(typeof(TAssembly));
        return assembly.GetManifestResourceNames();
    }

    public static string ReadEmbededResource<TAssembly, TNamespace>(string name)
    {
        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
        return ReadEmbededResource(typeof(TAssembly), typeof(TNamespace), name);
    }

    public static string ReadEmbededResource(Type assemblyType, Type namespaceType, string name)
    {
        if (assemblyType == null) throw new ArgumentNullException(nameof(assemblyType));
        if (namespaceType == null) throw new ArgumentNullException(nameof(namespaceType));
        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));

        return ReadEmbededResource(assemblyType, $"{namespaceType.Namespace}.{name}");
    }

    public static string ReadEmbededResource(Type assemblyType, string name)
    {
        if (assemblyType == null) throw new ArgumentNullException(nameof(assemblyType));
        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));

        var assembly = Assembly.GetAssembly(assemblyType);
        using (var resourceStream = assembly.GetManifestResourceStream(name))
        {
            if (resourceStream == null) return null;
            using (var streamReader = new StreamReader(resourceStream))
            {
                return streamReader.ReadToEnd();
            }
        }
    }
}
t3chb0t
  • 16,340
  • 13
  • 78
  • 118
  • How does this work? I can't pass a namespace to TAssembly – Shadowblitz16 May 07 '23 at 03:39
  • @Shadowblitz16 `TAssembly` is just any type inside that assembly/dll/lib whatever you call it. The actual _magic_ happens here `Assembly.GetAssembly(typeof(TAssembly))`. – t3chb0t May 07 '23 at 10:23
6

I know this is old, but I just wanted to point out for NETMF (.Net MicroFramework), you can easily do this:

string response = Resources.GetString(Resources.StringResources.MyFileName);

Since NETMF doesn't have GetManifestResourceStream

ann
  • 576
  • 1
  • 10
  • 19
dreamwork801
  • 123
  • 2
  • 3
4

I read an embedded resource text file use:

    /// <summary>
    /// Converts to generic list a byte array
    /// </summary>
    /// <param name="content">byte array (embedded resource)</param>
    /// <returns>generic list of strings</returns>
    private List<string> GetLines(byte[] content)
    {
        string s = Encoding.Default.GetString(content, 0, content.Length - 1);
        return new List<string>(s.Split(new[] { Environment.NewLine }, StringSplitOptions.None));
    }

Sample:

var template = GetLines(Properties.Resources.LasTemplate /* resource name */);

template.ForEach(ln =>
{
    Debug.WriteLine(ln);
});
Philippe
  • 3,945
  • 3
  • 38
  • 56
Sith2021
  • 3,245
  • 30
  • 22
4

Some VS .NET project types don’t auto-generate a .NET (.resx) file. The following steps add a Resource file to your project:

  1. Right-click the project node and select Add/New Item, scroll to Resources File. In the Name box choose an appropriate name, for instance Resources and click the button Add.
  2. The resource file Resources.resx is added to the project and can be seen as a node in the solution explorer.
  3. Actually, two files are created, there is also an auto-generated C# class Resources.Designer.cs. Don’t edit it, it is maintained by VS. The file contains a class named Resources.

Now you can add a text file as a resource, for example an xml file:

  1. Double-click Resources.resx. Select Add Resource > Add Existing File and scroll to the file you want to be included. Leave the default value Internal for Access Modify.
  2. An icon represents the new resource item. If selected, the property pane shows its properties. For xml files, under the property Encoding select Unicode (UTF-8) – Codepage 65001 instead of the default local codepage. For other text files select the correct encoding of this file, for example codepage 1252.
  3. For text files like xml files, the class Resources has a property of type string that is named after the included file. If the file name is e.g. RibbonManifest.xml, then the property should have the name RibbonManifest. You find the exact name in the code file Resources.Designer.cs.
  4. Use the string property like any other string property, for example: string xml = Resources.RibbonManifest. The general form is ResourceFileName.IncludedTextFileName. Don’t use ResourceManager.GetString since the get-function of the string property has done that already.
  • 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. – SendETHToThisAddress Sep 02 '21 at 23:08
4

This is a class which you might find very convenient for reading embedded resource files from the current Assembly:

using System.IO;
using System.Linq;
using System.Text;
using System.Reflection;

public static class EmbeddedResourceUtils
{
    public static string ReadFromResourceFile(string endingFileName)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var manifestResourceNames = assembly.GetManifestResourceNames();

        foreach (var resourceName in manifestResourceNames)
        {
            var fileNameFromResourceName = _GetFileNameFromResourceName(resourceName);
            if (!fileNameFromResourceName.EndsWith(endingFileName))
            {
                continue;
            }

            using (var manifestResourceStream = assembly.GetManifestResourceStream(resourceName))
            {
                if (manifestResourceStream == null)
                {
                    continue;
                }

                using (var streamReader = new StreamReader(manifestResourceStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }

        return null;
    }
    
    // https://stackoverflow.com/a/32176198/3764804
    private static string _GetFileNameFromResourceName(string resourceName)
    {
        var stringBuilder = new StringBuilder();
        var escapeDot = false;
        var haveExtension = false;

        for (var resourceNameIndex = resourceName.Length - 1;
            resourceNameIndex >= 0;
            resourceNameIndex--)
        {
            if (resourceName[resourceNameIndex] == '_')
            {
                escapeDot = true;
                continue;
            }

            if (resourceName[resourceNameIndex] == '.')
            {
                if (!escapeDot)
                {
                    if (haveExtension)
                    {
                        stringBuilder.Append('\\');
                        continue;
                    }

                    haveExtension = true;
                }
            }
            else
            {
                escapeDot = false;
            }

            stringBuilder.Append(resourceName[resourceNameIndex]);
        }

        var fileName = Path.GetDirectoryName(stringBuilder.ToString());
        return fileName == null ? null : new string(fileName.Reverse().ToArray());
    }
}
BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
  • @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 Sep 21 '20 at 11:43
3

After reading all the solutions posted here. This is how I solved it:

// How to embedded a "Text file" inside of a C# project
//   and read it as a resource from c# code:
//
// (1) Add Text File to Project.  example: 'myfile.txt'
//
// (2) Change Text File Properties:
//      Build-action: EmbeddedResource
//      Logical-name: myfile.txt      
//          (note only 1 dot permitted in filename)
//
// (3) from c# get the string for the entire embedded file as follows:
//
//     string myfile = GetEmbeddedResourceFile("myfile.txt");

public static string GetEmbeddedResourceFile(string filename) {
    var a = System.Reflection.Assembly.GetExecutingAssembly();
    using (var s = a.GetManifestResourceStream(filename))
    using (var r = new System.IO.StreamReader(s))
    {
        string result = r.ReadToEnd();
        return result;
    }
    return "";      
}
Bimo
  • 5,987
  • 2
  • 39
  • 61
3

The answer is quite simple, simply do this if you added the file directly from the resources.resx.

string textInResourceFile = fileNameSpace.Properties.Resources.fileName;

With that line of code, the text from the file is directly read from the file and put into the string variable.

Jamisco
  • 1,658
  • 3
  • 13
  • 17
  • That will return byte array not string – Elnoor Jan 09 '21 at 06:34
  • @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. – David Bentley Jun 14 '21 at 17:54
  • I have tested in Core. Maybe in Net standard yeah will return string – Elnoor Jun 15 '21 at 01:57
2
public class AssemblyTextFileReader
{
    private readonly Assembly _assembly;

    public AssemblyTextFileReader(Assembly assembly)
    {
        _assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
    }

    public async Task<string> ReadFileAsync(string fileName)
    {
        var resourceName = _assembly.GetManifestResourceName(fileName);

        using (var stream = _assembly.GetManifestResourceStream(resourceName))
        {
            using (var reader = new StreamReader(stream))
            {
                return await reader.ReadToEndAsync();
            }
        }
    }
}

public static class AssemblyExtensions
{
    public static string GetManifestResourceName(this Assembly assembly, string fileName)
    {
        string name = assembly.GetManifestResourceNames().SingleOrDefault(n => n.EndsWith(fileName, StringComparison.InvariantCultureIgnoreCase));

        if (string.IsNullOrEmpty(name))
        {
            throw new FileNotFoundException($"Embedded file '{fileName}' could not be found in assembly '{assembly.FullName}'.", fileName);
        }

        return name;
    }
}
// To use the code above:
var reader = new AssemblyTextFileReader(assembly);

string text = await reader.ReadFileAsync(@"MyFile.txt");
bytedev
  • 8,252
  • 4
  • 48
  • 56
2

I wanted to read the embedded resource just as a byte array (without assuming any specific encoding), and I ended up using a MemoryStream which makes it very simple:

using var resStream = assembly.GetManifestResourceStream(GetType(), "file.txt");
var ms = new MemoryStream();
await resStream .CopyToAsync(ms);
var bytes = ms.ToArray();
Saeb Amini
  • 23,054
  • 9
  • 78
  • 76
2

As indicated by SonarCloud better to do:

public class Example
{
    public static void Main()
    { 
        // Compliant: type of the current class
        Assembly assembly = typeof(Example).Assembly; 
        Console.WriteLine("Assembly name: {0}", assem.FullName);

        // Non-compliant
        Assembly assembly = Assembly.GetExecutingAssembly();
        Console.WriteLine("Assembly name: {0}", assem.FullName);
    }
}
Matteo Gariglio
  • 482
  • 5
  • 12
1

I was annoyed that you had to always include the namespace and the folder in the string. I wanted to simplify the access to the embedded resources. This is why I wrote this little class. Feel free to use and improve!

Usage:

using(Stream stream = EmbeddedResources.ExecutingResources.GetStream("filename.txt"))
{
 //...
}

Class:

public class EmbeddedResources
{
    private static readonly Lazy<EmbeddedResources> _callingResources = new Lazy<EmbeddedResources>(() => new EmbeddedResources(Assembly.GetCallingAssembly()));

    private static readonly Lazy<EmbeddedResources> _entryResources = new Lazy<EmbeddedResources>(() => new EmbeddedResources(Assembly.GetEntryAssembly()));

    private static readonly Lazy<EmbeddedResources> _executingResources = new Lazy<EmbeddedResources>(() => new EmbeddedResources(Assembly.GetExecutingAssembly()));

    private readonly Assembly _assembly;

    private readonly string[] _resources;

    public EmbeddedResources(Assembly assembly)
    {
        _assembly = assembly;
        _resources = assembly.GetManifestResourceNames();
    }

    public static EmbeddedResources CallingResources => _callingResources.Value;

    public static EmbeddedResources EntryResources => _entryResources.Value;

    public static EmbeddedResources ExecutingResources => _executingResources.Value;

    public Stream GetStream(string resName) => _assembly.GetManifestResourceStream(_resources.Single(s => s.Contains(resName)));

}
Felix Keil
  • 2,344
  • 1
  • 25
  • 27
  • 2
    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 ;) – Harry Feb 14 '16 at 11:04
  • @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? – Felix Keil Feb 15 '16 at 10:30
  • Yes, I wanted to do a little improvement. OK: var a = Assembly.GetExecutingAssembly(); using (var s = a.GetManifestResourceStream($"{a.EntryPoint.ReflectedType.Namespace}.{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. – Harry Feb 16 '16 at 21:45
  • What references do you have for 'EmbeddedResources'? using System... ; ??? – Estevez Mar 17 '17 at 09:06
  • 1
    @Estevez using System; using System.IO; using System.Linq; using System.Reflection; – Felix Keil Mar 17 '17 at 10:34
  • 2
    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. – Curly Brace Jan 31 '19 at 11:54
  • 1
    @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. – Felix Keil Feb 04 '19 at 11:04
0

For all the people that just quickly want the text of a hardcoded file in winforms;

  1. Right-click your application in the solution explorer > Resources > Add your file.
  2. Click on it, and in the properties tab set the "FileType" to "Text".
  3. In your program just do Resources.<name of resource>.toString(); to read the file.

I would not recommend this as best practice or anything, but it works quickly and does what it needs to do.

Nightfall
  • 107
  • 1
  • 10
0

Most of answers here holds base or full namespace as a constant or iterate over all resources from GetManifestResourceNames to get it. I have much simpler but not perfect solution:

var ns = typeof(Form1).Namespace;
var filename = "MyFile.txt";
using (var s = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ns}.{filename}"))
using (var sr = new StreamReader(s))
{
    var text = sr.ReadToEnd();
}

// OR
var ns = this.GetType().Namespace;
var filename = "MyFile.txt";
using (var s = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ns}.{filename}"))
using (var sr = new StreamReader(s))
{
    var text = sr.ReadToEnd();
}

Of course file shold be marked as "Embedded Resource".

Save
  • 1,376
  • 2
  • 12
  • 26
-1

Read Embedded TXT FILE on Form Load Event.

Set the Variables Dynamically.

string f1 = "AppName.File1.Ext";
string f2 = "AppName.File2.Ext";
string f3 = "AppName.File3.Ext";

Call a Try Catch.

try 
{
     IncludeText(f1,f2,f3); 
     /// Pass the Resources Dynamically 
     /// through the call stack.
}

catch (Exception Ex)
{
     MessageBox.Show(Ex.Message);  
     /// Error for if the Stream is Null.
}

Create Void for IncludeText(), Visual Studio Does this for you. Click the Lightbulb to AutoGenerate The CodeBlock.

Put the following inside the Generated Code Block

Resource 1

var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(file1))
using (StreamReader reader = new StreamReader(stream))
{
string result1 = reader.ReadToEnd();
richTextBox1.AppendText(result1 + Environment.NewLine + Environment.NewLine );
}

Resource 2

var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(file2))
using (StreamReader reader = new StreamReader(stream))
{
string result2 = reader.ReadToEnd();
richTextBox1.AppendText(
result2 + Environment.NewLine + 
Environment.NewLine );
}

Resource 3

var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(file3))

using (StreamReader reader = new StreamReader(stream))
{
    string result3 = reader.ReadToEnd();
    richTextBox1.AppendText(result3);
}

If you wish to send the returned variable somewhere else, just call another function and...

using (StreamReader reader = new StreamReader(stream))
{
    string result3 = reader.ReadToEnd();
    ///richTextBox1.AppendText(result3);
    string extVar = result3;

    /// another try catch here.

   try {

   SendVariableToLocation(extVar)
   {
         //// Put Code Here.
   }

       }

  catch (Exception ex)
  {
    Messagebox.Show(ex.Message);
  }

}

What this achieved was this, a method to combine multiple txt files, and read their embedded data, inside a single rich text box. which was my desired effect with this sample of Code.

MasterCassidy
  • 49
  • 1
  • 14
-1

For users that are using VB.Net

Imports System.IO
Imports System.Reflection

Dim reader As StreamReader
Dim ass As Assembly = Assembly.GetExecutingAssembly()
Dim sFileName = "MyApplicationName.JavaScript.js" 
Dim reader = New StreamReader(ass.GetManifestResourceStream(sFileName))
Dim sScriptText = reader.ReadToEnd()
reader.Close()

where MyApplicationName is namespace of my application. It is not the assembly name. This name is define in project's properties (Application tab).

If you don't find correct resource name, you can use GetManifestResourceNames() function

Dim resourceName() As String = ass.GetManifestResourceNames()

or

Dim sName As String 
    = ass.GetManifestResourceNames()
        .Single(Function(x) x.EndsWith("JavaScript.js"))

or

Dim sNameList 
    = ass.GetManifestResourceNames()
        .Where(Function(x As String) x.EndsWith(".js"))
schlebe
  • 3,387
  • 5
  • 37
  • 50