Загрузите файл из класса System.Io.Stream C # asp.net [duplicate]

Я знаю, что это должно звучать глупо ... но редко бывает.

Проверьте, пытаетесь ли вы выполнить php из

**http://localhost/info.php**

, а не из

file:///var/www/info.php

ps> вы можете заметить, что если вы пишете из shell

php info.php 

, то ответьте на код (это означает php-функции) ..

606
задан sbeliakov 5 February 2015 в 13:35
поделиться

9 ответов

Почему бы не использовать объект FileStream?

public void SaveStreamToFile(string fileFullPath, Stream stream)
{
    if (stream.Length == 0) return;

    // Create a FileStream object to write a stream to a file
    using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
    {
        // Fill the bytes[] array with the stream data
        byte[] bytesInStream = new byte[stream.Length];
        stream.Read(bytesInStream, 0, (int)bytesInStream.Length);

        // Use FileStream object to write to the specified file
        fileStream.Write(bytesInStream, 0, bytesInStream.Length);
     }
}
6
ответ дан balexandre 21 August 2018 в 01:16
поделиться
  • 1
    что, если входной поток длиннее 1 ГБ - этот код попытается выделить 1 ГБ буфер :) – Buthrakaur 30 June 2011 в 08:56
  • 2
    Бутракавр прав - этот ответ нужно удалить. – Frank Hileman 23 May 2013 в 22:08
  • 3
    Это не работает с ResponseStream, так как оно неизвестно. – qub1n 18 October 2013 в 11:31
  • 4
    Хотя это правда, вы должны иметь доступную память для byte[], я думаю, что было бы редко, если бы вы потоковали 1 GB + blob в файл ... если у вас нет сайта, на котором хранятся торренты на DVD. .. Кроме того, на большинстве компьютеров в настоящее время доступно не менее 2 ГБ ОЗУ. Во всяком случае ... Caveat действительно, но я думаю, что это случай, когда он, вероятно, «достаточно хорош», для большинства рабочих мест. – vapcguy 12 October 2016 в 20:50
  • 5
    Вебсерверы не будут мириться с таким случаем, если только на веб-сайте не будет активирован только один пользователь. – NateTheGreatt 3 October 2017 в 21:28
//If you don't have .Net 4.0  :)

public void SaveStreamToFile(Stream stream, string filename)
{  
   using(Stream destination = File.Create(filename))
      Write(stream, destination);
}

//Typically I implement this Write method as a Stream extension method. 
//The framework handles buffering.

public void Write(Stream from, Stream to)
{
   for(int a = from.ReadByte(); a != -1; a = from.ReadByte())
      to.WriteByte( (byte) a );
}

/*
Note, StreamReader is an IEnumerable<Char> while Stream is an IEnumbable<byte>.
The distinction is significant such as in multiple byte character encodings 
like Unicode used in .Net where Char is one or more bytes (byte[n]). Also, the
resulting translation from IEnumerable<byte> to IEnumerable<Char> can loose bytes
or insert them (for example, "\n" vs. "\r\n") depending on the StreamReader instance
CurrentEncoding.
*/
8
ответ дан George 21 August 2018 в 01:16
поделиться
  • 1
    Копирование потокового байта (с использованием ReadByte / WriteByte) будет намного медленнее, чем копирование буфера по буфере (используя Read (byte [], int, int) / Write (byte [], int, int)). – Kevin 10 August 2011 в 04:10
public void CopyStream(Stream stream, string destPath)
{
  using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
  {
    stream.CopyTo(fileStream);
  }
}
57
ответ дан Jerome 21 August 2018 в 01:16
поделиться
  • 1
    Вероятно, вы не должны поместить объект stream в скобку using(){}. Ваш метод не создал поток, поэтому он не должен его утилизировать. – LarsTech 1 August 2013 в 22:16
  • 2
    Вместо этого вам нужно поместить FileStream вместо использования, иначе он будет оставаться открытым, пока не будет собран мусор. – Pavel Chikulaev 17 January 2014 в 01:55
  • 3
    Я обнаружил, что ваш подход был намного ближе для решения моей проблемы в WinForms с классом шлюза класса AWS S3! Спасибо! – Luiz Eduardo 3 June 2015 в 18:06
  • 4
    Это закончилось отлично, но я получил выход в 0 КБ. Вместо этого я должен был сделать это для правильного вывода: File.WriteAllBytes(destinationFilePath, input.ToArray());. В моем случае input является MemoryStream, исходящим из ZipArchive. – SNag 10 January 2016 в 02:50
  • 5
    Это хорошо работает в моем методе действий контроллера MVC. – kimbaudi 6 October 2016 в 16:52

