Запись файла из потока ресурсов сборки на диск
Я не могу найти более эффективный способ "скопировать" внедренный ресурс на диск, чем следующее:
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;
}
}
}
Кажется, что нет более прямого способа сделать копию, если я не пропущу что-то...
Ответы
Ответ 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);
}
}