2013-02-22 18 views
7

Sto provando a modificare a livello di programmazione un file excel (xlsx). Posso decomprimere con successo, modificare l'xml secondo necessità e ricomprimerlo. Tuttavia, ricevo un avviso ogni volta che apro Excel, anche se legge il file. Credo che l'errore sia dovuto al metodo di compressione usato. Questo è un esempio dei più vicini posso ottenere:metodo di compressione per xlsx con 7z

Decompress

7z x original.xlsx -o./decomp_xlsx 

..Do alcune cose ..

Compress

7z a -tzip new ./decomp_xlsx/* 

Rinomina

mv ./new.zip ./new.xlsx 

L'errore ottengo io s: Excel ha trovato contenuti illeggibili in 'new.xlsx'. Vuoi recuperare il contenuto di questa cartella di lavoro? Se ti fidi dell'origine di questa cartella di lavoro, fai clic su Sì.

Da ECMA-376-2 Formati aperti Office Parte 2 (Convenzioni di packaging) L'algoritmo di compressione supportato è DEFLATE, come descritto nella specifica .ZIP. L'implementatore del pacchetto non deve utilizzare alcun algoritmo di compressione diverso da DEFLATE.

Quindi, quali interruttori devo utilizzare in 7z o in un altro programma compatibile con Linux per portare a termine il lavoro senza l'avviso? Ho provato a rilasciare -tzip e usare -m0 = COPY, ma excel non può nemmeno recuperare da quello.

Quindi ecco il risultato del programma zip e zipinfo. Immagino che non troverò uno strumento per farlo, oltre a quello fornito di seguito, quindi premetterò la risposta e vedrò se riesco a trovare qualcuno da tradurre in python per il test. I "Non sono sicuro che gestisce le differenze tra il 4.5/3.0, quindi B-/tx o defs/deff però.

$ 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

Esegui il decomprimere/pacchetto con la modifica in mezzo. Quindi confrontare i contenuti "zip" con uno strumento diff. Sono davvero uguali? Ci sono modifiche non intenzionali? Manca qualcosa? – usr

+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 Questo mostra che le cartelle decompresse sono identiche, ma la differenza originale/nuova mostra i file binari differiscono. – jnewt

+0

Le altre differenze non contano. Solo la versione necessaria per estrarre. –

risposta

6

Per qualche strana ragione, Microsoft sta guardando la codifica del sistema operativo nella" versione necessaria per estrarre "nelle intestazioni dei file locali e nelle intestazioni delle directory centrali. Vuole che siano zero, ma 7z li imposta su 3 per Unix. Se si è intenzionati ad usare 7z, allora sarà necessario patchare il file risultante.

Questo programma lo farà:

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

Beh, sembra che tu abbia identificato il problema Mark, oltre a una soluzione che probabilmente avrebbe funzionato, anche se è un po 'sopra la mia testa. Questo mi porta ad altre due domande, che posso spostare su un altro post SO se è più appropriato. 1. Può essere fatto con uno strumento nix preconfezionato, in caso affermativo quale? 2. Potrebbe essere fatto in python o direttamente da bash (sto chiamando uno script python per le mie modifiche interne al file), se sì, come? – jnewt

+1

Non esiste uno strumento Unix, diverso da quello sopra, che lo farà. Puoi sicuramente convertire il programma qui sopra in Python o qualsiasi altra lingua che possa leggere, scrivere e cercare su file. Non credo che bash sia uno di quelli, ma forse c'è un modo per cercare in bash che non conosco. –

+0

alla fine è riuscito a compilare e provare questo, e sì, risolve il problema, mentre ancora usa 7z. i file sono diversi, ma risponde alla domanda nel modo più diretto. – jnewt

1

si potrebbe usare sys tem zip e unzip invece. Io uso spesso qualcosa come il seguente.

Unzip il file xlsx in una directory:

$ 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 

quindi modificare uno o più dei file XML e li ri-Zip:

$ cd xlsx_dir 

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

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

Il find|zip all'interno della directory non è molto carina ma genera una struttura di file che corrisponde all'originale senza path stripping aggiuntivo.

+0

jmcnamara - questo sembra funzionare per quanto riguarda Excel. Sono curioso di sapere perché produce file diversi (usando diff), ma funziona ancora? Il mio nuovo file è più piccolo dell'originale, ma quando si decomprime il nuovo file, diff sulle directory (dei file decompressi) mostra che sono uguali. Questa è un'altra differenza di compressione? – jnewt

+0

@ user2100964 La differenza può essere ridotta al livello di compressione. Si può provare l'altro livello di compressione 'zip' usando' -4', '-5', ecc. Da memoria Excel accetta tutti i livelli di compressione da 0 fino a circa 8 o 9. E 0 significa file non compressi che indicherebbero che Excel non funziona si preoccupano veramente della compressione usata nel file. Pertanto, per la compatibilità con Excel è meglio concentrarsi sulla generazione della stessa struttura di file/dir anziché sulla corrispondenza esatta della compressione. – jmcnamara

+0

Vorrei poter accettare due risposte, accetterei questo due, poiché entrambi hanno ragione. – jnewt