Ошибка неправильного состояния Dotnetzip при извлечении текстового/XML-файла

Я пытаюсь сохранить файл XML в zip, используя dotnetzip, используя следующий метод:

    private void writeHosts()
    {
        XmlRootAttribute root = new XmlRootAttribute(ROOTNAME_HOST);
        XmlSerializer ser = new XmlSerializer(typeof(Host[]), root);
        MemoryStream ms = new MemoryStream();
        StreamWriter swriter = new StreamWriter(ms);

        //write xml to memory stream
        ser.Serialize(swriter, m_hostList.ToArray());
        swriter.Flush();

        //be kind, rewind (the stream)
        ms.Seek(0, SeekOrigin.Begin);

        //copy memory stream to zip as a file.
        using (m_repo)
        {
            ZipEntry e = m_repo.AddEntry(FILENAME_HOST, ms);
            e.IsText = true;
            m_repo.Save();
        }

        swriter.Close();
    }

Затем я снова прочитал файл XML, используя этот метод:

private List<Host> readHosts()
    {
        XmlRootAttribute root = new XmlRootAttribute(ROOTNAME_HOST);
        XmlSerializer ser = new XmlSerializer(typeof(Host[]), root);
        MemoryStream ms = new MemoryStream();
        StreamReader reader = new StreamReader(ms);
        List<Host> retlist = new List<Host>();

        //get the vuln list from the zip and read into memory
        using (m_repo)
        {
            ZipEntry e = m_repo[FILENAME_HOST];
            e.Extract(ms);
        }

        //rewind to the start of the stream
        ms.Flush();
        ms.Seek(0, SeekOrigin.Begin);

        //Pull the host list from XML
        Host[] ret = (Host[])ser.Deserialize(reader);
        retlist.AddRange(ret);

        ms.Close();

        return retlist;
    }

Однако этот метод создает исключение ZlibException -- Bad state (недопустимая длина сохраненных блоков) -- при вызове e.Extract(ms). Я прочитал достаточно документации и примеров, чтобы быть уверенным, что это должно работать, но я также впервые работаю с dotnetzip, так что... есть мысли о том, как решить эту проблему?


person mcscrilla    schedule 24.05.2011    source источник


Ответы (1)


Я действительно не понимаю, что вы делаете, я не вижу, как создается m_repo на этапе создания zip. Похоже, это слишком сложно. Также то же самое в части извлечения почтового индекса. Возможно, вы создали zip странным образом, что приводит к ошибке декомпрессии. Я не могу сказать, потому что код не весь.

Я думаю, если вы упростите, вы, вероятно, избежите этих проблем.

Предположим, что класс объекта передачи данных выглядит следующим образом:

public class Scrilla
{
    // the parts that get serialized:
    [XmlElement]
    public String Name { get;set; }
    [XmlElement]
    public DateTime FirstReport { get;set; }
    [XmlElement]
    public String MoreInfo { get;set; }
}

Этот код создаст zip-файл (сохраненный в потоке) с XML-представлением этой вещи, хранящейся в zip-файле в виде записи:

    var FILENAME_HOST = "self.xml";
    XmlRootAttribute root = new XmlRootAttribute("root");
    XmlSerializer ser = new XmlSerializer(typeof(Scrilla), root);
    MemoryStream zipStream = new MemoryStream();
    var scrilla = new Scrilla
    {
        Name = "Foop",
        FirstReport = DateTime.Now,
        MoreInfo = "see http://example.org"
    };

    // zip up:
    using (var zip1 = new ZipFile())
    {
        zip1.AddEntry(FILENAME_HOST,(entryName,stream) => {
                using (var swriter = new StreamWriter(stream))
                {
                    ser.Serialize(swriter, scrilla);
                }});
        zip1.Save(zipStream);
    }

    // the content (an XML file) is now held in the MemoryStream
    zipStream.Seek(0, SeekOrigin.Begin);

Если вы затем хотите распаковать из того же потока памяти, вы можете сделать это:

    Scrilla unpacked;
    // unzip:
    using (var zip2 = ZipFile.Read(zipStream))
    {
        Stream s = zip2[FILENAME_HOST].OpenReader();
        unpacked = (Scrilla) ser.Deserialize(new StreamReader(s));
    }

А затем, чтобы доказать, что это сработало:

    // prove that it worked - print out to Console
    var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
    using ( var w2 = System.Xml.XmlWriter.Create(Console.Out, xmlws))
    {
        ser.Serialize(w2, unpacked);
    }

При создании приведенный выше код использует перегрузку ZipFile.AddEntry. который принимает WriteDelegate. WriteDelegate — это функция, которая вызывается ZipFile.Save() с именем записи и потоком, в который вы должны записать содержимое для этой записи. Подробности смотрите в документации DotNetZip. Как вы можете видеть, этот WriteDelegate просто XML-сериализует объект в генератор потоков, обернутый вокруг этого потока.

Распаковка также проходит по упрощенной схеме — она просто читает из читаемого потока.

В каждом случае вам не нужно создавать и искать дополнительный поток памяти.

Этот код работал для меня.

Если это не поможет вам, возможно, вы могли бы предоставить более подробную информацию.

person Cheeso    schedule 24.05.2011
comment
Спасибо за предложения. Я дам им шанс и посмотрим, поможет ли это. Для справки, вот как я создаю zip... При создании нового экземпляра: m_repo = new ZipFile(filename); При чтении в существующем zip: m_repo = ZipFile.Read(filename); - person mcscrilla; 25.05.2011