Làm cách nào tôi có thể tạo một zip / tgz trong Linux để Windows có tên tệp phù hợp?


26

Hiện tại, tar -zcf arch.tgz files/*mã hóa tên tệp trong UTF, vì vậy người dùng Windows thấy tất cả các ký tự bị hỏng trong tên tệp không phải là tiếng Anh và không thể làm gì với nó.

zip -qq -r arch.zip files/* có hành vi tương tự.

Làm cách nào tôi có thể tạo một kho lưu trữ zip / tgz để khi người dùng Windows giải nén nó sẽ có tất cả tên tệp được mã hóa đúng cách?

Câu trả lời:


24

Hiện tại, tar mã hóa tên tệp trong UTF

Trên thực tế tar không mã hóa / giải mã tên tập tin, Nó chỉ đơn giản là sao chép chúng ra khỏi hệ thống tập tin như hiện tại. Nếu ngôn ngữ của bạn dựa trên UTF-8 (như trong nhiều bản phân phối Linux hiện đại), đó sẽ là UTF-8. Thật không may, bảng mã hệ thống của một hộp Windows không bao giờ là UTF-8, vì vậy các tên sẽ luôn được đọc sai trừ các công cụ như WinRAR cho phép thay đổi bộ ký tự được sử dụng.

Vì vậy, không thể tạo tệp ZIP với tên tệp không phải ASCII hoạt động trên các bản phát hành Windows của các quốc gia khác nhau và hỗ trợ thư mục nén tích hợp của chúng.

Một thiếu sót của các định dạng tar và zip là không có thông tin mã hóa cố định hoặc được cung cấp, vì vậy các ký tự không phải ASCII sẽ luôn không thể mang theo được. Nếu bạn cần một định dạng lưu trữ không phải ASCII, bạn sẽ phải sử dụng một trong các định dạng mới hơn, chẳng hạn như 7z hoặc rar gần đây. Thật không may, những điều này vẫn còn rất khó khăn; trong 7zip bạn cần -mcuchuyển đổi, và rar vẫn không sử dụng UTF-8 trừ khi nó phát hiện các ký tự không có trong bảng mã.

Về cơ bản, đó là một mớ hỗn độn khủng khiếp và nếu bạn có thể tránh phân phối tài liệu lưu trữ có chứa tên tệp với các ký tự không phải ASCII, bạn sẽ tốt hơn nhiều.


Cảm ơn rất nhiều! Thật không may, hầu hết người dùng không biết gì về 7z và rar là độc quyền :(
kolypto

Vâng, đó là một vấn đề. ZIP là giải pháp hữu dụng nhất cho người dùng, vì tất cả các hệ điều hành hiện đại đều có hỗ trợ UI gốc tốt cho nó. Thật không may, vấn đề bộ ký tự ngày nay không thực sự có thể giải quyết được trong ZIP (và ngay cả trong các định dạng lưu trữ khác, nó vẫn gây rắc rối).
bobince

25

Đây là một tập lệnh Python đơn giản mà tôi đã viết để giải nén các tập tin tar từ UNIX trên Windows:

import tarfile

archive_name = "archive_name.tar"

def recover(name):
    return unicode(name, 'utf-8')

tar = tarfile.open(name=archive_name, mode='r', bufsize=16*1024)
updated = []
for m in tar.getmembers():
    m.name = recover(m.name)
    updated.append(m)

tar.extractall(members=updated)
tar.close()

Tuyệt vời! tập lệnh này đã giúp tôi chuyển đổi tệp tar được mã hóa EUC-JP được tạo trên máy chủ Solaris cũ.
wm_eddie

Thưa bạn, bạn đã cứu cuộc đời tôi. Chúa phù hộ bạn :)
1576772

8

Vấn đề, sử dụng trong Linux mặc định tar(GNU tar), đã được giải quyết ... thêm --format=posixtham số khi tạo tệp.

Ví dụ:
tar --format=posix -cf

Trong Windows, để giải nén các tập tin, tôi sử dụng bsdtar .

Trong https://lists.gnu.org/archive/html/orms-tar/2005-02/msg00018.html nó được viết (từ năm 2005 !!):

> Tôi đã đọc một cái gì đó trong ChangeLog về UTF-8 đang được hỗ trợ. Điều
này có nghĩa là gì?
> Tôi không tìm thấy cách nào để tạo một kho lưu trữ có thể hoán đổi cho nhau
> giữa các địa phương khác nhau.

Khi tạo tài liệu lưu trữ ở định dạng POSIX.1-2001 (tar --format = posix hoặc --format = pax), tar chuyển đổi tên tệp từ các vị trí hiện tại thành UTF-8 và sau đó lưu trữ chúng trong kho lưu trữ. Khi giải nén, thao tác ngược được thực hiện.

PS Thay vì gõ --format=posixbạn có thể gõ -H pax, ngắn hơn.


5

Tôi tin rằng bạn đang gặp vấn đề với chính định dạng của bộ chứa Zip. Tar có thể bị vấn đề tương tự.

Sử dụng các định dạng lưu trữ 7zip ( .7z) hoặc RAR ( .rar) để thay thế. Cả hai đều có sẵn cho Windows và Linux; các p7zipphần mềm xử lý cả hai định dạng.

Tôi chỉ thử nghiệm tạo .7z, .rar, .zip, và .tarcác tập tin trên cả WinXP và Debian 5, và .7z.rarlưu trữ các file / khôi phục tên tập tin một cách chính xác trong khi .zip.tarfile thì không. Không quan trọng hệ thống nào được sử dụng để tạo kho lưu trữ thử nghiệm.


5

Tôi gặp vấn đề với việc giải nén tarzipcác tệp tôi nhận được từ người dùng Windows. Mặc dù tôi không trả lời câu hỏi "làm thế nào để tạo kho lưu trữ sẽ hoạt động", các tập lệnh bên dưới giúp giải nén tarziptập tin chính xác bất kể HĐH gốc.

CẢNH BÁO: người ta phải điều chỉnh mã hóa nguồn theo cách thủ công ( cp1251, cp866trong các ví dụ bên dưới). Tùy chọn dòng lệnh có thể là một giải pháp tốt trong tương lai.

Tar:

#!/usr/bin/env python

import tarfile
import codecs
import sys

def recover(name):
    return codecs.decode(name, 'cp1251')

for tar_filename in sys.argv[1:]:
    tar = tarfile.open(name=tar_filename, mode='r', bufsize=16*1024)
    updated = []
    for m in tar.getmembers():
        m.name = recover(m.name)
        updated.append(m)
    tar.extractall(members=updated)
    tar.close()

Zip:

#!/usr/bin/env python

import zipfile
import os
import codecs
import sys

def recover(name):
    return codecs.decode(name, 'cp866')

for filename in sys.argv[1:]:
    archive = zipfile.ZipFile(filename, 'r')
    infolist = archive.infolist()
    for i in infolist:
        f = recover(i.filename)
        print f
        if f.endswith("/"):
            os.makedirs(os.path.dirname(f))
        else:
            open(f, 'w').write(archive.read(i))
    archive.close()

CẬP NHẬT 2018-01 / 02 : Tôi sử dụng chardetgói để đoán mã hóa chính xác của khối dữ liệu thô. Bây giờ kịch bản hoạt động tốt trên tất cả các tài liệu lưu trữ xấu của tôi, cũng như một tài liệu tốt.

Những điều cần lưu ý:

  1. Tất cả các tên tệp được trích xuất và hợp nhất thành một chuỗi để tạo ra một đoạn văn bản lớn hơn cho công cụ đoán mã hóa. Điều đó có nghĩa là một vài tên tập tin được gắn vào một cách khác nhau, mỗi tên có thể làm hỏng dự đoán.
  2. Đường dẫn nhanh đặc biệt được sử dụng để xử lý văn bản unicode tốt ( chardetkhông hoạt động với một đối tượng unicode bình thường).
  3. Doctests được thêm vào để kiểm tra và để chứng minh rằng bộ chuẩn hóa nhận ra bất kỳ mã hóa nào trên một chuỗi ngắn hợp lý.

Phiên bản cuối cùng:

#!/usr/bin/env python2
# coding=utf-8

import zipfile
import os
import codecs
import sys

import chardet


def make_encoding_normalizer(txt):
    u'''
    Takes raw data and returns function to normalize encoding of the data.
        * `txt` is either unicode or raw bytes;
        * `chardet` library is used to guess the correct encoding.

    >>> n_unicode = make_encoding_normalizer(u"Привет!")
    >>> print n_unicode(u"День добрый")
    День добрый

    >>> n_cp1251 = make_encoding_normalizer(u"Привет!".encode('cp1251'))
    >>> print n_cp1251(u"День добрый".encode('cp1251'))
    День добрый
    >>> type(n_cp1251(u"День добрый".encode('cp1251')))
    <type 'unicode'>
    '''
    if isinstance(txt, unicode):
        return lambda text: text

    enc = chardet.detect(txt)['encoding']
    return lambda file_name: codecs.decode(file_name, enc)


for filename in sys.argv[1:]:
    archive = zipfile.ZipFile(filename, 'r')
    infolist = archive.infolist()

    probe_txt = "\n".join(i.filename for i in infolist)
    normalizer = make_encoding_normalizer(probe_txt)

    for i in infolist:
        print i.filename
        f = normalizer(i.filename)
        print f
        dirname = os.path.dirname(f)
        if dirname:
            assert os.path.abspath(dirname).startswith(os.path.abspath(".")), \
                "Security violation"
            if not os.path.exists(dirname):
                os.makedirs(dirname)
        if not f.endswith("/"):
            open(f, 'w').write(archive.read(i))
    archive.close()


if __name__ == '__main__' and len(sys.argv) == 1:
    # Hack for Python 2.x to support unicode source files as doctest sources.
    reload(sys)
    sys.setdefaultencoding("UTF-8")

    import doctest
    doctest.testmod()

    print "If there are no messages above, the script passes all tests."

Cảm ơn bạn cho chương trình của bạn! Rất tiếc, chương trình Zip không hoạt động theo Python 3, nhưng nó hoạt động theo Python 2.
beroal

@beroal, tôi cập nhật kịch bản. Bây giờ, nó sử dụng công cụ được phát triển bởi Mozilla cho Firefox để tự động phát hiện mã hóa.
dmitry_romanov

4

POSIX-1.2001 đã chỉ định cách TAR sử dụng UTF-8.

Kể từ năm 2007, phiên bản thay đổi 6.3.0 trong PKZIP APPNOTE.TXT ( http://www.pkware.com/document/casestudies/APPNOTE.TXT ) đã chỉ định cách ZIP sử dụng UTF-8.

Chỉ có công cụ nào hỗ trợ các tiêu chuẩn này đúng cách, đó vẫn là một câu hỏi mở.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.