Skip to content

Reading a file stream from resource file in C#

Reading Mode

There may be occassions during the course of developing a software project that you may need to store a text file or any binary type file within the resources of project, and make use of it.

In my example below, developing a generic CSV reader class, which is basically wrapper class around a CSV parser utility, LINQtoCSV

public class IngestList<TEntity> where TEntity : class, new()
    {
        private readonly CsvFileDescription _csvFileDescription;
        private readonly ISource _source;
 
        public IngestList(IFileDescription filedescription, ISource source)
        {
            _csvFileDescription = new CsvFileDescription
                {
                    SeparatorChar = filedescription.Delimiter,
                    FirstLineHasColumnNames = filedescription.HasColumnNames,
                    DetectEncodingFromByteOrderMarks = filedescription.DetectEncoding,
                    TextEncoding = filedescription.TextEncoding
                };
            _source = source;
        }
 
        public IList Get()
        {
            var sr = new StreamReader(new MemoryStream(_source.Source()));
            return new CsvContext().Read(sr, _csvFileDescription).ToList();
        }
    }

What if we wanted to test a few different CSV files at it of various lengths  and check the out put etc. Maybe we need to create some integration tests Unit Tests to esnure it operated as expected, and cover any edge type cases.

Lets set up a test library with nUnit, rhino and other TDD components. We may want to store the CSV files within the Test library, primarily so other developers could execute the tests without having to copy files around.

It's a simple enough process of adding files to resources, but how do we get them out again?

The wrong solutions

The following solution on StackOverflow. Seems to indicate you need to create some private method and make use of reflection on the current executing assembly.

private  byte[] ExtractResource(string filename)
        {
            System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
            using (Stream resFilestream = a.GetManifestResourceStream(filename))
            {
                if (resFilestream == null) return null;
                byte[] ba = new byte[resFilestream.Length];
                resFilestream.Read(ba, 0, ba.Length);
                return ba;
            }
        }

The solution works, but taking a step back and thinking about it. There has to be a simpler method.

The easy method

A bit of good old-fashioned RTFM! and this page in particular! Adding and Editing Resources (Visual C#)

All that is needed to get a file in the resources and view the properties window and set the File Type to Binary

It is then a trivial matter of passing the byte array to my class in one line of code!

C#

Where FileName is the name of the file in the Resource.

Simple! Easy!

We can now use this in a simple unit test

[Test(Description = "Should read a standard Test File")]
        public void ShouldReadTestFile()
        {
 
            var source = _mock.StrictMock();
            var stubFileDesc = MockRepository.GenerateStrictMock();
 
            stubFileDesc.Stub(x => x.HasColumnNames).Return(true);
            stubFileDesc.Stub(x => x.Delimiter).Return(';');
            stubFileDesc.Stub(x => x.Quotes).Return(false);
            stubFileDesc.Stub(x => x.DetectEncoding).Return(false);
            stubFileDesc.Stub(x => x.TextEncoding).Return(Encoding.UTF8);
            stubFileDesc.Stub(x => x.EnforceColumnAttribute).Return(true);
 
            Expect.Call(source.Source()).Return(Properties.Resources.test);
            _mock.ReplayAll();
 
            var people = new IngestList(stubFileDesc, source).Get();
 
            Assert.IsNotNull(people);
 
        }

I appreciate the fact that many purists will take a look at these unit test, and regard them more as integration tests, in that the test is testing actual outcomes of a unit of work, in that there is still a dependency on LinqToCsv being present and that it does some kind of work. However, in my case I did want the ability to test this code, and ensure that the results it emits are as expected. I also wanted a method that I could quickly and repeatedly run these tests.

I would love to hear your views on this. If you feel that you could provide me with a better solution or even improve my current solution I would certainly love to hear it, feel free to contact me or leave a note in the comment section below.

Gary Woodfine
Latest posts by Gary Woodfine (see all)