Question Comment enregistrer un flux dans un fichier en C #?


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

Code existant:

StreamReader sr = new StreamReader(myOtherObject.InputStream);
  1. Je dois enregistrer ceci sur le disque (j'ai le nom de fichier).
  2. Dans le futur, je pourrais vouloir stocker ceci à SQL Server.

J'ai aussi le type d'encodage, dont j'ai besoin si je le stocke sur SQL Server, correct?


587
2018-01-04 20:04


origine


Réponses:


Comme l'a souligné Tilendor dans la réponse de Jon Skeet, les cours d'eau ont un CopyTo méthode 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 le using syntaxe:

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

761
2018-04-01 16:01



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

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

EDIT: Comme cela semble être quelque chose que les gens veulent voir ... si vous faire Je veux juste copier un flux dans un autre (par exemple dans 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 vider un flux dans 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.


474
2018-01-04 20:08



public void CopyStream(Stream stream, string destPath)
{
  using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
  {
    stream.CopyTo(fileStream);
  }
}

57
2017-08-01 20:25



private void SaveFileStream(String path, Stream stream)
{
    var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
    stream.CopyTo(fileStream);
    fileStream.Dispose();
}

18
2017-12-11 14:38



//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.
*/

9
2017-07-07 14:30



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

7
2018-04-23 22:49



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

5
2017-07-16 06:47



Je ne reçois pas toutes les réponses en utilisant CopyTo, où les systèmes utilisant l'application n'ont peut-être pas été mis à niveau vers .NET 4.0+. Je sais que certains voudraient forcer les gens à se mettre à niveau, mais la compatibilité est également agréable.

Une autre chose, je ne suis pas en utilisant 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 les é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 .jpg fichier, bien que j'avoue que je l'ai seulement utilisé 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 trop compliquer les choses avec StreamReader Si vous avez déjà un flux, vous pouvez convertir en bytes directement avec .ToArray()!

Seuls les inconvénients potentiels que je peux voir en le faisant de cette façon est s'il y a un gros fichier que vous avez, en l'ayant comme un flux et en utilisant .CopyTo() ou équivalent permet FileStream pour le diffuser au lieu d'utiliser un tableau d'octets et de lire les octets un par un. Il pourrait être plus lent de le faire de cette façon, en conséquence. Mais il ne devrait pas étouffer depuis le .Write() méthode de FileStream gère l'écriture des octets, et il ne fait qu'un octet à la fois, de sorte qu'il ne sera pas boucher la mémoire, sauf que vous devrez avoir assez de mémoire pour maintenir le flux en tant que byte[] objet. Dans ma situation où je l'ai utilisé, obtenir un OracleBlob, Je devais aller à un byte[], il était assez petit, et d'ailleurs, il n'y avait pas de streaming disponible pour moi, de toute façon, alors je viens d'envoyer mes octets à ma fonction, ci-dessus.

Une autre option, en utilisant un flux, serait de l'utiliser avec Jon Skeet CopyStreamfonction qui était dans un autre poste - cela utilise juste FileStream prendre le flux d'entrée et créer le fichier directement. Il n'utilise pas File.Create, comme il l'a fait (ce qui semblait initialement être problématique pour moi, mais plus tard, il a été trouvé que c'était probablement 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
2017-10-12 13:57



Une autre option consiste à obtenir le flux à un byte[] et utilise File.WriteAllBytes. Cela devrait faire:

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

En l'enveloppant dans une méthode d'extension lui donne une meilleure dénomination:

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

4
2018-02-13 11:04