2013-02-22 6 views
7

Ich versuche, eine Excel-Datei (xlsx) programmgesteuert zu ändern. Ich kann das XMP erfolgreich dekomprimieren, modifizieren und neu komprimieren. Allerdings bekomme ich immer eine Warnung, wenn ich Excel öffne, obwohl es die Datei liest. Ich glaube, der Fehler ist auf die verwendete Komprimierungsmethode zurückzuführen. Dies ist ein Beispiel für die nächste, die ich bekommen kann:Komprimierungsmethode für xlsx mit 7z

Dekomprimieren

7z x original.xlsx -o./decomp_xlsx 

..Do some stuff ..

Compress

7z a -tzip new ./decomp_xlsx/* 

umbenennen

mv ./new.zip ./new.xlsx 

Der Fehler ich bekomme ich s: Excel hat in 'new.xlsx' nicht lesbaren Inhalt gefunden. Möchten Sie den Inhalt dieser Arbeitsmappe wiederherstellen? Wenn Sie der Quelle dieser Arbeitsmappe vertrauen, klicken Sie auf Ja.

Von ECMA-376-2 Office Open Formats Teil 2 (Verpackungskonventionen) Der unterstützte Komprimierungsalgorithmus ist DEFLATE, wie in der .ZIP-Spezifikation beschrieben. Der Paketierungsimplementierer darf keinen anderen Komprimierungsalgorithmus als DEFLATE verwenden.

Also, welche Schalter muss ich in 7z oder anderen Linux-kompatiblen Programm verwenden, um den Job ohne die Warnung zu erledigen? Ich habe versucht, den -tzip fallen zu lassen und -m0 = COPY zu verwenden, aber Excel kann nicht einmal von diesem wiederherstellen.

Also hier ist das Ergebnis des ZIP-Programms und zipinfo. Ich schätze, ich werde kein anderes Tool finden, als das unten angegebene, also werde ich diese Antwort vergeben und sehen, ob ich jemanden finden kann, der python zum Testen übersetzt. I "m nicht sicher, ob es die Unterschiede zwischen dem 4.5/3.0 behandelt, dann b-/tx oder DEFs/Deff though.

$ 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

Führen Sie das Auspacken/Pack mit Ihrer Änderung dazwischen. Vergleichen Sie dann den "zip" Inhalt mit einem Diff-Tool. Sind sie wirklich gleich? Gibt es unbeabsichtigte Änderungen? Fehlt etwas? – usr

+0

7z x original.xlsx -o./original_decomp && 7z a -tzip neu ./original_decomp/* && mv ./new.zip ./new.xlsx && 7z x neu.xlsx -o./new_decomp && diff -r original_dec omp neue_decomp && diff original.xlsx neu.xlsx Dies zeigt, dass die dekomprimierten Ordner identisch sind, aber das Original/neue Diff zeigt Binärdateien unterscheiden. – jnewt

+0

Die anderen Unterschiede sind nicht wichtig. Nur die Version benötigt-zu-extrahieren. –

Antwort

6

Aus irgendeinem seltsamen Grund, Microsoft bei dem Betriebssystem-Codierung in der Suche" Version benötigt, um "in den lokalen Dateiheadern und zentralen Verzeichnisheadern zu extrahieren. Es will diese Null sein, aber 7z setzt sie auf 3 für Unix. Wenn Sie beabsichtigen, 7z zu verwenden, dann müssen Sie die resultierende Datei patchen.

wird dieses Programm das tun:

/* 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

Nun, es klingt, als ob Sie das Problem Mark identifiziert, sowie eine Lösung, die wahrscheinlich funktionieren würde, obwohl es ein bisschen über meinem Kopf ist. Dies führt mich zu zwei weiteren Fragen, die ich zu einem anderen SO-Post verschieben kann, wenn das angemessener ist. 1. Kann dies mit einem vorverpackten Nix-Tool gemacht werden, wenn ja welches? 2. Könnte es in Python oder direkt von bash getan werden (ich rufe ein Python-Skript für meine internen Änderungen an der Datei auf), wenn ja, wie? – jnewt

+1

Es gibt kein anderes Unix-Tool als das obige. Sie können das oben beschriebene Programm sicherlich in Python oder in jede andere Sprache konvertieren, die Dateien lesen, schreiben und suchen kann. Ich glaube nicht, dass Bash einer von denen ist, aber vielleicht gibt es einen Weg, in Bash zu suchen, von dem ich nichts weiß. –

+0

endlich um zu kompilieren und dies zu versuchen, und ja, es behebt das Problem, während immer noch 7z verwenden. Dateien sind unterschiedlich, aber sie beantworten die Frage am direktesten. – jnewt

1

Sie sys verwenden könnte Tem.zip und unzip stattdessen. Ich benutze oft etwas wie das Folgende.

Entpacken die xlsx Datei in ein Verzeichnis:

$ 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 

Dann, eines oder mehrere der XML-Dateien ändern und neu zip ihnen:

$ cd xlsx_dir 

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

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

Die find|zip aus dem Verzeichnis nicht ist Sehr schön, aber es erzeugt eine Dateistruktur, die mit dem Original ohne zusätzliche Wegstrippen übereinstimmt.

+0

jmcnamara - das scheint zu funktionieren, soweit es um Excel geht. Ich bin neugierig, warum es Dateien erzeugt, die anders sind (mit diff), aber immer noch funktioniert? Meine neue Datei ist kleiner als das Original, aber beim Entpacken der neuen Datei zeigt diff auf den Verzeichnissen (der entpackten Dateien), dass sie identisch sind. Ist das ein weiterer Kompressionsunterschied? – jnewt

+0

@ user2100964 Der Unterschied liegt möglicherweise in der Komprimierungsstufe. Sie könnten die anderen 'zip' Kompressionslevel mit' -4', '-5', etc. aus dem Speicher versuchen. Von Excel akzeptiert Excel alle Komprimierungsstufen von 0 bis etwa 8 oder 9. Und 0 bedeutet unkomprimierte Dateien, die anzeigen würden, dass Excel nicht funktioniert Die Komprimierung in der Datei interessiert mich nicht. Aus Gründen der Kompatibilität mit Excel ist es besser, sich darauf zu konzentrieren, die gleiche Datei-/Dateistruktur zu erstellen, anstatt die Komprimierung exakt zu berücksichtigen. – jmcnamara

+0

Ich wünschte, ich könnte zwei Antworten akzeptieren, ich würde dieses eine zwei akzeptieren, da beide recht haben. – jnewt