ExcelReaderFactory,从 SftpFileStream 读取
ExcelReaderFactory, reading from SftpFileStream
我在使用 ExcelReaderFactory.CreateOpenXmlReader(streamReader)
读取 .xlsx 文件时出错,流 reader 是 SftpFileStream
(SftpClient.OpenRead(filePath)
).
我收到的错误消息是
Renci.SshNet.Common.SshException: General failure
我无法通过第一行代码。
using (var reader = ExcelReaderFactory.CreateOpenXmlReader(streamReader))
{
//Get reader as DataSet
var result = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true
}
});
.......
}
但是当我使用 System.IO.File.Open
的代码时,它工作正常。
堆栈:
at Renci.SshNet.Sftp.SftpSession.RequestRead(Byte[] handle, UInt64 offset, UInt32 length)
at Renci.SshNet.Sftp.SftpFileStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Compression.ZipHelper.ReadBytes(Stream stream, Byte[] buffer, Int32 bytesToRead)
at System.IO.Compression.ZipHelper.SeekBackwardsAndRead(Stream stream, Byte[] buffer, Int32& bufferPointer)
at System.IO.Compression.ZipHelper.SeekBackwardsToSignature(Stream stream, UInt32 signatureToFind)
at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
at System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen, Encoding entryNameEncoding)
at ExcelDataReader.Core.ZipWorker..ctor(Stream fileStream)
at ExcelDataReader.ExcelOpenXmlReader..ctor(Stream stream)
at ExcelDataReader.ExcelReaderFactory.CreateOpenXmlReader(Stream fileStream, ExcelReaderConfiguration configuration)
SftpFileStream.Seek
代码中显然存在错误。当用 SeekOrigin.End
调用时,它从文件末尾的位置减去 offset
,而不是添加它。
如果您可以修改 SSH.NET 代码,请在 SftpFileStream.Seek
中更改此语句的两个实例:
newPosn = attributes.Size - offset;
到
newPosn = attributes.Size + offset;
我已将 pull request with this fix 提交到 SSH.NET 存储库。
如果您无法更改 SSH.NET 代码,则必须解决该问题。
将 SftpFileStream
内容复制到临时 MemoryStream
并将其用于 ExcelReaderFactory
.
using (var memoryStream = new MemoryStream())
{
sftpFileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
using (var reader = ExcelReaderFactory.CreateOpenXmlReader(memoryStream))
{
// ...
}
}
或者如果您不想浪费内存来保存文件的另一个副本,您可以实现自己的 Stream
围绕 SftpFileStream
的包装器,它转换 SeekOrigin.End
SeekOrigin.Begin
用适当的 offset
.
有关此类实施的示例,请参阅:
注意ZipArchive
(ExcelReaderFactory
内部使用)使用Stream.Seek
和SeekOrigin.End
,因为ZIP中心目录在末尾压缩文件。 – XLSX 文件基本上是一个具有特定结构的 ZIP 文件。
我在使用 ExcelReaderFactory.CreateOpenXmlReader(streamReader)
读取 .xlsx 文件时出错,流 reader 是 SftpFileStream
(SftpClient.OpenRead(filePath)
).
我收到的错误消息是
Renci.SshNet.Common.SshException: General failure
我无法通过第一行代码。
using (var reader = ExcelReaderFactory.CreateOpenXmlReader(streamReader))
{
//Get reader as DataSet
var result = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true
}
});
.......
}
但是当我使用 System.IO.File.Open
的代码时,它工作正常。
堆栈:
at Renci.SshNet.Sftp.SftpSession.RequestRead(Byte[] handle, UInt64 offset, UInt32 length)
at Renci.SshNet.Sftp.SftpFileStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Compression.ZipHelper.ReadBytes(Stream stream, Byte[] buffer, Int32 bytesToRead)
at System.IO.Compression.ZipHelper.SeekBackwardsAndRead(Stream stream, Byte[] buffer, Int32& bufferPointer)
at System.IO.Compression.ZipHelper.SeekBackwardsToSignature(Stream stream, UInt32 signatureToFind)
at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
at System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen, Encoding entryNameEncoding)
at ExcelDataReader.Core.ZipWorker..ctor(Stream fileStream)
at ExcelDataReader.ExcelOpenXmlReader..ctor(Stream stream)
at ExcelDataReader.ExcelReaderFactory.CreateOpenXmlReader(Stream fileStream, ExcelReaderConfiguration configuration)
SftpFileStream.Seek
代码中显然存在错误。当用 SeekOrigin.End
调用时,它从文件末尾的位置减去 offset
,而不是添加它。
如果您可以修改 SSH.NET 代码,请在 SftpFileStream.Seek
中更改此语句的两个实例:
newPosn = attributes.Size - offset;
到
newPosn = attributes.Size + offset;
我已将 pull request with this fix 提交到 SSH.NET 存储库。
如果您无法更改 SSH.NET 代码,则必须解决该问题。
将
SftpFileStream
内容复制到临时MemoryStream
并将其用于ExcelReaderFactory
.using (var memoryStream = new MemoryStream()) { sftpFileStream.CopyTo(memoryStream); memoryStream.Position = 0; using (var reader = ExcelReaderFactory.CreateOpenXmlReader(memoryStream)) { // ... } }
或者如果您不想浪费内存来保存文件的另一个副本,您可以实现自己的
Stream
围绕SftpFileStream
的包装器,它转换SeekOrigin.End
SeekOrigin.Begin
用适当的offset
.有关此类实施的示例,请参阅:
注意ZipArchive
(ExcelReaderFactory
内部使用)使用Stream.Seek
和SeekOrigin.End
,因为ZIP中心目录在末尾压缩文件。 – XLSX 文件基本上是一个具有特定结构的 ZIP 文件。