user7116
user7116

Reputation: 64068

Write file from assembly resource stream to disk

I can't seem to find a more efficient way to "copy" an embedded resource to disk, than the following:

using (BinaryReader reader = new BinaryReader(
    assembly.GetManifestResourceStream(@"Namespace.Resources.File.ext")))
{
    using (BinaryWriter writer
        = new BinaryWriter(new FileStream(path, FileMode.Create)))
    {
        long bytesLeft = reader.BaseStream.Length;
        while (bytesLeft > 0)
        {
            // 65535L is < Int32.MaxValue, so no need to test for overflow
            byte[] chunk = reader.ReadBytes((int)Math.Min(bytesLeft, 65536L));
            writer.Write(chunk);

            bytesLeft -= chunk.Length;
        }
    }
}

There appears to be no more direct way to do the copy, unless I'm missing something...

Upvotes: 45

Views: 51449

Answers (6)

arcalo
arcalo

Reputation: 1

This Worked for me:

    using (MemoryStream input = new MemoryStream(Properties.Resources.*RESOURCE_NAME*))
    using (Stream output = File.Create(databasePath)){


                    input.CopyTo(output)
    }

Upvotes: 0

KoalaBear
KoalaBear

Reputation: 2948

If the resource (file) is binary.

File.WriteAllBytes("C:\ResourceName", Resources.ResourceName);

And if the resource (file) is text.

 File.WriteAllText("C:\ResourceName", Resources.ResourceName);

Upvotes: 65

cjbarth
cjbarth

Reputation: 4479

I actually ended up using this single line: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)). Of course, this is for .Net 4.0

Update: I found that the line above might keep a file locked such that SQLite reports that the database is read-only. Therefore I ended up with the following:

Using newFile As Stream = New FileStream(FileLocation, FileMode.Create)
    Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(newFile)
End Using

Upvotes: 22

Jon Skeet
Jon Skeet

Reputation: 1500525

I'm not sure why you're using BinaryReader/BinaryWriter at all. Personally I'd start off with a useful utility method:

public static void CopyStream(Stream input, Stream output)
{
    // Insert null checking here for production
    byte[] buffer = new byte[8192];

    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}

then call it:

using (Stream input = assembly.GetManifestResourceStream(resourceName))
using (Stream output = File.Create(path))
{
    CopyStream(input, output);
}

You can change the buffer size of course, or have it as a parameter to the method - but the main point is that this is simpler code. Is it more efficient? Nope. Are you sure you really need this code to be more efficient? Do you actually have hundreds of megabytes you need to write out to disk?

I find I rarely need code to be ultra-efficient, but I almost always need it to be simple. The sort of difference in performance that you might see between this and a "clever" approach (if one is even available) isn't likely to be a complexity-changing effect (e.g. O(n) to O(log n)) - and that's the type of performance gain which really can be worth chasing.

EDIT: As noted in comments, .NET 4.0 has Stream.CopyTo so you don't need to code this up yourself.

Upvotes: 68

Henk Holterman
Henk Holterman

Reputation: 273244

You will have to write a loop, if that's your question. But you could do without the reader and writer since the basic Stream already deals with byte[] data.

This is about as compact as I can get:

using (Stream inStream = File.OpenRead(inputFile))
using (Stream outStream = File.OpenWrite(outputFile))
{
    int read;
    byte[] buffer = new byte[64 * 1024];

    while ((read = inStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        outStream.Write(buffer, 0, read);
    }
}

Upvotes: 2

Lloyd
Lloyd

Reputation: 29668

Personally I would do it this way:

using (BinaryReader reader = new BinaryReader(
    assembly.GetManifestResourceStream(@"Namespace.Resources.File.ext")))
{
    using (BinaryWriter writer
        = new BinaryWriter(new FileStream(path, FileMode.Create)))
    {
        byte[] buffer = new byte[64 * 1024];
        int numread = reader.Read(buffer,0,buffer.Length);

        while (numread > 0)
        {
            writer.Write(buffer,0,numread);
            numread = reader.Read(buffer,0,buffer.Length);
        }

        writer.Flush();
    }
}

Upvotes: 2

Related Questions