Haskell zip 包:如何将 mimetype 文件添加为存档的第一个文件
Posted
技术标签:
【中文标题】Haskell zip 包:如何将 mimetype 文件添加为存档的第一个文件【英文标题】:Haskell zip package: How to add mimetype file as first file of the archive 【发布时间】:2021-12-12 01:29:57 【问题描述】:我已经开始使用这个包来创建一个.epub
文件,我必须说它比我之前尝试过的javascript库(epub-zipper)要流畅得多
但是,有一个小细节我无法解决:EPUB 3.2 规范states 那
OCF ZIP 容器中的第一个文件必须是 mimetype 文件
而且它不能被压缩。我已经达到了“未压缩”的条件,但我不知道如何满足“zip 存档中的第一个文件”的条件。这是我的代码:
main :: IO ()
main = do
mimetype <- mkEntrySelector "mimetype"
createArchive "conmocion.epub" $ do
packDirRecur Deflate (\s -> mkEntrySelector $ "META-INF/" ++ s) "./ePub/META-INF"
packDirRecur Deflate (\s -> mkEntrySelector $ "es/" ++ s) "./ePub/es"
loadEntry Store mimetype "./ePub/mimetype"
我在epub online validator 中收到以下错误
Mimetype file entry is missing or is not the first file in the archive.
知道如何将 mimetype 文件作为存档中的第一个文件吗?
编辑
代码现在是:
-# LANGUAGE OverloadedStrings #-
module Main where
import Codec.Archive.Zip
import qualified Data.Map as M
main :: IO ()
main = do
mimetype <- mkEntrySelector "000mimetype"
createArchive "conmocion.epub" $ contents mimetype
createArchive "conmocion.zip" $ contents mimetype
where
contents x = do
loadEntry Store x "./ePub/mimetype"
packDirRecur Deflate (mkEntrySelector . ("META-INF/" ++)) "./ePub/META-INF"
packDirRecur Deflate (mkEntrySelector . ("es/" ++) ) "./ePub/es"
packDirRecur Deflate (mkEntrySelector . ("assets/" ++) ) "./ePub/assets"
test :: IO ()
test = do
entries <- withArchive "conmocion.epub" (M.keys <$> getEntries)
mapM_ print entries
当我调用test
函数时,它会打印以下内容:
ghci> test
"000mimetype"
"assets\\all.css"
"es\\chapters\\c1.xhtml"
"es\\chapters\\c2.xhtml"
"es\\chapters\\c3.xhtml"
"es\\chapters\\c4.xhtml"
"es\\chapters\\c5.xhtml"
"es\\chapters\\c6.xhtml"
"es\\chapters\\c7.xhtml"
"es\\chapters\\c8.xhtml"
"es\\chapters\\c9.xhtml"
"es\\docs\\colophon.xhtml"
"es\\docs\\coverback.xhtml"
"es\\docs\\coverfront.xhtml"
"es\\docs\\epigraph.xhtml"
"es\\docs\\legal.xhtml"
"es\\docs\\nav.xhtml"
"es\\docs\\notice.xhtml"
"es\\docs\\thanks.xhtml"
"es\\es.opf"
"META-INF\\container.xml"
当我提取 zip 文件时,可以在里面找到 000mimetype
文件,其中只有 application/epub+zip
行
编辑 2
引用EPUB Open Container Format (OCF) 3.2
4.3 OCF ZIP Container Media Type Identification
The first file in the OCF ZIP Container MUST be the mimetype file, which meets the following requirements:
The contents of the mimetype file MUST be the MIME media type [RFC2046] string application/epub+zip encoded in US-ASCII [US-ASCII].
The mimetype file MUST NOT contain any leading or trailing padding or white space.
The mimetype file MUST NOT begin with the Unicode byte order mark U+FEFF.
The mimetype file MUST NOT be compressed or encrypted, and there MUST NOT be an extra field in its ZIP header.
【问题讨论】:
将loadEntry
放在第一个packDirRecur
之前会发生什么?
epub 验证器返回相同的错误
当您将文件解压缩到一个单独的位置时,mimetype 文件的内容是您所期望的吗?列出edoc文件的内容时,mimetype文件是不是第一个?
mimetype 文件里面只有一行,application/epub+zip
,当我使用 Haskell 包中的 withArchive
函数列出 epub 文件的内容时,它总是按字母顺序打印文件,无论我是在 do 块的开头还是结尾调用 loadEntry
在这一点上,我怀疑软件包本身在添加文件时正在重新排序文件,尽管粗略查看源代码似乎不太可能。您将不得不想出一个解决方法或使用不同的库。
【参考方案1】:
好的,通过使用包本身的commit
函数找到了解决方案。但是,由于 mimetype 文件中有一个长度为 20 的额外字段,我现在遇到了另一个错误。郁闷。
main :: IO ()
main = do
mimetype <- mkEntrySelector "mimetype"
createArchive "conmocion.epub" $ do
addEntry Store "application/epub+zip" mimetype
commit
packDirRecur Deflate (mkEntrySelector . ("META-INF/" ++)) "./ePub/META-INF"
packDirRecur Deflate (mkEntrySelector . ("es/" ++) ) "./ePub/es"
packDirRecur Deflate (mkEntrySelector . ("assets/" ++) ) "./ePub/assets"
【讨论】:
以上是关于Haskell zip 包:如何将 mimetype 文件添加为存档的第一个文件的主要内容,如果未能解决你的问题,请参考以下文章
如何将我的夜间 Haskell 包放入 Stackage LTS?
使用 Haskell 的 zip-conduit 从 zip 存档中的文件中读取行