Необработанный поток содержит данные, Deflate возвращает ноль байтов - PullRequest
4 голосов
/ 19 февраля 2011

Я читаю данные (в отчете adCenter, как это бывает), которые должны быть заархивированы.Читая содержимое обычным потоком, я получаю пару тысяч байт, поэтому это кажется разумным.Поэтому я передаю поток в DeflateStream.

Сначала он сообщает: «Длина блока не соответствует его дополнению».Краткий поиск показывает, что существует двухбайтовый префикс, и действительно, если я дважды вызываю ReadByte () перед открытием DeflateStream, исключение исчезает.

Однако DeflateStream теперь вообще ничего не возвращает.Я провел большую часть дня в погоне за лидами, но без удачи.Помоги мне, StackOverflow, ты моя единственная надежда!Может кто-нибудь сказать мне, что мне не хватает?

Вот код.Естественно, я включил только один из двух закомментированных блоков одновременно при тестировании.

_results = new List<string[]>();
using (Stream compressed = response.GetResponseStream())
  {
  // Skip the zlib prefix, which conflicts with the deflate specification
  compressed.ReadByte();  compressed.ReadByte();

  // Reports reading 3,000-odd bytes, followed by random characters
  /*byte[]  buffer    = new byte[4096];
  int     bytesRead = compressed.Read(buffer, 0, 4096);
  Console.WriteLine("Read {0} bytes.", bytesRead.ToString("#,##0"));
  string  content   = Encoding.ASCII.GetString(buffer, 0, bytesRead);
  Console.WriteLine(content);*/

  using (DeflateStream decompressed = new DeflateStream(compressed, CompressionMode.Decompress))
    {
    // Reports reading 0 bytes, and no output
    /*byte[]  buffer    = new byte[4096];
    int     bytesRead = decompressed.Read(buffer, 0, 4096);
    Console.WriteLine("Read {0} bytes.", bytesRead.ToString("#,##0"));
    string  content   = Encoding.ASCII.GetString(buffer, 0, bytesRead);
    Console.WriteLine(content);*/

    using (StreamReader reader = new StreamReader(decompressed))
      while (reader.EndOfStream == false)
        _results.Add(reader.ReadLine().Split('\t'));
    }
  }

Как вы, вероятно, можете догадаться из последней строки, распакованный контент должен быть TDT.

Только длязабавно, я пытался распаковать с помощью GZipStream, но он сообщает, что магическое число неверно.Документы MS просто говорят: «Загруженный отчет сжимается с помощью сжатия zip. Вы должны разархивировать отчет, прежде чем сможете использовать его содержимое».


Вот код, который наконец заработал.Мне пришлось сохранить содержимое в файл и прочитать его обратно. Это не представляется разумным, но для небольших объемов данных, с которыми я работаю, это приемлемо, я возьму это!

WebRequest   request  = HttpWebRequest.Create(reportURL);
WebResponse  response = request.GetResponse();

_results = new List<string[]>();
using (Stream compressed = response.GetResponseStream())
  {
  // Save the content to a temporary location
  string  zipFilePath = @"\\Server\Folder\adCenter\Temp.zip";
  using (StreamWriter file = new StreamWriter(zipFilePath))
    {
    compressed.CopyTo(file.BaseStream);
    file.Flush();
    }

  // Get the first file from the temporary zip
  ZipFile  zipFile = ZipFile.Read(zipFilePath);
  if (zipFile.Entries.Count > 1)  throw new ApplicationException("Found " + zipFile.Entries.Count.ToString("#,##0") + " entries in the report; expected 1.");
  ZipEntry  report = zipFile[0];

  // Extract the data
  using (MemoryStream decompressed = new MemoryStream())
    {
    report.Extract(decompressed);
    decompressed.Position = 0;  // Note that the stream does NOT start at the beginning
    using (StreamReader reader = new StreamReader(decompressed))
      while (reader.EndOfStream == false)
        _results.Add(reader.ReadLine().Split('\t'));
    }
  }

Ответы [ 2 ]

1 голос
/ 19 февраля 2011

Вы обнаружите, что DeflateStream чрезвычайно ограничен в том, какие данные он будет распаковывать.Фактически, если вы ожидаете целых файлов, это будет бесполезно.Существует множество (в основном небольших) вариаций ZIP-файлов, и DeflateStream будет ладить только с двумя или тремя из них.

Лучшим способом является использование специальной библиотеки для чтения Zip-файлов / потоков, таких как DotNetZip или SharpZipLib (несколько не поддерживается).

0 голосов
/ 19 февраля 2011

Вы можете записать поток в файл и попробовать мой инструмент Precomp на нем.Если вы используете его следующим образом:

precomp -c- -v [name of input file]

любой поток (ы) ZIP / gZip внутри файла будет обнаружен, и будет сообщена некоторая подробная информация (позиция и длина потока).Кроме того, если они могут быть распакованы и перекомпрессированы по битам одинаково, выходной файл будет содержать распакованные потоки.

Precomp обнаруживает потоки ZIP / gZip (и некоторые другие) в любом месте файла,так что вам не придется беспокоиться о байтах заголовков или мусоре в начале файла.

Если он не обнаруживает такой поток, попробуйте добавить -slow, который обнаруживает потоки с дефляцией, даже еслиу них нет заголовка ZIP / gZip.Если это не удается, вы можете попробовать -brute, который даже обнаруживает дефлированные потоки, в которых отсутствует двухбайтовый заголовок, но это будет очень медленно и может привести к ложным срабатываниям.

После этого вы узнаете, есть ли(действительный) поток дефляции в файле и, если да, дополнительная информация должна помочь вам правильно распаковать другие отчеты, используя процедуры распаковки zLib или аналогичные.

...