2012-07-16 348 views
13

我的用例需要我打开一个txt文件,说的abc.txt这是包含在形式修改ZIP档案文本文件中的Java

键1键 - 值对一个zip压缩包内=值1

键2 =值

..等,其中每个键 - 值对是在一个新行。 我必须更改与某个特定键相对应的一个值,并将该文本文件重新放回到存档的新副本中。我如何在java中做到这一点?

我迄今为止尝试:

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(); 
+0

那么,其他然后刷新输出流,有什么不工作? – MadProgrammer 2012-07-16 10:25:16

+0

我没有得到你。我没有明确地刷新输出流。 – Prabhakar 2012-07-17 04:19:50

回答

10

你几乎是正确的。一个可能的原因,该文件显示为损坏的是,你可能已经使用

zos.putNextEntry(entryIn)

在其他部分

为好。这会在包含来自现有zip文件的信息的zip文件中创建一个新条目。现有信息包含条目名称(文件名称)及其CRC等。

然后,当您尝试更新文本文件并关闭zip文件时,它将引发错误,因为条目中定义的CRC和您尝试写入的对象的CRC不同。

此外,如果你正在试图取代文本的长度是一个比现有的即你正在试图取代

key1的不同ü可能得到错误=值

键1 = VAL1

这可以归结为您尝试写入的缓冲区长度与指定的缓冲区长度不同的问题。

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

以下代码确保即使被替换的数据是比原来的长度的长度以下,不会发生IndexOutOfBoundsExceptions。

(len < buf.length)? len:buf。长度

+2

荣誉,这个答复应该被接受! – sunlock 2014-12-19 10:10:33

+2

您应该将偏移量和长度传递给字节数组中的字符串初始化,否则您有可能会在len小于缓冲区时仍然使用整个缓冲区创建字符串。这甚至可能在大部分时间都有效!上述代码严重错误! – Neil 2017-01-06 11:06:50

+0

如果在创建ZipEntry之后修改文件,则后者将与数据不一致(例如CRC)。这不是问题吗? – GregT 2017-09-05 15:09:46

0

只有一点点改进:

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); 
    } 
} 

这应该是:

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

为了捕获所有出现

的原因是,与第一,您可以在一次读取中获得“key1”,然后在下一次获得“= value1”,无法捕获您想要更改的事件

2

Java 7引入了一种更简单的方法来执行zip归档操作 - FileSystems API,它允许以文件系统访问文件内容。

除了更直接的API之外,它正在进行修改,并且不需要在zip存档中重写其他(不相关的)文件(如接受的答案中所做的那样)。

下面是解决了OP的用例的示例代码:

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

更多zip压缩包操作示例,请参阅demo/nio/zipfs/Demo.java样品,你可以下载here(寻找JDK 8演示和样本)。