Подтвердить что ты не робот

Запись файла из потока ресурсов сборки на диск

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

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

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

4b9b3361

Ответ 1

Я не уверен, почему вы используете 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)) - и это тот тип производительности, который действительно может стоить гоняться.

EDIT: Как отмечено в комментариях,.NET 4.0 имеет Stream.CopyTo, поэтому вам не нужно сами это кодировать.

Ответ 2

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

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

И если ресурс (файл) является текстом.

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

Ответ 3

На самом деле я использовал эту единственную строку: 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

Ответ 4

Лично я бы сделал это следующим образом:

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

Ответ 5

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

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

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