web-dev-qa-db-ja.com

メモリストリームとファイルストリームの違い

シリアル化中に、メモリストリームまたはファイルストリームを使用できます。

これら2つの基本的な違いは何ですか?メモリストリームとはどういう意味ですか?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;

namespace Serilization
{
    class Program
    {
        static void Main(string[] args)
        {
            MemoryStream aStream = new MemoryStream();
            BinaryFormatter aBinaryFormat = new BinaryFormatter();
            aBinaryFormat.Serialize(aStream, person);
            aStream.Close();
        }
    }
}
50
Raghav55

ストリームはバイトの表現です。これらのクラスは両方とも、定義により抽象的であるStreamクラスから派生します。

名前が示すように、FileStreamはファイルの読み取りと書き込みを行い、MemoryStreamはメモリの読み取りと書き込みを行います。したがって、ストリームの保存場所に関連しています。

現在、これらの両方をどのように使用するかによって異なります。たとえば、データベースからバイナリデータを読み取りたい場合、MemoryStreamにアクセスするとします。ただし、システム上のファイルを読み取りたい場合は、FileStreamにアクセスします。

MemoryStreamの簡単な利点の1つは、アプリケーションで一時的なバッファーとファイルを作成する必要がないことです。

76
Enigma State

ここでの他の答えは素晴らしいですが、スチームが提供する目的を非常に高いレベルで見るものが役立つと思いました。以下の説明では多少の簡略化が行われていますが、うまくいけばアイデアが理解できると思います。

ストリームとは何ですか?

ストリームは、事実上、2つの場所の間のデータの流れであり、パイプの内容ではなくパイプです。

悪い例え

水の淡水化プラント(海水を取り、塩を除去し、きれいな飲料水を水ネットワークに出力するもの)を想像してください。

海水淡水化プラントは、一度にすべての海から塩を除去することはできません(また、海水魚がどこに生息するのでしょうか?)。

  • 植物に一度に一定量の水を吸い込むSeaStream
  • SeaStreamDesalinationStreamに接続され、塩を除去します
  • そして、DesalinationStreamの出力はDrinkingWaterNetworkStreamに接続され、塩分を含まない水を飲料水に出力します。

OK、それではコンピューターとは何の関係があるのでしょうか?

大きなファイルを一度に移動すると問題が発生する可能性があります

コンピューティングでは、2つの場所間でデータを移動することがよくあります。外部ハードドライブからデータベースのバイナリフィールドへ(別の回答にある例を使用するため)。ファイルからすべてのデータをロケーションAからコンピューターのメモリにコピーし、そこからロケーションBにコピーすることでそれを行うことができますが、ファイルが大きい場合、またはソースまたは宛先が潜在的に信頼できない場合、ファイル全体を一度に移動することができます実行不可能または賢明ではありません。

たとえば、USBスティック上の大きなファイルをデータベース内のフィールドに移動するとします。 「System.IO.File」オブジェクトを使用してファイル全体をコンピューターのメモリに取得し、データベース接続を使用してそのファイルをデータベースに渡すことができます。

しかし、それは潜在的に問題があります。ファイルがコンピューターの使用可能なRAMよりも大きい場合はどうでしょうか。これで、ファイルは潜在的にハードドライブにキャッシュされますが、これは低速であり、コンピューターの速度も低下する可能性があります。

同様に、データソースが信頼できない場合、例えば低速で不安定なWiFi接続を使用してネットワークドライブからファイルをコピーしますか?大きなファイルを一度にコピーしようとすると、ファイルの半分が取得されてから接続が切断され、最初からやり直す必要があるため、イライラする可能性があります。

ファイルを分割して、一度に1つずつ移動する方が良い場合があります

したがって、ファイル全体を一度に取得するのではなく、一度に1つずつファイルを取得し、各ピースを1つずつ宛先に渡す方がよいでしょう。これはStreamが行うことであり、それがあなたが言及した2つの異なるタイプのストリームが来る場所です:

  • FileStreamを使用して、一度に1つずつファイルからデータを取得できます
  • また、データベースAPIは、一度に1つのピースに書き込むことができるMemoryStreamエンドポイントを使用可能にする場合があります。
  • これらの2つの「パイプ」を接続して、ファイルからデータベースへファイルの断片を流します。

ファイルが大きすぎてRAMに保持できなかったとしても、ストリームがなければ、必要のない番号操作または読み取り/書き込み操作を実行していました。私たちが実施している段階は次のとおりです。

  1. ディスクからデータを取得する(遅い)
  2. コンピューターのメモリ内のFileオブジェクトへの書き込み(少し高速)
  3. コンピューターのメモリ内のそのFileオブジェクトからの読み取り(より高速)
  4. データベースへの書き込み(おそらく、そのパイプの最後に回転するディスクハードドライブがあるため、おそらく遅い)

ストリームを使用すると、ファイル全体を一度にコンピューターのメモリにドラッグするのではなく、中間の2つの段階を概念的に廃止できます。操作の出力を取得してデータを取得し、その操作に直接パイプしてデータベースにデータを渡します。

ストリームのその他の利点

このようにデータの取得をデータの書き込みから分離することにより、データの取得と引き渡しの間のアクションを実行することもできます。たとえば、暗号化ステージを追加したり、着信データを複数のタイプの出力ストリーム(たとえば、FileStreamとNetworkStream)に書き込むことができます。

また、ストリームを使用すると、転送が途中で失敗した場合に操作を再開できるコードを作成できます。移動したピースの数を追跡することにより、転送が失敗した場合(たとえば、ネットワーク接続がドロップアウトした場合)、最後のピースを受信したポイントからストリームを再起動できます(これはoffsetBeginReadメソッドで)。

14
tomRedox

最も単純な形式では、MemoryStreamはデータをメモリに書き込み、FileStreamはデータをファイルに書き込みます。

通常、ストリームが必要な場合はMemoryStreamを使用しますが、ディスクに何もヒットさせたくないので、ファイルをディスクに書き込むときにFileStreamを使用します。

8
AllenG

ファイルストリームはファイルから読み取りますが、メモリストリームを使用して、コンピューターの内部メモリ(RAM)にマップされたデータを読み取ることができます。基本的に、メモリからバイトのストリームを読み書きしています。

6
Tudor

この問題について苦い経験を​​したので、ここに私が見つけたものを示します。パフォーマンスが必要な場合は、ファイルストリームの内容をメモリストリームにコピーする必要があります。 144個のファイル(それぞれ528kバイト)のコンテンツを処理し、結果をユーザーに提示する必要がありました。約250秒かかりました。 (!!!!)。何も変更せずに各ファイルストリームの内容をメモリストリームにコピーしたとき(CopyToメソッド)、時間は約32秒に短縮されました。あるストリームを別のストリームにコピーするたびに、ストリームは宛先ストリームの最後に追加されるため、コピーする前にストリームを「巻き戻す」必要があることに注意してください。それが役に立てば幸い。

5
ManosG

メモリストリームは、メモリ内バッファを介してデータを処理します。ファイルストリームは、ディスク上のファイルを処理します。

2

私の意見では、メモリ内のオブジェクトをシリアル化することはほとんど役に立ちません。オブジェクトをディスクに保存する場合は、オブジェクトをシリアル化する必要があります。通常、シリアル化はオブジェクト(メモリ内)からディスクに対して行われ、逆シリアル化は保存されたシリアル化オブジェクト(ディスク上)からオブジェクト(メモリ内)に対して行われます。

そのため、ほとんどの場合、ディスクにシリアル化する必要があるため、シリアル化にはFilestreamを使用します。

0
ThunderGr