Comment enregistrer un flux dans un fichier en C#?

j'ai un objet StreamReader que j'ai initialisé avec un stream, maintenant je veux sauvegarder ce stream sur disque (le stream peut être un .gif ou .jpg ou .pdf ).

Code Existant:

StreamReader sr = new StreamReader(myOtherObject.InputStream);
  1. j'ai besoin de le sauvegarder sur disque (j'ai le nom du fichier).
  2. dans le futur, je voudrais peut-être stocker ceci sur SQL Server.

j'ai aussi le type d'encodage, qui Je vais avoir besoin si je le stocke à SQL Server, correct?

600
demandé sur sbeliakov 2009-01-04 23:04:39

9 réponses

tel que souligné par Tilendor dans la réponse de Jon Skeet, les cours d'eau ont une méthode CopyTo depuis .NET 4.

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

ou avec la syntaxe using :

using (var fileStream = File.Create("C:\Path\To\File"))
{
    myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
    myOtherObject.InputStream.CopyTo(fileStream);
}
778
répondu Antoine Leclair 2014-12-28 15:02:27

vous ne doit pas utiliser StreamReader pour les fichiers binaires (comme gifs ou jpgs). StreamReader est pour texte données. Vous serez presque certainement perdre des données si vous l'utilisez pour des données binaires arbitraires. (Si vous utilisez l'Encodage.GetEncoding(28591) vous serez probablement d'accord, mais quel est le point?)

Pourquoi avez-vous besoin d'utiliser un StreamReader ? Pourquoi ne pas simplement garder les données binaires comme données binaires et l'écrire sur le disque (ou SQL) comme données binaires?

EDIT: comme cela semble être quelque chose que les gens veulent voir... si vous do voulez simplement copier un flux vers un autre (par exemple vers un fichier) utilisez quelque chose comme ceci:

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

Pour l'utiliser pour faire un dump d'un flux vers un fichier, par exemple:

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

notez que Stream.CopyTo a été introduit dans .NET 4, servant essentiellement le même but.

478
répondu Jon Skeet 2017-08-01 13:05:44
public void CopyStream(Stream stream, string destPath)
{
  using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
  {
    stream.CopyTo(fileStream);
  }
}
58
répondu Darren Corbett 2014-04-04 09:08:56
private void SaveFileStream(String path, Stream stream)
{
    var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
    stream.CopyTo(fileStream);
    fileStream.Dispose();
}
19
répondu jhonjairoroa87 2014-05-26 06:21:42
//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
répondu George 2011-07-07 14:48:37

pourquoi ne pas utiliser un objet 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
répondu Adrian 2010-10-14 11:27:39

Je n'obtiens pas toutes les réponses en utilisant CopyTo , où peut-être les systèmes utilisant l'application pourraient ne pas avoir été mis à niveau à .net 4.0+. Je sais que certains voudraient forcer les gens à mettre à jour, mais la compatibilité est également agréable, aussi.

autre chose, Je ne peux pas utiliser un flux pour copier à partir d'un autre flux en premier lieu. Pourquoi ne pas simplement faire:

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

une Fois que vous avez les octets, vous pouvez facilement écrire dans un fichier:

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

ce code fonctionne comme je l'ai testé avec un fichier .jpg , bien que j'admette ne l'avoir utilisé qu'avec de petits fichiers (moins de 1 Mo). Un flux, pas de copie entre les flux, pas d'encodage nécessaire, il suffit d'écrire les octets! Pas besoin de compliquer les choses avec StreamReader si vous avez déjà un flux, vous pouvez convertir le bytes directement avec .ToArray() !

seuls les inconvénients potentiels que je peux voir en le faisant de cette façon est s'Il ya une grande le fichier que vous avez, l'ayant comme un flux et en utilisant .CopyTo() ou l'équivalent permet FileStream de le flux au lieu d'utiliser un tableau d'octets et de lire les octets un par un. Ça pourrait être plus lent de le faire de cette façon, en conséquence. Mais il ne devrait pas s'étouffer depuis la méthode .Write() de la FileStream gère l'écriture des octets, et il ne le fait qu'un octet à la fois, donc il ne va pas bloquer la mémoire, sauf que vous aurez assez de mémoire pour tenir le flux comme un byte[] objet . Dans ma situation où j'ai utilisé ceci, obtenir un OracleBlob , j'ai dû aller à un byte[] , il était assez petit, et en outre, il n'y avait pas de diffusion en continu disponible pour moi, de toute façon, donc j'ai juste envoyé mes octets à ma fonction, ci-dessus.

une autre option, en utilisant un flux, serait de l'utiliser avec la fonction CopyStream de Jon Skeet qui était dans un autre post - cela utilise juste FileStream pour prendre le flux d'entrée et créer le fichier à partir de celui-ci directement. Il n' ne pas utiliser File.Create , comme il l'a fait (ce qui a d'abord semblé problématique pour moi, mais plus tard a trouvé que c'était probablement juste un bug 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
répondu vapcguy 2017-07-19 15:53:13
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
répondu Angelo 2013-07-16 07:10:14

une autre option est d'obtenir le flux à un byte[] et utiliser File.WriteAllBytes . Cela devrait faire:

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

L'envelopper dans une méthode d'extension lui donne un meilleur nom:

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.
}
3
répondu nawfal 2014-02-13 11:04:43