web-dev-qa-db-ja.com

C#のファイルにストリームを保存する方法

ストリームで初期化したStreamReaderオブジェクトがあります。このストリームをディスクに保存します(ストリームは.gif.jpg.pdfのいずれかです)。

既存のコード

StreamReader sr = new StreamReader(myOtherObject.InputStream);
  1. これをディスクに保存する必要があります(私はファイル名を持っています)。
  2. 将来的には、これをSQL Serverに保存したいと思うかもしれません。

SQL Serverに保存する場合に必要なエンコードタイプもありますが、正しいですか?

645
Loadman

Jon Skeetの回答でTilendorが強調しているように、.NET 4からストリームはCopyToメソッドを持ちます。

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);
}
831
Antoine Leclair

あなたは してはいけません (gifsやjpgsのような)バイナリファイルにStreamReaderを使わないでください。 StreamReader text data用です。 確かに 任意のバイナリデータに使用すると、データが失われます。 (Encoding.GetEncoding(28591)を使えばおそらく大丈夫でしょうが、要点は何ですか?)

なぜあなたはStreamReaderを使う必要があるのですか?バイナリデータバイナリデータとして保存し、それをバイナリデータとしてディスク(またはSQL)に書き戻すだけではどうでしょうか。

編集:これは人々が見たいものであるように思われるように...あなたが 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で導入され、基本的に同じ目的で使用されています。

493
Jon Skeet
public void CopyStream(Stream stream, string destPath)
{
  using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
  {
    stream.CopyTo(fileStream);
  }
}
65
Darren Corbett
private void SaveFileStream(String path, Stream stream)
{
    var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
    stream.CopyTo(fileStream);
    fileStream.Dispose();
}
22
jhonjairoroa87

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 MB未満)でしか使用していません。 1つのストリーム、ストリーム間のコピー、エンコードの必要なし、バイトを書き込むだけです! StreamReaderで物事を過度に複雑にする必要はありません。すでにストリームがある場合は、.ToArray()で直接bytesに変換できます!

この方法で見られる潜在的な欠点は、大きなファイルがあり、それをストリームとして使用し、.CopyTo()または同等の機能を使用すると、バイト配列を使用する代わりにFileStreamでストリーミングできることですバイトを1つずつ読み取ります。その結果、この方法で行うのが遅くなる可能性があります。しかし、FileStream.Write()メソッドがバイトの書き込みを処理し、一度に1バイトしか実行しないため、チョークする必要はありません。したがって、ストリームをbyte[]オブジェクトとして保持するのに十分なメモリが必要ですOracleBlobを取得してこれを使用した私の状況では、byte[]に移動する必要がありました。それは十分に小さく、さらに、利用可能なストリーミングがなかったため、送信しました上記の私の関数に私のバイト。

ストリームを使用する別のオプションは、別の投稿にあるJon SkeetのCopyStream関数で使用することです。これは、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();
}
10
vapcguy
//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

なぜ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);
     }
}
5
Adrian

もう1つの選択肢は、ストリームを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.
}
4
nawfal
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
Angelo