7

我正在尝试以编程方式修改 excel 文件(xlsx)。我可以成功解压,根据需要修改xml,重新压缩。但是,每次打开 excel 时都会收到警告,即使它确实读取了文件。我相信错误是由于使用的压缩方法造成的。这是我能得到的最接近的例子:

解压

7z x original.xlsx -o./decomp_xlsx

..做一些事情..

压缩

7z a -tzip new ./decomp_xlsx/*

改名

mv ./new.zip ./new.xlsx

我得到的错误是:Excel 在“new.xlsx”中发现了不可读的内容。是否要恢复此工作簿的内容?如果您信任此工作簿的来源,请单击“是”。

来自 ECMA-376-2 Office Open Formats Part 2 (Packaging Conventions) 支持的压缩算法是 DEFLATE,如 .ZIP 规范中所述。包实现者不得使用除 DEFLATE 之外的任何压缩算法。

那么,我需要在 7z 或其他 linux 兼容程序中使用哪些开关才能在没有警告的情况下完成工作?我试过删除 -tzip 并使用 -m0=COPY,但 excel 甚至无法从那个中恢复。

所以这里是 zip 程序和 zipinfo 的结果。我猜除了下面提供的工具外,我不会找到执行此操作的工具,因此我将授予该答案,并看看是否可以找到可以翻译为 python 进行测试的人。我不确定它是否处理 4.5 / 3.0,然后是 b- / tx 或 defS / defF 之间的差异。

$ zipinfo original.xlsx
Archive:  original.xlsx
Zip file size: 228039 bytes, number of entries: 20
-rw----     4.5 fat     1969 b- defS 80-Jan-01 00:00 [Content_Types].xml
-rw----     4.5 fat      588 b- defS 80-Jan-01 00:00 _rels/.rels
-rw----     4.5 fat     1408 b- defS 80-Jan-01 00:00 xl/_rels/workbook.xml.rels
-rw----     4.5 fat      908 b- defS 80-Jan-01 00:00 xl/workbook.xml
-rw----     4.5 fat    35772 b- defS 80-Jan-01 00:00 xl/worksheets/sheet4.xml
-rw----     4.5 fat      322 b- defS 80-Jan-01 00:00 xl/worksheets/_rels/sheet4.xml.rels
-rw----     4.5 fat      322 b- defS 80-Jan-01 00:00 xl/worksheets/_rels/sheet1.xml.rels
-rw----     4.5 fat   230959 b- defS 80-Jan-01 00:00 xl/worksheets/sheet2.xml
-rw----     4.5 fat   263127 b- defS 80-Jan-01 00:00 xl/worksheets/sheet3.xml
-rw----     4.5 fat   295775 b- defS 80-Jan-01 00:00 xl/worksheets/sheet1.xml
-rw----     4.5 fat     1947 b- defS 80-Jan-01 00:00 xl/sharedStrings.xml
-rw----     4.5 fat    22698 b- defS 80-Jan-01 00:00 xl/styles.xml
-rw----     4.5 fat     7079 b- defS 80-Jan-01 00:00 xl/theme/theme1.xml
-rw----     4.5 fat      220 b- defS 80-Jan-01 00:00 xl/printerSettings/printerSettings2.bin
-rw----     4.5 fat   464247 b- defS 80-Jan-01 00:00 xl/externalLinks/externalLink1.xml
-rw----     4.5 fat      338 b- defS 80-Jan-01 00:00 xl/externalLinks/_rels/externalLink1.xml.rels
-rw----     4.5 fat      220 b- defS 80-Jan-01 00:00 xl/printerSettings/printerSettings1.bin
-rw----     4.5 fat      593 b- defS 80-Jan-01 00:00 docProps/core.xml
-rw----     4.5 fat    62899 b- defS 80-Jan-01 00:00 xl/calcChain.xml
-rw----     4.5 fat     1031 b- defS 80-Jan-01 00:00 docProps/app.xml
20 files, 1392422 bytes uncompressed, 223675 bytes compressed:  83.9%

$ zipinfo new.xlsx
Archive:  new.xlsx
Zip file size: 233180 bytes, number of entries: 20
-rw-r--r--  3.0 unx     1031 tx defF 80-Jan-01 00:00 docProps/app.xml
-rw-r--r--  3.0 unx      593 tx defF 80-Jan-01 00:00 docProps/core.xml
-rw-r--r--  3.0 unx    62899 tx defF 80-Jan-01 00:00 xl/calcChain.xml
-rw-r--r--  3.0 unx   464247 tx defF 80-Jan-01 00:00 xl/externalLinks/externalLink1.xml
-rw-r--r--  3.0 unx      338 tx defF 80-Jan-01 00:00 xl/externalLinks/_rels/externalLink1.xml.rels
-rw-r--r--  3.0 unx      220 bx defF 80-Jan-01 00:00 xl/printerSettings/printerSettings1.bin
-rw-r--r--  3.0 unx      220 bx defF 80-Jan-01 00:00 xl/printerSettings/printerSettings2.bin
-rw-r--r--  3.0 unx     1947 tx defF 80-Jan-01 00:00 xl/sharedStrings.xml
-rw-r--r--  3.0 unx    22698 tx defF 80-Jan-01 00:00 xl/styles.xml
-rw-r--r--  3.0 unx     7079 tx defF 80-Jan-01 00:00 xl/theme/theme1.xml
-rw-r--r--  3.0 unx      908 tx defF 80-Jan-01 00:00 xl/workbook.xml
-rw-r--r--  3.0 unx   295775 tx defF 80-Jan-01 00:00 xl/worksheets/sheet1.xml
-rw-r--r--  3.0 unx   230959 tx defF 80-Jan-01 00:00 xl/worksheets/sheet2.xml
-rw-r--r--  3.0 unx   263127 tx defF 80-Jan-01 00:00 xl/worksheets/sheet3.xml
-rw-r--r--  3.0 unx    35772 tx defF 80-Jan-01 00:00 xl/worksheets/sheet4.xml
-rw-r--r--  3.0 unx      322 tx defF 80-Jan-01 00:00 xl/worksheets/_rels/sheet1.xml.rels
-rw-r--r--  3.0 unx      322 tx defF 80-Jan-01 00:00 xl/worksheets/_rels/sheet4.xml.rels
-rw-r--r--  3.0 unx     1408 tx defF 80-Jan-01 00:00 xl/_rels/workbook.xml.rels
-rw-r--r--  3.0 unx     1969 tx defF 80-Jan-01 00:00 [Content_Types].xml
-rw-r--r--  3.0 unx      588 tx defF 80-Jan-01 00:00 _rels/.rels
20 files, 1392422 bytes uncompressed, 229608 bytes compressed:  83.5%
4

2 回答 2

7

出于某种奇怪的原因,微软正在查看本地文件头和中央目录头中“需要提取的版本”中的操作系统编码。它希望那些为零,但 7z 将它们设置为 3 用于 Unix。如果您打算使用 7z,则需要修补生成的文件。

该程序将这样做:

/* needz.c - zero the operating system byte for "version needed to extract" in
   the local and central headers of the zip files given on the command line.
   Placed in the public domain by Mark Adler, 23 Feb 2013. */

