如何解压具有指定文件/目录名称字符编码的 ZIP 文件?

如何解压具有指定文件/目录名称字符编码的 ZIP 文件?

我得到了 ZIP 文件,其中包含一些文件,这些文件的文件名采用某种编码。假设我知道这些文件名的编码,但我仍然不知道如何正确解压它们。

以下是示例文件,其中包含一个文件“【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12.ass”

我知道使用的编码是 GB18030 (中文)

问题是 - 如何使用 unzip 或其他 CLI 实用程序在 FreeBSD 中解压该文件以获取正确的编码文件名?我尝试了所有我能尝试的方法,但结果总是不好。请帮忙。

我在 OSX 上尝试过:

MBP1:test 2ge$ bsdtar xf gb18030.zip
MBP1:test 2ge$ ls
%A1%BESSK%D7%D6Ļ%D7顿The Vampire Diaries %CE%FCѪ%B9%ED%C8ռ%C7S06E12/      gb18030.zip
MBP1:test 2ge$ cd %A1%BESSK%D7%D6Ļ%D7顿The\ Vampire\ Diaries\ %CE%FCѪ%B9%ED%C8ռ%C7S06E12/
MBP1:%A1%BESSK%D7%D6Ļ%D7顿The Vampire Diaries %CE%FCѪ%B9%ED%C8ռ%C7S06E12 2ge$ ls
%A1%BESSK%D7%D6Ļ%D7顿The Vampire Diaries %CE%FCѪ%B9%ED%C8ռ%C7S06E12.ass*
MBP1:%A1%BESSK%D7%D6Ļ%D7顿The Vampire Diaries %CE%FCѪ%B9%ED%C8ռ%C7S06E12 2ge$ find . | iconv -f gb18030 -t utf-8
.
./%A1%BESSK%D7%D6L抬%D7椤縏he Vampire Diaries %CE%FC血%B9%ED%C8占%C7S06E12.ass 
MBP1:%A1%BESSK%D7%D6Ļ%D7顿The Vampire Diaries %CE%FCѪ%B9%ED%C8ռ%C7S06E12 2ge$ convmv -r -f gb18030 -t utf-8 --notest .
Skipping, already UTF-8: ./%A1%BESSK%D7%D6Ļ%D7顿The Vampire Diaries %CE%FCѪ%B9%ED%C8ռ%C7S06E12.ass
Ready!

我尝试了类似的解压缩方法,但遇到了类似的问题。

谢谢,现在尝试在 FREE BSD 上,我使用 OSX(终端)的 SSH 进行连接:

# locale
LANG=
LC_CTYPE="C"
LC_COLLATE="C"
LC_TIME="C"
LC_NUMERIC="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_ALL=C

首先,我想正确地显示中文名字。我改变了

setenv LC_ALL zh_CN.GB18030
setenv LANG zh_CN.GB18030

然后我下载了文件并尝试“ls”查看正确的字符,但没有成功。所以我想我必须先解决中文语言环境以验证我何时得到正确的结果,实际上我可以比较它。你能帮我解决这个问题吗?

答案1

这是我在 Ubuntu 16.04 上解压任何编码的 zip 文件的方法,只要我知道该编码是什么。同样的方法应该适用于 FreeBSD,因为它只依赖于广泛可用的unzip工具。

  1. 我仔细检查了编码的确切名称,以免拼写错误:https://www.iana.org/assignments/character-sets/character-sets.xhtml

  2. 我只是跑

    $ unzip -O <encoding> <filename> -d <target_dir>
    

    或者

    $ unzip -I <encoding> <filename> -d <target_dir>
    

    选择-O-I按照此处的说明进行操作:

    $ unzip -h
    UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.
      ...
      -O CHARSET  specify a character encoding for DOS, Windows and OS/2 archives
      -I CHARSET  specify a character encoding for UNIX and other archives
      ...
    

    这意味着我只需尝试-O,它就应该可以工作,因为没有多少人会.zip在 Unix 中创建文件……


因此,对于您的具体示例:

  1. 确切的编码名称是GB18030

  2. 我使用-O标志并且:

    $ unzip -O GB18030 gb18030.zip -d target_dir
    Archive:  gb18030.zip
       creating: target_dir/【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12/
      inflating: target_dir/【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12/【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12.ass
    

    ... 有用。

答案2

方法 1:使用 unar 实用程序

sudo apt-get install unar

unar -e gb18030 gb18030.zip

方法 2:使用python脚本解压文件(参考https://gist.github.com/usunyu/dfc6e56af6e6caab8018bef4c3f3d452#file-gbk-unzip-py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# unzip-gbk.py

import os
import sys
import zipfile
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--encoding", help="encoding for filename, default gbk")
parser.add_argument("-l", help="list filenames in zipfile, do not unzip", action="store_true")
parser.add_argument("file", help="process file.zip")
args = parser.parse_args()
print "Processing File " + args.file

file=zipfile.ZipFile(args.file,"r");
if args.encoding:
    print "Encoding " + args.encoding
for name in file.namelist():
    if args.encoding:
        utf8name=name.decode(args.encoding)
    else:
        utf8name=name.decode('gbk')
    pathname = os.path.dirname(utf8name)
    if args.l:
        print "Filename " + utf8name
    else:
        print "Extracting " + utf8name
        if not os.path.exists(pathname) and pathname!= "":
            os.makedirs(pathname)
        data = file.read(name)
        if not os.path.exists(utf8name):
            fo = open(utf8name, "w")
            fo.write(data)
            fo.close
file.close()

示例 gb18030.zip 将提取以下文件

【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12
【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12/【SSK字幕组】The Vampire Diaries 吸血鬼日记S06E12.ass

答案3

在大多数 POSIX 文件系统中,文件名只是一系列字节,由用户空间来理解它。您可以利用这一点。

  1. 首先,使用 提取档案bsdtar,因为该unzip工具似乎会破坏文件名,而 bsdtar 会直接提取文件名。(我在 Linux 上测试了这一点。我猜 FreeBSD 只是将其称为tar。)

    $ bsdtar xf gb18030.zip
    
  2. 验证以下工具是否iconv可以成功解码名称:

    $ find . | iconv -f gb18030 -t utf-8
    

    (请注意,这只会影响find输出,而不会影响文件本身。)

  3. 最后使用convmv将文件名转换为UTF-8:

    $ convmv -r -f gb18030 -t utf-8 --notest .
    

    (注:我必须从 CPAN 安装 Encode::HanExtra 才能获得 GB18030 支持,手动添加use Encode::HanExtra;到 /usr/bin/convmv 即使它应该

  4. 如果convmv不可用,请编写脚本:

    $ find . -depth | while read -r old; do
        old=./$old;
        head=${old%/*};
        tail=${old##*/};
        new=$head/$(echo "$tail" | iconv -f gb18030 -t utf-8);
        [ "$old" = "$new" ] || mv "$old" "$new";
    done
    

    (至少在 Linux 上,这有一个优点,因为它iconv几乎总是可用的,而且它总是支持gb18030。

答案4

7z 通过开关支持字符集 ID -scs,例如:

7z x -scs903 some.zip

其中 903 是中文简体字符集。可以找到更长的字符集 ID 列表这里

相关内容