你如何使用 GZipStream 在内存中解压一个 gz 文件?
How do you unzip a gz file in memory using GZipStream?
我可能在这里做了一些明显愚蠢的事情。请指出!
我有一些 C# 代码可以从 SFTP 中下载一堆 .gz 文件(使用 SSH.NET Nuget package - 效果很好!)。每个 gz 中仅包含一个 .CSV 文件。我想将这些文件保存在内存中而不打磁盘(是的,我知道,存在服务器内存管理问题 - 这很好,因为这些文件相当小),在内存中解压缩它们以提取里面的 CSV 文件,然后 return 自定义 DTO (FtpFile
) 中的 CSV 文件集合。
我的问题是,虽然我的 SFTP 连接的 MemoryStream 中有数据,但它似乎从未填充到我的 GZipStream 中,或者从 GZipStream 到我的输出 MemoryStream 的复制失败。我已经尝试使用我自己的缓冲区对 Read 进行更传统的循环,但它的结果与此代码相同。
除了连接细节(它连接成功,所以不用担心),这是我的所有代码:
逻辑:
public static List<FtpFile> Foo()
{
var connectionInfo = new ConnectionInfo("example.com",
"username",
new PasswordAuthenticationMethod("username", "password"));
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
var searchResults = client.ListDirectory("/testdir")
.Where(obj => obj.IsRegularFile
&& obj.Name.ToLowerInvariant().StartsWith("test_")
&& obj.Name.ToLowerInvariant().EndsWith(".gz"))
.Take(2)
.ToList();
var fileResults = new List<FtpFile>();
foreach (var file in searchResults)
{
var ftpFile = new FtpFile { FileName = file.Name, FileSize = file.Length };
using (var fileStream = new MemoryStream())
{
client.DownloadFile(file.FullName, fileStream); // Success! All is good here, so far. :)
using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
{
using (var outputStream = new MemoryStream())
{
gzStream.CopyTo(outputStream);
byte[] outputBytes = outputStream.ToArray(); // No data. Sad panda. :'(
ftpFile.FileContents = Encoding.ASCII.GetString(outputBytes);
fileResults.Add(ftpFile);
}
}
}
}
return fileResults;
}
}
FtpFile(我正在填充一个简单的 DTO):
public class FtpFile
{
public string FileName { get; set; }
public long FileSize { get; set; }
public string FileContents { get; set; }
}
PSA 如果有人来复制此代码,请注意这不是好代码,因为您可能会有一些 严重这段代码的内存管理问题!最好的做法是将其流式传输到磁盘,这是 而不是 在此代码中完成的!我的需求非常具体,因为我必须同时将这些文件保存在内存中以用于我正在构建的内容。
如果您要将数据插入到流中,请确保在解压缩之前先找到它的来源。
以下应该可以解决您的问题:
using (var fileStream = new MemoryStream())
{
client.DownloadFile(file.FullName, fileStream); // Success! All is good here, so far. :)
fileStream.Seek(0, SeekOrigin.Begin);
using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
{
using (var outputStream = new MemoryStream())
{
gzStream.CopyTo(outputStream);
byte[] outputBytes = outputStream.ToArray(); // No data. Sad panda. :'(
ftpFile.FileContents = Encoding.ASCII.GetString(outputBytes);
fileResults.Add(ftpFile);
}
}
}
我可能在这里做了一些明显愚蠢的事情。请指出!
我有一些 C# 代码可以从 SFTP 中下载一堆 .gz 文件(使用 SSH.NET Nuget package - 效果很好!)。每个 gz 中仅包含一个 .CSV 文件。我想将这些文件保存在内存中而不打磁盘(是的,我知道,存在服务器内存管理问题 - 这很好,因为这些文件相当小),在内存中解压缩它们以提取里面的 CSV 文件,然后 return 自定义 DTO (FtpFile
) 中的 CSV 文件集合。
我的问题是,虽然我的 SFTP 连接的 MemoryStream 中有数据,但它似乎从未填充到我的 GZipStream 中,或者从 GZipStream 到我的输出 MemoryStream 的复制失败。我已经尝试使用我自己的缓冲区对 Read 进行更传统的循环,但它的结果与此代码相同。
除了连接细节(它连接成功,所以不用担心),这是我的所有代码:
逻辑:
public static List<FtpFile> Foo()
{
var connectionInfo = new ConnectionInfo("example.com",
"username",
new PasswordAuthenticationMethod("username", "password"));
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
var searchResults = client.ListDirectory("/testdir")
.Where(obj => obj.IsRegularFile
&& obj.Name.ToLowerInvariant().StartsWith("test_")
&& obj.Name.ToLowerInvariant().EndsWith(".gz"))
.Take(2)
.ToList();
var fileResults = new List<FtpFile>();
foreach (var file in searchResults)
{
var ftpFile = new FtpFile { FileName = file.Name, FileSize = file.Length };
using (var fileStream = new MemoryStream())
{
client.DownloadFile(file.FullName, fileStream); // Success! All is good here, so far. :)
using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
{
using (var outputStream = new MemoryStream())
{
gzStream.CopyTo(outputStream);
byte[] outputBytes = outputStream.ToArray(); // No data. Sad panda. :'(
ftpFile.FileContents = Encoding.ASCII.GetString(outputBytes);
fileResults.Add(ftpFile);
}
}
}
}
return fileResults;
}
}
FtpFile(我正在填充一个简单的 DTO):
public class FtpFile
{
public string FileName { get; set; }
public long FileSize { get; set; }
public string FileContents { get; set; }
}
PSA 如果有人来复制此代码,请注意这不是好代码,因为您可能会有一些 严重这段代码的内存管理问题!最好的做法是将其流式传输到磁盘,这是 而不是 在此代码中完成的!我的需求非常具体,因为我必须同时将这些文件保存在内存中以用于我正在构建的内容。
如果您要将数据插入到流中,请确保在解压缩之前先找到它的来源。
以下应该可以解决您的问题:
using (var fileStream = new MemoryStream())
{
client.DownloadFile(file.FullName, fileStream); // Success! All is good here, so far. :)
fileStream.Seek(0, SeekOrigin.Begin);
using (var gzStream = new GZipStream(fileStream, CompressionMode.Decompress))
{
using (var outputStream = new MemoryStream())
{
gzStream.CopyTo(outputStream);
byte[] outputBytes = outputStream.ToArray(); // No data. Sad panda. :'(
ftpFile.FileContents = Encoding.ASCII.GetString(outputBytes);
fileResults.Add(ftpFile);
}
}
}