ExcelReaderFactory, чтение из SftpFileStream - PullRequest
0 голосов
/ 11 января 2019

Я получаю сообщение об ошибке при чтении файла .xlsx с использованием ExcelReaderFactory.CreateOpenXmlReader(streamReader), а потоковая программа чтения - SftpFileStream (SftpClient.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, он работает нормально.

Stack:

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)

1 Ответ

0 голосов
/ 11 января 2019

В коде SftpFileStream.Seek явно есть ошибка. При вызове с SeekOrigin.End он вычитает offset из позиции конца файла, а не добавляет его.

Если вы можете изменить код SSH.NET, измените оба экземпляра этого оператора в SftpFileStream.Seek:

newPosn = attributes.Size - offset;

до

newPosn = attributes.Size + offset;

Я отправил запрос на получение с этим исправлением в репозиторий SSH.NET.


Если вы не можете изменить код SSH.NET, вам придется обойти это.

  1. Либо скопируйте содержимое SftpFileStream во временный MemoryStream и используйте его с ExcelReaderFactory.

    using (var memoryStream = new MemoryStream())
    {
        sftpFileStream.CopyTo(memoryStream);
        memoryStream.Position = 0;
        using (var reader = ExcelReaderFactory.CreateOpenXmlReader(memoryStream))
        {
            // ...
        }
    }
    
  2. Или, если вы не хотите тратить память на другую копию файла, вы можете реализовать собственную Stream оболочку вокруг SftpFileStream, которая переводит SeekOrigin.End в SeekOrigin.Begin с правильным offset .


Обратите внимание, что ZipArchive (для внутреннего использования ExcelReaderFactory) использует Stream.Seek с SeekOrigin.End, поскольку центральный каталог ZIP находится в конце файла ZIP. - XLSX-файл в основном представляет собой ZIP-файл с определенной структурой.

...