2012-02-13 20 views
0

TCP接続を介してディレクトリツリーをコピーしたいとします。ソース側は、すべてのファイルを再帰的に収集し、NetworkStream経由でシンク側に送信するために、ファイルシステムのどこかで開始する必要があります。ソースサイドでZIPファイルを作成してクライアントに送信できるように見えます。NetworkStream経由でアーカイブを転送する

  • あり作成すべきではない一時ファイル
  • メモリ内のすべてのファイルが作成されるべきではない
  • データは、インバンドで送信する必要があります。しかし、いくつかの要件があります。

最初の2つの要件は、NetworkStream経由でZIPアーカイブを送信することで実現できます。 アクセス権の問題により一時ファイルを避ける必要があります。ディレクトリツリーには、膨大な量のデータが格納され、メモリ不足の問題を引き起こす可能性があります。 3番目の要件は少し複雑です。ソースとシンクの間に1つのTCP接続しか確立されていないはずです。

プロトコルは、ディレクトリ名のようなメタ情報の交換のために、データ転送の前に同じ接続を使用し、少なくとも成功した転送を確認し、データがファイルシステムに書き込まれたことを確認します。

私はすでにSharpZipLibを試しました。しかし、これはストリームを読むときに常に4キロバイトのチャンクを読み込みます。 ZIPアーカイブの終わりを識別するためにストリームの終わりが必要です。アーカイブはインバンドである必要があるため、これは不適切です。

DotNetZipライブラリのドキュメントには、シーク可能なストリームが必要であることが記載されています。ネットワークストリームでは利用できないものがあります。

このようなディレクトリ構造はどのように転送できますか?

は、ファイルデータが同じTCPストリームに埋め込まれている必要があることを明確にしました。

+0

Windows用の 'tar'を試しましたか?サブプロセスとして起動しましたか?それはあなたが望むものを正確に行い、ディレクトリツリーをストリームに変換するために日常的に使用されます。さらに、それは両方向を行います。外部のコンプレッサーでパイプするか、C#の内部でストリームを圧縮することができます。私はまた、車輪を再発明しないことが良いことだと思います。 –

+0

@EugenRieck接続ごとに新しいプロセスを作成するのは少し高価です。 (さらに、ディレクトリツリー内の各ファイルに対して512バイトのブロックを取得します。) – harper

+0

はい、プロセスを生成するコストがあります。しかし、ディレクトリツリーを走査し、すべての単一のファイルを処理し、出力を圧縮し、最後にネットワーク経由で送信するコストと比較すると、きわめて小さいです。 512バイトのブロックサイズは、圧縮した後も簡単です。 –

答えて

0

DotNetZipは、シーク不可能なストリームを直接サポートしていないようです。しかし、それが必要な唯一の理由は、シーク不可能なストリームがサポートしていないPositionを知る必要があるからです。

これを修正するには、NetworkStreamCountingStreamに入れてください(DotNetZipの一部として提供されています)。あなたがそうするなら、ZipOutputStreamをうまく使うことができるはずです。

圧縮を必要としない場合は、独自のtar形式のプロトコルを作成できます。パスを含むファイル名の長さ

何かなど

  • 4バイト、(M)ファイルの長さ
  • 8バイト(N)ファイル名
  • Mバイト(含パス)、ファイル自体

前部各ファイルの内容のためにUTF-8

  • Nバイトを使用してエンコード。