Вы не должны использовать StreamReader для двоичных файлов (например, gif или jpg). StreamReader для данных text . Вы почти , конечно, теряете данные, если используете их для произвольных двоичных данных. (Если вы используете Encoding.GetEncoding (28591), вы, вероятно, будете в порядке, но в чем смысл?)

Зачем вам вообще нужно использовать StreamReader? Почему бы просто не сохранить двоичные данные в качестве двоичных данных и записать их на диск (или SQL) в виде двоичных данных?

EDIT: поскольку это, кажется, то, что люди хотят видеть ... если вы do просто хотите скопировать один поток в другой (например, в файл), используйте что-то вроде этого:

/// <summary>
/// Copies the contents of input to output. Doesn't close either stream.
/// </summary>
public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8 * 1024];
    int len;
    while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, len);
    }    
}

Чтобы использовать его для сброса потока в файл, например:

using (Stream file = File.Create(filename))
{
    CopyStream(input, file);
}

Обратите внимание, что Stream.CopyTo был введен в .NET 4, служащий в основном той же цели.

474
ответ дан Jon Skeet 21 August 2018 в 01:16
поделиться
  • 1
    Это похоже на такой общий случай, я удивлен его не в .NET. Я вижу, что люди создают массивы байтов размером всего файла, что может вызвать проблемы для больших файлов. – Tilendor 7 December 2010 в 18:00
  • 2
    @Tilendor: он присутствует как метод расширения в .NET 4. (CopyTo) – Jon Skeet 7 December 2010 в 18:17
  • 3
    Я не думаю, что это метод расширения, но он новичок в классе Stream. – Kugel 24 January 2011 в 22:43
  • 4
    @ Кугель: Вы правы, извините. I использовал его как метод расширения в библиотеке служебных программ, но теперь, когда он находится в самом потоке, мой метод расширения не вызван. – Jon Skeet 24 January 2011 в 23:02
  • 5
    @Florian: Это достаточно произвольно - достаточно маленькое значение, чтобы не брать слишком много памяти и достаточно большой, чтобы передавать разумный кусок за раз. Было бы неплохо, если бы было 16K, 32K, возможно, я просто буду осторожен, чтобы не оказаться на большой куче объекта. – Jon Skeet 2 October 2013 в 17:53

Как было подчеркнуто Tilendor в ответе Джона Скита, потоки имеют метод CopyTo с .NET 4.

var fileStream = File.Create("C:\\Path\\To\\File");
myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
myOtherObject.InputStream.CopyTo(fileStream);
fileStream.Close();

Или с синтаксисом using:

using (var fileStream = File.Create("C:\\Path\\To\\File"))
{
    myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
    myOtherObject.InputStream.CopyTo(fileStream);
}
762
ответ дан Jony Adamit 21 August 2018 в 01:16
поделиться
  • 1
    Обратите внимание, что вы должны называть myOtherObject.InputStream.Seek(0, SeekOrigin.Begin), если вы еще не в начале, или вы не будете копировать весь поток. – Steve Rukuts 22 March 2012 в 14:00
  • 2
    Если этот входной поток получен из http-соединения, он будет буферировать и загружать, а затем записывать все байты из источника ????? – dbw 4 January 2014 в 16:16
  • 3
    Я создал программу просмотра PDF, где я использую поток, как только я привязываю поток, и когда я сохраняю файл pdf с использованием того же потока, но без использования «Seek (0, SeekOrigin.Begin) & quot; Я не смогу сохранить правильный документ. так что +1 для упоминания этого «Seek (0, SeekOrigin.Begin)» – user2463514 6 March 2014 в 14:28
  • 4
    myOtherObject.InputStream.CopyTo (FileStream); эта строка дает ошибку: доступ запрещен. – sulhadin 29 June 2016 в 13:05
  • 5
    @sulhadin, что означает, что у вас нет разрешения писать на fileStream – Antoine Leclair 29 June 2016 в 17:05
public void testdownload(stream input)
{
    byte[] buffer = new byte[16345];
    using (FileStream fs = new FileStream(this.FullLocalFilePath,
                        FileMode.Create, FileAccess.Write, FileShare.None))
    {
        int read;
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
             fs.Write(buffer, 0, read);
        }
    }
}
4
ответ дан Major Byte 21 August 2018 в 01:16
поделиться
  • 1
    Подача буферизованного входного потока непосредственно на FileStream - приятно! – vapcguy 12 October 2016 в 20:55

Другой вариант - передать поток в byte[] и использовать File.WriteAllBytes. Это должно сделать:

using (var stream = new MemoryStream())
{
    input.CopyTo(stream);
    File.WriteAllBytes(file, stream.ToArray());
}

