Calibre 转换 TXT 文件出现 Errno 21 错误的解决方法

昨天有一个叫 sumina 的小伙伴留言反馈奇怪的问题,他在用 Calibre 将某个 TXT 文件转换成 MOBI 格式错误,其他 TXT 文件可以正常转换,出错 TXT 似乎没有问题。

取得小伙伴提供的样本 TXT 文件发布后,我先用 Calibre 经过测试,出现了以下错误:

# 省略了无关内容……

Python function terminated unexpectedly: [Errno 21] Is a directory: u'/var/folders/1r/1qwpq6f56hz4xp0gwv7br_kr0000gn/C/calibre_3.40.1_tmp_BSEcvF/'
InputFormatPlugin: TXT Input running
on /var/folders/1r/1qwpq6f56hz4xp0gwv7br_kr0000gn/C/calibre_3.40.1_tmp_BSEcvF/JAVXx3.txt
Reading text from file...
Detected input encoding as gbk with a confidence of 99.0%
Auto detected paragraph type as unformatted
Auto detected formatting as textile
Running text through textile conversion...
Traceback (most recent call last):
  File "/Applications/calibre.app/Contents/Resources/Python/lib/python2.7/site.py",line 154,in main
    return run_entry_point()
  File "/Applications/calibre.app/Contents/Resources/Python/lib/python2.7/site.py",line 114,in run_entry_point
    return getattr(pmod,func)()
  File "site-packages/calibre/utils/ipc/worker.py",line 199,in main
  File "site-packages/calibre/gui2/convert/gui_conversion.py",line 42,in gui_convert_override
  File "site-packages/calibre/gui2/convert/gui_conversion.py",line 27,in gui_convert
  File "site-packages/calibre/ebooks/conversion/plumber.py",line 1106,in run
  File "site-packages/calibre/customize/conversion.py",line 244,in __call__
  File "site-packages/calibre/ebooks/conversion/plugins/txt_input.py",line 268,in convert
  File "site-packages/calibre/ebooks/conversion/plugins/txt_input.py",line 117,in fix_resources
IOError: [Errno 21] Is a directory: u'/var/folders/1r/1qwpq6f56hz4xp0gwv7br_kr0000gn/C/calibre_3.40.1_tmp_BSEcvF/'

不幸的是,错误的信息除了提示一条路径是文件夹之外([Errno 21] Is a directory    ),没有给出更有价值的信息。根据以往的使用经验,转换 TXT 不应该与任何目录有任何联系。

由于其它 TXT 文件转换正常,可以确定 Calibre 的转换功能应该没问题。问题应该是 TXT 以上内容。但打开 TXT 文件,里面的内容除了使用了英文标点符号,并没有什么异样,没有什么特殊字符,也没有什么乱码。看来是时候祭出解决这类“灵异”问题的终极武器——排除大法。

在保持转换问题再现的前提下,我用人肉二分法提取 TXT 文档中的内容逐一测试,以将问题缩小到某个段落。将范围缩小到 20 段后,出现了有趣的现象。当维护 20 段时,可以重现转换问题,但无论删除前几行、后几行还是中间段,问题都不会重现,就好像问题不是在某个字符或段落上,而是在分布式上。虽然它离问题的根源很近,但并不明显。

于是我继续缩小范围,直至在保持转换问题重现的状态下,将内容缩减到如下所示:

!"!!!!!!!!!!!!!!我!说!!!说!!!说!!说!说!!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!说!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

在这种情况下,删除任何字符,转换问题都会消失。另一个有趣的现象是,当删除引号并重新转换时,输出信息出现以下转换 TXT 纯文本文档的内容相当奇怪:

# 省略了无关内容……

Converting XHTML to Mobipocket markup...
Failed to find image: 逢
Failed to find image: 他
Failed to find image: 啊
Failed to find image: 可
Failed to find image: 我
Failed to find image: 说
Serializing markup content...

# 省略了无关内容……


与图片相关的信息如何出现在纯文本文档中?回顾最小化后的内容,我发现惊叹号成对重复,中间有一个字符,非常像一种标记语法。直到现在我才明白发生了什么。

▲ Calibre 默认会自动检测 TXT 文档结构

Calibre 在将 TXT 文件转换成 MOBI 在格式电子书之前,将其转换为 HTML。 在这个过程中Calibre 默认会自动检测 TXT 文档结构(如上图所示,可见【TXT 输入】设置项中的【格式化样式】默认值是【auto】),这意味着 Calibre 会“自动决定使用哪种格式化处理器当它发现某种标记语法(如 Markdown)重复出现了几次,就会认为文档结构使用了该标记语言并试图将其转换成 HTML。

在转换问题的样本中,由于原文档输入不规范,英文标点应在本应使用中文标点符号的地方使用,过多使用的英文感叹号!文档结构,让 Calibre 误以为用了 Textile    在语言中标记插入图片的语法(即 !/carver.png!,从测试的角度来看,出现至少六次会被 Calibre 认为是 Textile 语法)。

如果只有这个问题,只会导致文档缺失,不会导致转换失败。转换失败的根源是 Calibre 认为文档使用 Textile 在标记语言的同时,也遇到了错误的标记,即叹号后面的引号(如 !"内容!),这就导致 Calibre 在错误认为是图片的基础上,尝试在错误的位置引用根本不存在的图片,这就是为什么提示某个路径是文件夹的原因。最后,当错误添加错误时,转换被中断。

知道问题所在,解决方案自然会出现:要么提前把原 TXT 文档中的英文标点符号(至少英文叹号)全部替换为中文标点符号;或者在转换过程中【格式化样式】的值改为【Markdown】或【plain】,以禁止 Calibre 分析可能出现问题的标记语言(建议同时使用搜索

阅读剩余
THE END