1

ExcelReaderFactory.CreateOpenXmlReader(streamReader)使用流阅读器读取 .xlsx 文件时出现错误SftpFileStreamSftpClient.OpenRead(filePath))。

我收到的错误消息是

Renci.SshNet.Common.SshException:一般故障

我无法通过第一行代码。

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)
4

1 回答 1

2

代码中显然存在错误SftpFileStream.Seek。当使用 调用时SeekOrigin.End,它会从文件末尾的位置减去offset,而不是添加它。

如果您可以修改 SSH.NET 代码,请在以下位置更改此语句的两个实例SftpFileStream.Seek

newPosn = attributes.Size - offset;

newPosn = attributes.Size + offset;

我已向SSH.NET 存储库提交了包含此修复程序的拉取请求。


如果您无法更改 SSH.NET 代码,则必须解决该问题。

  1. Either copy the SftpFileStream contents to a temporary MemoryStream and use that with ExcelReaderFactory.

     using (var memoryStream = new MemoryStream())
     {
         sftpFileStream.CopyTo(memoryStream);
         memoryStream.Position = 0;
         using (var reader = ExcelReaderFactory.CreateOpenXmlReader(memoryStream))
         {
             // ...
         }
     }
    
  2. Or if you do not want to waste memory holding another copy of the file, you can implement own Stream wrapper around SftpFileStream, which translates SeekOrigin.End to SeekOrigin.Begin with a proper offset.

    For an example of such implementation, see:
    List files inside ZIP file located on SFTP server in C#


Note that ZipArchive (internally used by ExcelReaderFactory) uses Stream.Seek with SeekOrigin.End, because ZIP central directory is at the end of the ZIP file. – XLSX file is basically a ZIP file with a specific structure.

于 2019-01-11T13:38:59.430 回答