Записать файл из потока ресурсов сборки на диск - PullRequest
42 голосов
/ 14 мая 2009

Я не могу найти более эффективный способ "скопировать" встроенный ресурс на диск, чем следующий:

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

Кажется, нет более прямого способа сделать копию, если я что-то упустил ...

Ответы [ 5 ]

65 голосов
/ 14 мая 2009

Я не уверен, почему вы вообще используете BinaryReader / BinaryWriter. Лично я бы начал с полезного служебного метода:

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

тогда назовите это:

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

Конечно, вы можете изменить размер буфера или использовать его в качестве параметра метода - но главное, что это более простой код. Это более эффективно? Нету. Вы уверены, что нужен этот код, чтобы быть более эффективным? У вас есть сотни мегабайт, которые нужно записать на диск?

Я нахожу, что мне редко нужно, чтобы код был сверхэффективным, но мне почти всегда нужно, чтобы он был простым. Разница в производительности, которую вы можете увидеть между этим и «умным» подходом (если он вообще доступен), вряд ли будет эффектом изменения сложности (например, от O (n) до O (log n)) - и это тип прироста производительности, который действительно стоит преследовать.

РЕДАКТИРОВАТЬ: Как отмечено в комментариях, .NET 4.0 имеет Stream.CopyTo, поэтому вам не нужно кодировать это самостоятельно.

58 голосов
/ 18 сентября 2011

Если ресурс (файл) является двоичным.

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

А если ресурс (файл) текстовый.

 File.WriteAllText("C:\ResourceName", Resources.ResourceName);
17 голосов
/ 14 апреля 2012

Я фактически закончил тем, что использовал эту единственную строку: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)). Конечно, это для .Net 4.0

Обновление: Я обнаружил, что строка выше может держать файл заблокированным, так что SQLite сообщает, что база данных доступна только для чтения. Поэтому я получил следующее:

Using newFile As Stream = New FileStream(FileLocation, FileMode.Create)
    Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(newFile)
End Using
2 голосов
/ 14 мая 2009

Вам придется написать цикл, если это ваш вопрос. Но вы можете обойтись без чтения и записи, поскольку базовый поток уже работает с данными byte [].

Это настолько компактно, насколько я могу получить:

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);
    }
}
2 голосов
/ 14 мая 2009

Лично я бы сделал это так:

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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...