c# - 列出位于 C# 中 SFTP 服务器上的 ZIP 文件中的文件
问题描述
我需要通过 ASP.NET Core 以编程方式处理来自 SFTP 服务器 (WinSCP) 的 ZIP 文件中的文件夹。
有什么方法可以在不下载到本地计算机的情况下获取 ZIP 文件中的文件列表?因为文件大小会很高并且不会以一致的方式。任何帮助,将不胜感激。
解决方案
使用SSH.NET 库,它可以很简单:
using (var client = new SftpClient(host, username, password)
{
client.Connect();
using (Stream stream = client.OpenRead("/remote/path/archive.zip"))
using (var archive = new ZipArchive(stream, ZipArchiveMode.Read))
{
foreach (var entry in archive.Entries)
{
Console.WriteLine(entry);
}
}
}
您需要参考System.IO.Compression
程序集来获取ZipArchive
.
该代码将仅读取(下载)ZIP 中央目录记录,而不是整个 ZIP 存档。有关证明,请参见答案的末尾。
不幸的是,库中有一个错误。要解决它,您必须Stream
像这样实现包装器实现:
class FixStream : Stream
{
public override long Seek(long offset, SeekOrigin origin)
{
long result;
// workaround for SSH.NET bug in implementation of SeekOrigin.End
if (origin == SeekOrigin.End)
{
result = _stream.Seek(Length + offset, SeekOrigin.Begin);
}
else
{
result = _stream.Seek(offset, origin);
}
return result;
}
// passthrough implementation of the rest of Stream interface
public override bool CanRead => _stream.CanRead;
public override bool CanSeek => _stream.CanSeek;
public override bool CanWrite => _stream.CanWrite;
public override long Length => _stream.Length;
public override long Position {
get => _stream.Position; set => _stream.Position = value; }
public FixStream(Stream stream)
{
_stream = stream;
}
public override void Flush()
{
_stream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _stream.Read(buffer, offset, count);
}
public override void SetLength(long value)
{
_stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_stream.Write(buffer, offset, count);
}
private Stream _stream;
}
并将其包装SftpFileStream
起来:
using (Stream stream = client.OpenRead("/remote/path/archive.zip"))
using (var stream2 = new FixStream(stream))
using (var archive = new ZipArchive(stream2, ZipArchiveMode.Read))
{
...
}
为了证明它确实有效,我已将日志记录添加到FixStream
. 当使用包含两个条目的 18 MB(18265315 字节)ZIP 存档的代码时,会生成以下内容。所以只从流中读取了 244 个字节。实际上更多是从实际的远程 SFTP 文件中读取的,因为 SSH.NET 会缓冲读取(否则代码将非常无效,特别是在这种情况下,正如您所看到的那样,ZipArchive
它会进行大量的小读取)。默认 SSH.NET 缓冲区为 32 KB ( SftpClient.BufferSize
)。
Tried to seek to -18 from End => converting to seek to 18265297 from Begin
Seeked to 18265297 from Begin => 18265297
Seeked to -32 from Current => 18265265
Tried to read 32, got 32
Seeked to -32 from Current => 18265265
Seeked to 28 from Current => 18265293
Tried to read 4, got 4
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 2, got 2
Seeked to 18265075 from Begin => 18265075
Tried to read 4, got 4
Tried to read 1, got 1
Tried to read 1, got 1
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 28, got 28
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 32, got 32
Set position to 18265185
Tried to read 4, got 4
Tried to read 1, got 1
Tried to read 1, got 1
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 4, got 4
Tried to read 4, got 4
Tried to read 26, got 26
Tried to read 2, got 2
Tried to read 2, got 2
Tried to read 32, got 32
Set position to 18265293
Tried to read 4, got 4
推荐阅读
- r - 如何根据用户输入创建具有实时数据的闪亮应用程序?
- vue-component - “属性或方法“项目”未在实例上定义,但在渲染期间引用”
- swiftui - SwiftUI 弹出框背景颜色
- python - 在python中用多行替换一行的最佳方法是什么?
- xml - Powershell替换XML文件中的值
- c# - 为什么航点列表和代理列表是空的?
- javascript - 向 Docusaurus 网站的 URL 添加可选参数
- php - 而不是 PHP 中,我该怎么做?
- android - 重用片段、主活动和导航菜单之间的共享 ViewModel 实例以显示不同的信息
- python - 如何计算发生的异常数量并打印出来?