使用Zip库创建Epub文件

10

大家好,

我正在尝试使用C#压缩一个EPUB文件。

我已经尝试过以下方法:

  • Dot Net Zip http://dotnetzip.codeplex.com/
  • - DotNetZip可以实现压缩,但epubcheck检测结果失败(**参见下面的编辑部分)
  • ZipStorer zipstorer.codeplex.com
  • - 创建了一个通过验证的EPUB文件,但是该文件无法在Adobe Digital Editions中打开。
  • 7 zip
  • - 我没有尝试使用C#,但当我使用其界面压缩文件时,它告诉我mimetype文件名长度为9,应为8。

在所有情况下,mimetype文件都是第一个添加到归档文件中且未经过压缩处理。

我所使用的EPUB验证器是epubcheck http://code.google.com/p/epubcheck/

如果有人成功地使用这些库之一压缩了EPUB文件,请告诉我如何操作。或者,如果有人成功地使用其他开源压缩API压缩了EPUB文件,那也可以。


编辑

DotNetZip可以实现压缩,详见下面接受的答案。


你是说那些工具不能将你的文件压缩成zip格式,还是在使用gzip(或其他函数)时C#会返回错误信息,或者是你的epub文件存在问题? - soandos
epub文件制作没有错误,但是当我对其运行验证器时,会出现关于mimetype文件的错误。 - claybo.the.invincible
如果您编写了文件并使用WinZip呢?它是否经过验证? - H H
3个回答

14
如果您需要控制ZIP文件中条目的顺序,可以使用DotNetZip和ZipOutputStream。您说您尝试过DotNetZip,但它(epub验证器)报告了一个关于mime类型的错误。这可能是因为您在DotNetZip中使用了ZipFile类型。如果您使用ZipOutputStream,则可以控制zip条目的顺序,这对于epub显然很重要(我不知道格式,只是猜测)。

编辑

我刚刚查看了维基百科上的epub页面,它描述了您需要如何格式化.epub文件。它说mimetype文件必须包含特定的文本,必须未压缩和未加密,并且必须作为ZIP存档中的第一个文件出现。

使用ZipOutputStream,您可以通过在该特定ZipEntry上设置CompressionLevel = None来完成此操作-该值不是默认值。

这是一些示例代码:

private void Zipup()
{
    string _outputFileName = "Fargle.epub";
    using (FileStream fs = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
    {
        using (var output= new ZipOutputStream(fs))
        {
            var e = output.PutNextEntry("mimetype");
            e.CompressionLevel = CompressionLevel.None;

            byte[] buffer= System.Text.Encoding.ASCII.GetBytes("application/epub+zip");
            output.Write(buffer,0,buffer.Length);

            output.PutNextEntry("META-INF/container.xml");
            WriteExistingFile(output, "META-INF/container.xml");
            output.PutNextEntry("OPS/");  // another directory
            output.PutNextEntry("OPS/whatever.xhtml");
            WriteExistingFile(output, "OPS/whatever.xhtml");
            // ...
        }
    }
}

private void WriteExistingFile(Stream output, string filename)
{
    using (FileStream fs = File.Open(fileName, FileMode.Read))
    {
        int n = -1;
        byte[] buffer = new byte[2048];
        while ((n = fs.Read(buffer,0,buffer.Length)) > 0)
        {
            output.Write(buffer,0,n);
        }
    }
}

请查看ZipOutputStream的此处文档。


非常感谢您快速并详细的回复。我只需要做两个小改动:output.PutNextEntry("META-INF/")是不必要的,它只会在zip文件夹中创建一个空的META-INF文件夹;在WriteExistingFile中,我将_outputFileName更改为filename,这样其他人查看您的答案时可能会更容易理解。再次感谢! - claybo.the.invincible
嘿,Claybo,谢谢。我修改了示例代码来解决那两个问题。我不确定epub文件中是否需要OPS/(内容目录)和META-INF/(元内容目录)。 - Cheeso

7

为什么不让生活更轻松一些呢?

private void IonicZip()
{
    string sourcePath = "C:\\pulications\\";
    string fileName = "filename.epub";

    // Creating ZIP file and writing mimetype
    using (ZipOutputStream zs = new ZipOutputStream(sourcePath + fileName))
    {
        var o = zs.PutNextEntry("mimetype");
        o.CompressionLevel = CompressionLevel.None;

        byte[] mimetype = System.Text.Encoding.ASCII.GetBytes("application/epub+zip");
        zs.Write(mimetype, 0, mimetype.Length);
    }

    // Adding META-INF and OEPBS folders including files     
    using (ZipFile zip = new ZipFile(sourcePath + fileName))
    {
        zip.AddDirectory(sourcePath  + "META-INF", "META-INF");
        zip.AddDirectory(sourcePath  + "OEBPS", "OEBPS");
        zip.Save();
    }
}

谢谢。这帮助我编写了一个ePub构建器,因为7zip无法胜任。7zip似乎无法正确处理mimetype。我还让它通过传入每种电子书类型要压缩的文件列表来进行多次构建(B&N,Kindle,iBooks,Short Sample)。 - Rhyous

1

对于像我这样正在寻找其他方法的人,我想补充一下,来自Jaime Olivares的ZipStorer类是一个很好的选择。您可以将代码直接复制到您的项目中,并且很容易在“deflate”和“store”之间进行选择。

https://github.com/jaime-olivares/zipstorer

这是我创建EPUB的代码:
Dictionary<string, string> FilesToZip = new Dictionary<string, string>()
{
    { ConfigPath + @"mimetype",                 @"mimetype"},
    { ConfigPath + @"container.xml",            @"META-INF/container.xml" },
    { OutputFolder + Name.Output_OPF_Name,      @"OEBPS/" + Name.Output_OPF_Name},
    { OutputFolder + Name.Output_XHTML_Name,    @"OEBPS/" + Name.Output_XHTML_Name},
    { ConfigPath + @"style.css",                @"OEBPS/style.css"},
    { OutputFolder + Name.Output_NCX_Name,      @"OEBPS/" + Name.Output_NCX_Name}
};

using (ZipStorer EPUB = ZipStorer.Create(OutputFolder + "book.epub", ""))
{
    bool First = true;
    foreach (KeyValuePair<string, string> File in FilesToZip)
    {
        if (First) { EPUB.AddFile(ZipStorer.Compression.Store, File.Key, File.Value, ""); First = false; }
        else EPUB.AddFile(ZipStorer.Compression.Deflate, File.Key, File.Value, "");
    }
}

这段代码创建了一个完全有效的EPUB文件。但是,如果您不需要担心验证,似乎大多数电子阅读器都会接受带有“deflate” mimetype的EPUB。因此,我之前使用.NET的ZipArchive生成的EPUB可以在Adobe Digital Editions和PocketBook上运行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接