通过 NetworkStream 传输档案

Posted

技术标签:

【中文标题】通过 NetworkStream 传输档案【英文标题】:Transfer an archive through NetworkStream 【发布时间】:2012-02-13 13:31:56 【问题描述】:

我想通过 TCP 连接复制目录树。源端应该从文件系统中的某个地方开始以递归方式收集所有文件并通过 NetworkStream 将它们发送到接收端。这看起来有点像我可以在源端创建一个 ZIP 文件并将其发送到客户端。但有一些要求:

不应创建任何临时文件 不应在内存中创建任何文件 数据应在带内发送。

前两个要求可以通过 NetworkStream 发送 ZIP 存档来满足。 由于访问权限问题,应避免使用临时文件。目录树可能包含大量数据,这些数据可能会导致内存不足问题。 第三个要求有点复杂。 source 和 sink 之间应该只建立一个 TCP 连接。

该协议在数据传输之前使用相同的连接来交换目录名称等元信息,并且在数据传输之后至少确认传输成功并且数据已写入文件系统。

我已经尝试过 SharpZipLib。但这在读取流时总是读取 4 KB 的块。它需要一个流结束来标识 ZIP 存档的结束。这是不合适的,因为存档应该是带内的。

DotNetZip 库文档提到它需要一个可搜索的流,而 NetworkStream 没有。

如何转移这样的目录结构?

编辑阐明文件数据必须嵌入到同一个 TCP 流中。

【问题讨论】:

您是否尝试过tar for Windows,只是将其作为子进程启动?它完全符合您的要求,并且通常用于将目录树转换为流。此外,它有两个方向。您可以通过外部压缩器对其进行管道传输,也可以在 C# 中压缩流。我也认为不重新发明***是件好事。 @EugenRieck 为每个连接生成一个新进程有点昂贵。 (此外,我会为目录树中的每个文件获得一个 512 字节的块。) 是的,产生一个进程是有成本的。但与遍历目录树、处理每个文件、压缩输出并最终通过网络发送的成本相比,它绝对是微不足道的。压缩后 512 字节的块大小是显而易见的。 将遍历委托给tar之类的另一个进程如何降低成本? 我的意思是:遍历的成本比外部进程的成本高(数十?数百?)数千倍,因此产生外部进程并没有真正的区别 -作为回报,您将获得一个久经考验的交钥匙解决方案。拥有易于与 Unix 兼容的流格式也可能是一个好点(相应的 Unix 应用程序是 2 行 shellscript)。只是我的 2 美分。 【参考方案1】:

您说得对,DotNetZip 似乎并不直接支持不可搜索的流。但它需要这样做的唯一原因是因为它需要知道不可搜索的流不支持的Position

要解决此问题,只需将 NetworkStream 包装在作为 DotNetZip 的一部分提供的 CountingStream 中。如果你这样做,你应该可以使用ZipOutputStream 就好了。

作为替代方案,如果您不需要压缩,您可以创建自己的类似 tar 的协议。

类似

4字节为文件名长度,包括路径(M) 8 字节为文件长度 (N) M 字节的文件名(包括路径),使用 UTF-8 编码 文件本身内容的 N 个字节

在每个文件之前。

【讨论】:

以上是关于通过 NetworkStream 传输档案的主要内容,如果未能解决你的问题,请参考以下文章

Socket网络编程(C#)----同步传输字符串

如何将档案 (zip) 通过管道传输到 S3 存储桶

TcpClient 的 NetworkStream 啥时候完成一次读操作?

C# 通过tcp协议向硬件发送命令,networkstream read 读取返回信息时卡死。

个人档案

iPadOS 15 新功能:下载传输档案有进度条了