Обертка его в методе расширения дает ему лучшее именование:

public void WriteTo(this Stream input, string file)
{
    //your fav write method:

    using (var stream = File.Create(file))
    {
        input.CopyTo(stream);
    }

    //or

    using (var stream = new MemoryStream())
    {
        input.CopyTo(stream);
        File.WriteAllBytes(file, stream.ToArray());
    }

    //whatever that fits.
}
19
ответ дан nawfal 21 August 2018 в 01:16
поделиться
  • 1
    Если вход слишком велик, вы получите исключение из памяти. Возможность копирования содержимого из входного потока в поток потока намного лучше – Ykok 4 September 2015 в 11:02
  • 2
    Это закончилось отлично, но я получил выход в 0 КБ. Вместо этого я должен был сделать это для правильного вывода: File.WriteAllBytes(destinationFilePath, input.ToArray());. В моем случае input является MemoryStream, исходящим из ZipArchive. – SNag 10 January 2016 в 02:50
  • 3
    Это помогло мне понять, что я делаю неправильно. Однако не забудьте переместиться в начало потока: stream.Seek(0, SeekOrigin.Begin); – Nathan Bills 8 August 2016 в 22:06

Я не получаю все ответы, используя CopyTo, где, возможно, системы, использующие приложение, возможно, не были обновлены до .NET 4.0+. Я знаю, что некоторые хотели бы заставить людей обновиться, но совместимость тоже хороша.

Другое дело, я не использую поток для копирования из другого потока в первую очередь. Почему бы просто не сделать:

byte[] bytes = myOtherObject.InputStream.ToArray();

Как только у вас есть байты, вы можете легко записать их в файл:

public static void WriteFile(string fileName, byte[] bytes)
{
    string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (!path.EndsWith(@"\")) path += @"\";

    if (File.Exists(Path.Combine(path, fileName)))
        File.Delete(Path.Combine(path, fileName));

    using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write)
    {
        fs.Write(bytes, 0, (int)bytes.Length);
        fs.Close();
    }
}

Этот код работает так, как я его тестировал файл .jpg, хотя я признаю, что использовал его только с небольшими файлами (менее 1 МБ). Один поток, без копирования между потоками, без необходимости кодирования, просто напишите байты! Не нужно чрезмерно усложнять вещи с помощью StreamReader, если у вас уже есть поток, который вы можете напрямую конвертировать в bytes с помощью .ToArray()!

Только потенциальные недостатки, которые я вижу при этом, - это если у вас есть большой файл, имеющий его как поток, а использование .CopyTo() или эквивалента позволяет FileStream передавать его, а не использовать байтовый массив и чтение байтов один за другим. В результате это может быть медленнее. Но он не должен задыхаться, так как метод .Write() дескрипторов FileStream записывает байты, и он выполняет только один байт за раз, поэтому он не будет забивать память, за исключением того, что вам нужно будет иметь достаточно памяти для хранения потока в качестве объекта byte[]. В моей ситуации, когда я использовал это, получив OracleBlob, я должен был перейти к byte[], он был достаточно маленьким, и, кроме того, для меня не было потоковой передачи, поэтому я просто отправил свои байты на мой функции [выше].

Другим вариантом, использующим поток, было бы использовать его с функцией CopyStream Jon Skeet, которая была в другом сообщении, - это просто использует FileStream для ввода входного потока и создания файл из него напрямую. Он не использует File.Create, как и он (который изначально казался мне проблематичным, но позже обнаружил, что это скорее всего ошибка VS ...).

/// <summary>
/// Copies the contents of input to output. Doesn't close either stream.
/// </summary>
public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8 * 1024];
    int len;
    while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, len);
    }    
}

public static void WriteFile(string fileName, Stream inputStream)
{
    string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (!path.EndsWith(@"\")) path += @"\";

    if (File.Exists(Path.Combine(path, fileName)))
        File.Delete(Path.Combine(path, fileName));

    using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write)
    {
        CopyStream(inputStream, fs);
    }

    inputStream.Close();
    inputStream.Flush();
}
5
ответ дан vapcguy 21 August 2018 в 01:16
поделиться
  • 1
    Не нужно вызывать Close из-за using() – Alex78191 25 June 2017 в 13:07
  • 2
    @ Alex78191 Если вы говорите о inputStream.Close(), посмотрите еще раз - inputStream отправляется как переменная. using находится в выходном потоке path+filename. Если вы говорили о fs.Close() в середине using, извините, вы были в этом уверены, и я удалил это. – vapcguy 19 July 2017 в 15:52
20
ответ дан nawfal 31 October 2018 в 20:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: