将tar.gz转换为zip

8

我在我的Ubuntu Web服务器上有一个大量的gzipped归档文件,我需要将它们转换为zip格式。我认为这可以通过编写脚本来完成,但是我应该使用什么编程语言,并且如何解压缩和重新压缩文件呢?

7个回答

8

我会用一个 bash(1) 一行代码来完成这个任务:

for f in *.tar.gz;\
do rm -rf ${f%.tar.gz} ;\
mkdir ${f%.tar.gz} ;\
tar -C ${f%.tar.gz} zxvf $f ;\
zip -r ${f%.tar.gz} $f.zip ;\
rm -rf ${f%.tar.gz} ;\
done

我不太擅长bash(1),所以这并不是很美观。请注意,这会删除许多目录,因此在执行之前,请确保您知道此操作的含义。

有关${foo%bar}语法的更多详细信息,请参见bash(1)参考卡


这基本上就是我所建议的,但你比我更快地举了一个例子。 :) - Sven
@Sven,不测试是缩短时间的好方法。 :) - sarnold

2

使用一个简单的bash脚本会更容易,这样你就可以直接调用tarzip命令。


1

1
你可以使用 node.jstar-to-zip 来达到这个目的。你需要做的就是:
如果您没有安装,请使用 nvm 安装 node.js。
然后使用以下命令安装 tar-to-zip
npm i tar-to-zip -g

并使用它:

tar-to-zip *.tar.gz

此外,您可以通过编程将.tar.gz文件转换为.zip。 您应该在本地安装asynctar-to-zip
npm i async tar-to-zip

然后创建一个名为 converter.js 的文件,其内容如下:
#!/usr/bin/env node

'use strict';

const fs = require('fs');
const tarToZip = require('tar-to-zip');
const eachSeries = require('async/eachSeries');
const names = process.argv.slice(2);

eachSeries(names, convert, exitIfError);

function convert(name, done) {
    const {stdout} = process;
    const onProgress = (n) => {
        stdout.write(`\r${n}%: ${name}`);
    };
    const onFinish = (e) => {
        stdout.write('\n');
        done();
    };

    const nameZip = name.replace(/\.tar\.gz$/, '.zip');    
    const zip = fs.createWriteStream(nameZip)
        .on('error', (error) => {
            exitIfError(error);
            fs.unlinkSync(zipPath);
        });

    const progress = true;
    tarToZip(name, {progress})
        .on('progress', onProgress)
        .on('error', exitIfError)
        .getStream()
        .pipe(zip)
        .on('finish', onFinish);
}

function exitIfError(error) {
    if (!error)
        return;

    console.error(error.message);
    process.exit(1);
}

0

这里是基于@Brad Campbell的答案编写的脚本,它可以处理作为命令参数传递的文件,可以处理其他tar文件类型(未压缩或tarfile支持的其他压缩类型),并处理源tar文件中的目录。如果源文件包含符号链接或硬链接,它还会打印警告,并将它们转换为常规文件。对于符号链接,链接在转换期间被解析。如果链接目标不在tar中,则可能会导致错误;从安全角度来看,这也可能很危险,所以请用户注意。

#!/usr/bin/python

import sys, tarfile, zipfile, glob, re

def convert_one_archive(in_file, out_file):
    with tarfile.open(in_file, mode='r:*') as tf:
        with zipfile.ZipFile(out_file, mode='a', compression=zipfile.ZIP_DEFLATED) as zf:
            for m in [m for m in tf.getmembers() if not m.isdir()]:
                if m.issym() or m.islnk():
                    print('warning: symlink or hardlink converted to file')
                f = tf.extractfile(m)
                fl = f.read()
                fn = m.name
                zf.writestr(fn, fl)

for in_file in sys.argv[1:]:
    out_file = re.sub(r'\.((tar(\.(gz|bz2|xz))?)|tgz|tbz|tbz2|txz)$', '.zip', in_file)
    if out_file == in_file:
        print(in_file, '---> [skipped]')
    else:
        print(in_file, '--->', out_file)
        convert_one_archive(in_file, out_file)

0

Zip文件非常方便,因为它们提供对文件的随机访问。Tar文件只能进行顺序访问。

我对这种转换的解决方案是编写一个shell脚本,该脚本通过tar(1)的"--to-command"选项来调用自身。(我更喜欢这种方式而不是拥有2个脚本)。但我承认,"untar and zip -r"比这种方法更快,因为zipnote(1)不能原地工作,遗憾的是。

#!/bin/zsh -feu

## Convert a tar file into zip:

usage() {
    setopt POSIX_ARGZERO
    cat <<EOF
    usage: ${0##*/} [+-h] [-v] [--] {tarfile} {zipfile}"

-v verbose
-h print this message
converts the TAR archive into ZIP archive.
EOF
    unsetopt POSIX_ARGZERO
}

while getopts :hv OPT; do
    case $OPT in
        h|+h)
            usage
            exit
            ;;
        v)
            # todo: ignore TAR_VERBOSE from env?
            # Pass to the grand-child process:
            export TAR_VERBOSE=y
            ;;
        *)
            usage >&2
            exit 2
    esac
done
shift OPTIND-1
OPTIND=1

# when invoked w/o parameters:
if [ $# = 0 ] # todo: or stdin is not terminal
then
    # we are invoked by tar(1)
    if [ -n "${TAR_VERBOSE-}" ]; then echo $TAR_REALNAME >&2;fi
    zip --grow --quiet $ZIPFILE -
    # And rename it:
    # fixme: this still makes a full copy, so slow.
    printf "@ -\n@=$TAR_REALNAME\n" | zipnote -w $ZIPFILE
else
    if [ $# != 2 ]; then usage >&2; exit 1;fi
    # possibly: rm -f $ZIPFILE
    ZIPFILE=$2 tar -xaf $1 --to-command=$0
fi

0

这里是一个基于这个答案的Python解决方案:

import sys, tarfile, zipfile, glob

def convert_one_archive(file_name):
    out_file = file_name.replace('.tar.gz', '.zip')
    with tarfile.open(file_name, mode='r:gz') as tf:
        with zipfile.ZipFile(out_file, mode='a', compression=zipfile.ZIP_DEFLATED) as zf:
            for m in tf.getmembers():
                f = tf.extractfile( m )
                fl = f.read()
                fn = m.name
                zf.writestr(fn, fl)

for f in glob.glob('*.tar.gz'):
    convert_one_archive(f)

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