2012-07-16 12 views
13

trường hợp sử dụng của tôi yêu cầu tôi để mở một file txt, nói abc.txt mà là bên trong một kho lưu trữ zip chứa cặp khóa-giá trị ở dạngSửa đổi một tập tin văn bản trong một kho lưu trữ ZIP trong Java

key1 = value1

khóa2 = value2

.. và vân vân nơi mà mỗi cặp khóa-giá trị trong một dòng mới. Tôi phải thay đổi một giá trị tương ứng với một khóa nhất định và đặt tệp văn bản trở lại trong bản sao lưu trữ mới. Làm thế nào để làm điều này trong java?

nỗ lực của tôi cho đến nay:

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

Vì vậy, sau đó xả luồng đầu ra, những gì không hoạt động? – MadProgrammer

+0

Tôi không nhận được bạn. Tôi chưa xóa luồng đầu ra một cách rõ ràng. – Prabhakar

Trả lời

10

Bạn đã gần như đã nhận nó đúng. Một lý do có thể, các tập tin được hiển thị như là hỏng là bạn có thể đã sử dụng

zos.putNextEntry (entryIn)

ở phần khác là tốt. Điều này tạo một mục mới trong tệp zip chứa thông tin từ tệp zip hiện có. Thông tin hiện có chứa tên mục nhập (tên tệp) và CRC của nó trong số những thứ khác. Sau đó, khi bạn cố gắng cập nhật tệp văn bản và đóng tệp nén, nó sẽ ném một lỗi khi CRC được xác định trong mục nhập và CRC của đối tượng bạn đang cố gắng viết khác nhau.

Cũng u có thể nhận được một lỗi nếu chiều dài của văn bản mà bạn đang cố gắng thay thế khác so với cái hiện có nghĩa là bạn đang cố gắng để thay thế

key1 = value1

với

key1 = VAL1

Điều này sẽ giải quyết vấn đề mà bộ đệm bạn đang cố gắng ghi có độ dài khác với độ dài được chỉ định.

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

Mã sau đây đảm bảo rằng ngay cả khi dữ liệu được thay thế nhỏ hơn độ dài ban đầu, không có IndexOutOfBoundsExceptions xảy ra.

(len < buf.length)? len: buf.chiều dài

+2

Kudo, câu trả lời này phải được chấp nhận! – sunlock

+2

Bạn nên đi qua bù đắp và chiều dài để bắt đầu chuỗi từ mảng byte, hoặc bạn có nguy cơ rằng khi len nhỏ hơn bộ đệm, chuỗi vẫn được tạo ra bằng cách sử dụng toàn bộ bộ đệm. Điều này thậm chí có thể làm việc hầu hết thời gian! Lỗi nghiêm trọng trong mã ở trên! – Neil

+0

Nếu bạn sửa đổi tệp SAU KHI tạo ZipEntry, thì tệp sau sẽ không nhất quán với dữ liệu (ví dụ CRC). Nó không phải là một vấn đề? – GregT

0

Chỉ có một cải tiến nhỏ để:

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

Đó nên là:

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

Để nắm bắt tất cả các lần xuất hiện

Lý do là, với người đầu tiên , bạn có thể có "key1" trong một lần đọc và "= value1" trong lần tiếp theo, không thể nắm bắt được sự xuất hiện mà bạn muốn thay đổi

2

Java 7 giới thiệu một cách đơn giản hơn nhiều để thực hiện thao tác lưu trữ zip - FileSystems API, cho phép truy cập nội dung của tệp dưới dạng hệ thống tệp .

Ngoài API đơn giản hơn, nó đang thực hiện sửa đổi tại chỗ và không yêu cầu viết lại các tệp khác (không có liên quan) trong kho lưu trữ zip (như được thực hiện trong câu trả lời được chấp nhận).

Dưới đây là mẫu mã mà giải quyết trường hợp sử dụng OP của:

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

Để biết thêm ví dụ thao tác lưu trữ zip, xem demo/nio/zipfs/Demo.java mẫu mà bạn có thể tải về here (tìm JDK 8 Demo và Samples).