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();
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
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).
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