Modifier un fichier texte dans une archive ZIP en Java

mon dossier d'utilisation me demande d'ouvrir un fichier txt, disons abc.txt qui se trouve à l'intérieur d'une archive zip qui contient des paires de valeurs-clés dans la forme

cle1=valeur1

cle2=valeur2

.. et ainsi de suite, où chaque paire clé-valeur est dans une nouvelle ligne. J'ai pour modifier une valeur correspondant à une clé donnée et de mettre le fichier texte dans une nouvelle copie de l'archive. Comment puis-je le faire en java?

Ma tentative à ce jour:

    ZipFile zipFile = new ZipFile("test.zip");
    final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("out.zip"));
    for(Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
        ZipEntry entryIn = (ZipEntry) e.nextElement();
        if(!entryIn.getName().equalsIgnoreCase("abc.txt")){
            zos.putNextEntry(entryIn);
            InputStream is = zipFile.getInputStream(entryIn);
            byte [] buf = new byte[1024];
            int len;
            while((len = (is.read(buf))) > 0) {            
                zos.write(buf, 0, len);
            }
        }
        else{
            // I'm not sure what to do here
            // Tried a few things and the file gets corrupt
        }
        zos.closeEntry();
    }
    zos.close();
14
demandé sur Prabhakar 2012-07-16 14:12:22

3 réponses

Vous aviez presque raison. Une raison possible, le fichier a été montré comme corrompu est que vous pourriez avoir utilisé

zos.putNextEntry (entryIn)

dans la partie. Cela crée une nouvelle entrée dans le fichier zip contenant des informations du fichier zip existant. Les informations existantes contiennent entre autres le nom de l'entrée(Nom du fichier) et son CRC.

Et puis, quand u essayez de mettre à jour le fichier texte et fermer le fichier zip, il sera jeter une erreur CRC défini dans l'entrée et le CRC de l'objet que vous essayez d'écrire diffèrent.

aussi u peut avoir une erreur si la longueur du texte que vous essayez de remplacer est différente de celle qui existe, c'est-à-dire que vous essayez de remplacer

cle1=valeur1

key1=val1

cela se résume au problème que le tampon que vous essayez d'écrire a une longueur différent de celui spécifié.

ZipFile zipFile = new ZipFile("test.zip");
final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("out.zip"));
for(Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
    ZipEntry entryIn = (ZipEntry) e.nextElement();
    if (!entryIn.getName().equalsIgnoreCase("abc.txt")) {
        zos.putNextEntry(entryIn);
        InputStream is = zipFile.getInputStream(entryIn);
        byte[] buf = new byte[1024];
        int len;
        while((len = is.read(buf)) > 0) {            
            zos.write(buf, 0, len);
        }
    }
    else{
        zos.putNextEntry(new ZipEntry("abc.txt"));

        InputStream is = zipFile.getInputStream(entryIn);
        byte[] buf = new byte[1024];
        int len;
        while ((len = (is.read(buf))) > 0) {
            String s = new String(buf);
            if (s.contains("key1=value1")) {
                buf = s.replaceAll("key1=value1", "key1=val2").getBytes();
            }
            zos.write(buf, 0, (len < buf.length) ? len : buf.length);
        }
    }
    zos.closeEntry();
}
zos.close();

le code suivant garantit que même si les données qui sont remplacées sont d'une longueur inférieure à la longueur originale, aucun IndexOutOfBoundsExceptions ne se produit.

(len < buf.la longueur) ? len : buf.longueur

11
répondu Shiva 2016-07-05 20:22:44

Java 7 introduit une méthode beaucoup plus simple pour faire des manipulations d'archives zip - systèmes de fichiers API, qui permet d'accéder au contenu d'un fichier sous la forme d'un système de fichiers.

en plus de L'API beaucoup plus simple, il fait la modification en place et n'a pas besoin de réécrire d'autres fichiers (non pertinents) dans une archive zip (comme fait dans la réponse acceptée).

import java.io.*;
import java.nio.file.*;

public static void main(String[] args) throws IOException {
    modifyTextFileInZip("test.zip");
}

static void modifyTextFileInZip(String zipPath) throws IOException {
    Path zipFilePath = Paths.get(zipPath);
    try (FileSystem fs = FileSystems.newFileSystem(zipFilePath, null)) {
        Path source = fs.getPath("/abc.txt");
        Path temp = fs.getPath("/___abc___.txt");
        if (Files.exists(temp)) {
            throw new IOException("temp file exists, generate another name");
        }
        Files.move(source, temp);
        streamCopy(temp, source);
        Files.delete(temp);
    }
}

static void streamCopy(Path src, Path dst) throws IOException {
    try (BufferedReader br = new BufferedReader(
            new InputStreamReader(Files.newInputStream(src)));
         BufferedWriter bw = new BufferedWriter(
            new OutputStreamWriter(Files.newOutputStream(dst)))) {

        String line;
        while ((line = br.readLine()) != null) {
            line = line.replace("key1=value1", "key1=value2");
            bw.write(line);
            bw.newLine();
        }
    }
}

Pour plus de zip exemples de manipulation d'archives, voir demo/nio/zipfs/Demo.java échantillon que vous pouvez télécharger ici (cherchez des démos et des échantillons de JDK 8).

7
répondu Alex Lipov 2017-05-07 21:35:10

un peu d'amélioration à:

else{
    zos.putNextEntry(new ZipEntry("abc.txt"));

    InputStream is = zipFile.getInputStream(entryIn);
    byte[] buf = new byte[1024];
    int len;
    while ((len = (is.read(buf))) > 0) {
        String s = new String(buf);
        if (s.contains("key1=value1")) {
            buf = s.replaceAll("key1=value1", "key1=val2").getBytes();
        }
        zos.write(buf, 0, (len < buf.length) ? len : buf.length);
    }
}

Qui devrait être:

else{
    zos.putNextEntry(new ZipEntry("abc.txt"));

    InputStream is = zipFile.getInputStream(entryIn);
    long size = entry.getSize();
    if (size > Integer.MAX_VALUE) {
        throw new IllegalStateException("...");
    }
    byte[] bytes = new byte[(int)size];
    is.read(bytes);
    zos.write(new String(bytes).replaceAll("key1=value1", "key1=val2").getBytes());
}

afin de capturer tous les événements

la raison est que, avec la première, vous pourriez avoir "key1" dans une lecture et "=value1 " dans la suivante, ne pas être en mesure de capturer l'occurrence que vous voulez changer

0
répondu Santiago Ruiz 2016-11-02 17:07:14