#include <stdio.h>
#include <stdlib.h>

static void bail(char *why, char *what)
{
    fprintf(stderr, "needz error: %s%s\n", why, what);
    exit(1);
}

/* Read len bytes from offset as a little-endian integer.  Negative offsets are
   considered to be from the end of the file. */
static unsigned long peek(FILE *stream, off_t offset, int len)
{
    int ret, shift;
    unsigned long val;

    ret = fseeko(stream, offset, offset < 0 ? SEEK_END : SEEK_SET);
    if (ret)
        bail("not a zip file", "");
    val = 0;
    shift = 0;
    while (len--) {
        ret = getc(stream);
        if (ret == EOF)
            bail("not a zip file", "");
        val += (unsigned long)ret << shift;
        shift += 8;
    }
    return val;
}

/* Write len bytes to offset from val as a little-endian integer.  Negative
   offsets are considered to be from the end of the file. */
static void poke(FILE *stream, off_t offset, int len, unsigned long val)
{
    int ret;

    ret = fseeko(stream, offset, offset < 0 ? SEEK_END : SEEK_SET);
    if (ret)
        bail("not a zip file", "");
    while (len--) {
        ret = putc(val, stream);
        if (ret == EOF)
            bail("could not write", "");
        val >>= 8;
    }
}

/* Zero out the OS byte in the extract fields.  This assumes the classic zip
   format (not Zip64), and no zip file comment. */
static void zip_zero_os(char *path)
{
    FILE *zip;
    unsigned entries;
    off_t central, local;

    zip = fopen(path, "r+b");
    if (zip == NULL)
        bail("could not open", path);
    if (peek(zip, -22, 4) != 0x06054b50)
        bail(path, " is not a zip file or has an end comment");
    entries = peek(zip, -12, 2);
    central = peek(zip, -6, 4);
    while (entries--) {
        if (peek(zip, central, 4) != 0x02014b50)
            bail(path, " has a structure error or is Zip64");
        poke(zip, central + 7, 1, 0);
        local = peek(zip, central + 42, 4);
        if (peek(zip, local, 4) != 0x04034b50)
            bail(path, " has a structure error or is Zip64");
        poke(zip, local + 5, 1, 0);
        central += 46 + peek(zip, central + 28, 2) +
                   peek(zip, central + 30, 2) + peek(zip, central + 32, 2);
    }
    if (fclose(zip) == EOF)
        bail("could not close ", path);
}

int main(int argc, char **argv)
{
    while (--argc)
        zip_zero_os(*++argv);
    return 0;
}
于 2013-02-23T08:17:46.460 回答
1

您可以使用 systemzipunzip不是。我经常使用类似下面的东西。

将 xlsx 文件解压缩到一个目录:

$ unzip -o -d xlsx_dir Workbook1.xlsx
Archive:  Workbook1.xlsx
  inflating: xlsx_dir/[Content_Types].xml  
  inflating: xlsx_dir/_rels/.rels    
  inflating: xlsx_dir/xl/_rels/workbook.xml.rels  
  inflating: xlsx_dir/xl/workbook.xml  
  inflating: xlsx_dir/xl/sharedStrings.xml  
  inflating: xlsx_dir/xl/theme/theme1.xml  
  inflating: xlsx_dir/xl/styles.xml  
  inflating: xlsx_dir/xl/worksheets/sheet1.xml  
 extracting: xlsx_dir/docProps/thumbnail.jpeg  
  inflating: xlsx_dir/docProps/core.xml  
  inflating: xlsx_dir/docProps/app.xml  

然后修改一个或多个 XML 文件并重新压缩它们:

$ cd xlsx_dir

# Do something with the files like:
$ sed -i '' s/Foo/Bar/ xl/sharedStrings.xml     

$ find . -type f | xargs zip ../newfile.xlsx

目录中的find|zipfrom 不是很漂亮,但它会生成一个与原始文件结构匹配的文件结构,而无需额外的路径剥离。

于 2013-02-24T00:42:08.577 回答