2013-02-22 37 views
7

我試圖以編程方式修改一個excel文件(xlsx)。我可以成功解壓縮,根據需要修改xml,然後重新壓縮。但是,我每次打開excel時都會收到警告,即使它讀取了文件。我相信這個錯誤是由於使用了壓縮方法。這是最接近的一個例子,我可以得到:xlsx與7z的壓縮方法

解壓

7z x original.xlsx -o./decomp_xlsx 

..Do一些東西..

壓縮

7z a -tzip new ./decomp_xlsx/* 

重命名

mv ./new.zip ./new.xlsx 

錯誤我得到我s:Excel在'new.xlsx'中發現了不可讀的內容。你想恢復這個工作簿的內容嗎?如果您信任此工作簿的來源,請單擊是。

從ECMA-376-2辦公開放格式第2部分(包裝規範) 支持的壓縮算法是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% 
+2

運行之間的修改解包/包。然後比較「zip」內容和diff工具。他們真的是一樣的嗎?有沒有意想不到的變化?有什麼缺失? – usr 2013-02-22 21:41:59

+0

7z x original.xlsx -o./original_decomp && 7z a -tzip new ./original_decomp/* && mv ./new.zip ./new。xlsx && 7z x new.xlsx -o./new_decomp && diff -r original_dec omp new_decomp && diff original.xlsx new.xlsx這表明解壓縮的文件夾是相同的,但原始/新差異顯示二進制文件不同。 – jnewt 2013-02-22 23:41:58

+0

其他差異並不重要。只需要提取版本即可。 – 2013-02-25 04:38:53

回答

6

一些奇怪的原因,微軟正在尋找在操作系統編碼」版本需要提取「在本地文件頭和中央目錄頭,它希望那些爲零,但7z將它們設置爲3,如果你打算使用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; 
} 
+0

好吧,這聽起來像你已經確定了問題馬克,以及可能會起作用的解決方案,雖然它有點高於我的頭。這導致我有兩個其他問題,如果更合適,我可以轉到另一個SO帖子。 1.這可以用一個預先包裝的nix工具來完成,如果是這樣的話? 2.是否可以在python中完成,或者直接從bash中完成(我打電話給我的內部修改文件的python腳本),如果是這樣,怎麼辦? – jnewt 2013-02-23 12:38:37

+1

除上述之外,沒有任何Unix工具可以這樣做。您當然可以將上述程序轉換爲Python或任何可以讀取,寫入和查找文件的語言。我不認爲bash是其中之一,但也許有一種方法可以在bash中尋找我不知道的東西。 – 2013-02-23 15:52:36

+0

終於開始編譯和嘗試這個,是的,它確實解決了問題,同時仍然使用7z。文件是不同的,但它確實以最直接的方式回答了問題。 – jnewt 2013-02-25 14:27:59

1

你可以使用SYS取而代之的是zipunzip。我經常使用類似以下的東西。

解壓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|zip不非常漂亮,但它生成的文件結構與原始文件相匹配,無需額外的路徑剝離。

+0

jmcnamara - 就excel而言,這似乎起作用。我很好奇它爲什麼產生不同的文件(使用差異),但仍然有效?我的新文件比原始文件小,但在解壓縮新文件時,對解壓縮文件的目錄進行比較顯示它們是相同的。這是另一種壓縮差異嗎? – jnewt 2013-02-24 11:00:36

+0

@ user2100964壓縮級別可能有所不同。您可以使用'-4','-5'等嘗試其他'zip'壓縮級別。從內存中,Excel接受從0到大約8或9的所有壓縮級別。而0表示未壓縮的文件,這表明Excel不會實際上並不關心文件中使用的壓縮。因此,爲了與Excel兼容,最好專注於生成相同的目錄/文件結構,而不是完全匹配壓縮。 – jmcnamara 2013-02-24 18:05:51

+0

我希望我能接受兩個答案,我會接受這一個兩個,因爲兩個都是對的。 – jnewt 2013-02-25 14:28:30