通过NetworkStream传输档案
问题描述:
我想通过TCP连接复制目录树。源端应在文件系统的某处启动,以递归方式收集所有文件,并通过NetworkStream将其发送到接收端。这看起来不知何故,因为我可以在源端创建一个ZIP文件并将其发送给客户端。但也有一些要求:通过NetworkStream传输档案
- 不应该有任何创建临时文件
- 应该不会在内存中创建任何文件
- 的数据应该在带内发送。
前两个要求可以通过NetworkStream发送ZIP压缩文件来实现。 由于访问权限问题,应避免临时文件。目录树可能包含大量可能导致内存不足问题的数据。 第三个要求有点复杂。源和宿之间应该只建立一个TCP连接。
该协议在数据传输之前使用相同的连接来交换元信息,例如目录名称,并在数据传输后至少应答成功传输并且数据已写入文件系统。
我已经试过SharpZipLib。但是,当读取数据流时,总是读取4 KB的数据块。它需要流结束才能识别ZIP归档文件的结尾。这是不合适的,因为存档应该是带内的。
DotNetZip库文档提到它需要一个可寻找的流,什么不可用于NetworkStream。
这样的目录结构如何传输?
编辑阐明了文件数据必须嵌入在同一个TCP流中。
答
你说得对,DotNetZip似乎不直接支持不可查找的流。但它需要的唯一原因是因为它需要知道Position
,哪些不可查找的流不支持。
要解决这个问题,只需将NetworkStream
包装在作为DotNetZip一部分提供的CountingStream
中。如果你这样做,你应该可以使用ZipOutputStream
就好了。
作为替代方案,如果您不需要压缩,则可以创建自己的tar类协议。
喜欢的东西
- 4个字节的文件名的长度,包括路径(M)
- 8个字节的文件的长度(N)
- M个字节的文件名(包括路径),则使用UTF-8
- N个字节的文件本身
前每个文件的内容进行编码。
您是否尝试过使用Windows的“tar”,将其作为子进程启动?它正是你想要的,并且经常用来将dir-tree转换成流。另外它可以确定两个方向。你可以通过一个外部压缩器来管它,或者压缩C#中的流。我也认为不重新发明轮子是件好事。 – 2012-02-13 13:38:00
@EugenRieck为每个连接生成一个新进程有点贵。 (进一步,我会得到目录树中每个文件的512字节块。) – harper 2012-02-13 13:54:42
是的,产生一个进程的代价是。但与遍历目录树,处理每个文件,压缩输出并最终通过网络发送的成本相比,这是微不足道的。在压缩之后,512字节的块大小是不容易的。 – 2012-02-13 14:07:34