2014-10-02 7 views
1

У меня возникла проблема замены или обновления некоторых файлов в определенном каталоге внутри файла jar.Как заменить некоторые файлы в определенном каталоге внутри файла jar?

Я уже прочитал несколько сообщений. Код (JarUpdater Class) приведены по этой ссылке Updating .JAR's contents from code

в настоящее время очень полезно для меня, чтобы понять роль и использование ZipInputStream, ZipOutputStream и ZipEntry, и т.д ..

Однако, когда я запускаю его,

  1. у меня есть EOF Exception

[Отредактированный MK7: Я узнал, что файл поврежден сосуд после того как я прошел через это в 20 раз или около того. Поэтому после того, как я заменил файл jar новым, исключение EOF исчезло. Остальные две проблемы ниже по-прежнему остаются нерешенными]

  1. эти два новых файла xml только копируются в «корневой каталог» файла jar.

  2. эти два новых файла xml НИКОГДА не заменили два оригинальных файла внутри каталога с именем/conf.

Какие строки кода следует изменить, чтобы заменить файлы xml новыми?

С System.out.println я видел, что цикл while проходит через каждый каталог и сравнивается в каждом файле, как и ожидалось. Новый temp jar также был создан, как и ожидалось ... Я думал, что утверждение «notInFiles = false» позаботится о моей потребности, но это НЕ.

Как я могу войти в/conf и заменить только эти два файла и НЕ оставлять копию в корневом файле jar?

Что мне не хватает? Спасибо за понимание!

Ниже приведен код ссылки.

import java.io.*; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipInputStream; 
import java.util.zip.ZipOutputStream; 


public class JarUpdater { 
public static void main(String[] args) { 

    File[] contents = {new File("abc.xml"), 
      new File("def.xml")}; 

    File jarFile = new File("xyz.jar"); 

    try { 
     updateZipFile(jarFile, contents); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 

public static void updateZipFile(File jarFile, 
           File[] contents) throws IOException { 
    // get a temp file 
    File tempFile = File.createTempFile(jarFile.getName(), null); 
    // delete it, otherwise you cannot rename your existing zip to it. 
    tempFile.delete(); 
    System.out.println("tempFile is " + tempFile); 
    boolean renameOk=jarFile.renameTo(tempFile); 
    if (!renameOk) 
    { 
     throw new RuntimeException("could not rename the file  "+jarFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath()); 
    } 
    byte[] buf = new byte[1024]; 

    ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile)); 
    ZipOutputStream out = new ZipOutputStream(new FileOutputStream(jarFile)); 

    ZipEntry entry = zin.getNextEntry(); 
    while (entry != null) { 
     String name = entry.getName(); 
     boolean notInFiles = true; 
     for (File f : contents) { 
      System.out.println("f is " + f); 
      if (f.getName().equals(name)) { 
       // that file is already inside the jar file 
       notInFiles = false; 
       System.out.println("file already inside the jar file"); 
       break; 
      } 
     } 
     if (notInFiles) { 
      System.out.println("name is " + name); 
      System.out.println("entry is " + entry); 
      // Add ZIP entry to output stream. 
      out.putNextEntry(new ZipEntry(name)); 
      // Transfer bytes from the ZIP file to the output file 
      int len; 
      while ((len = zin.read(buf)) > 0) { 
       out.write(buf, 0, len); 
      } 
     } 
     entry = zin.getNextEntry(); 
    } 
    // Close the streams 
    zin.close(); 
    // Compress the contents 
    for (int i = 0; i < contents.length; i++) { 
     InputStream in = new FileInputStream(contents[i]); 
     // Add ZIP entry to output stream. 
     out.putNextEntry(new ZipEntry(contents[i].getName())); 
     // Transfer bytes from the file to the ZIP file 
     int len; 
     while ((len = in.read(buf)) > 0) { 
      out.write(buf, 0, len); 
     } 
     // Complete the entry 
     out.closeEntry(); 
     in.close(); 
    } 
    // Complete the ZIP file 
    out.close(); 
    tempFile.delete(); 
} 
} 

ответ

2

В своем первом цикле (while цикла), где вы копируете записи, которые вы не хотите, чтобы заменить не закрывать записи в выходном файле почтового индекса. Добавить out.closeEntry(); как это:

// Add ZIP entry to output stream. 
out.putNextEntry(new ZipEntry(name)); 
// Transfer bytes from the ZIP file to the output file 
int len; 
while ((len = zin.read(buf)) > 0) { 
    out.write(buf, 0, len); 
} 
// ADD THIS LINE: 
out.closeEntry(); 

Кроме того, когда вы проверяете, если запись должна быть заменена, вы должны сравнить его полный путь, а не только имя файла. Например, если вы хотите заменить abc.xml, который находится в папке /conf, вы должны сравнить имя записи с "/conf/abc.xml", а не с "abc.xml".

Чтобы правильно проверить, если запись должна быть заменена:

String name = entry.getName(); 
boolean notInFiles = true; 
for (File f : contents) { 
    System.out.println("f is " + f); 
    if (name.equals("/conf/" + f.getName()) { 
     // that file is already inside the jar file 
     notInFiles = false; 
     System.out.println("file already inside the jar file"); 
     break; 
    } 
} 

И при добавлении записи к выходу, которые являются замененные файлы, вы также должны указать имя входа, имеющий полный путь, например, "/conf/abc.xml", а не только "abc.xml", потому что он положил бы "abc.xml" в корень выходного zip.

Чтобы сделать это, начните имя входа с "/conf/", как это:

// Add ZIP entry to output stream. 
out.putNextEntry(new ZipEntry("/conf/" + contents[i].getName())); 
+0

Я просто проверю дважды. В коде есть out.closeEntry(); и in.close(); – mk7

+0

Это был файл jar, который был поврежден. Поэтому после того, как я заменил файл jar, исключение EOF исчезло. Я редактировал свой оригинальный вопрос и удалял проблему исключения EOF, с которой я впервые сталкивался. Но даже сейчас у меня все еще нет двух файлов. – mk7

+0

Добавлен код для правильной проверки того, должна ли запись быть заменена (вы не проверили ее правильно, поэтому вы не отфильтровали записи, которые хотите заменить). – icza

1

Для URIs с протоколом jar:file: (полезной для всех почтовых файлов), вы можете использовать файловую системумолнии.

URI jarUri = new URI("jar:" + jarFile.toURI().toString()); // "jar:file:/C:/../xyz.jar" 
Map<String, String> zipProperties = new HashMap<>(); 
zipProperties.put("encoding", "UTF-8"); 
try (FileSystem zipFS = FileSystems.newFileSystem(jarUri, zipProperties)) { 
    for (File file : contents) { 
     Path updatePath = zipFS.getPath("/" + file.getName()); 
     Files.delete(updatePath); 
     Files.copy(file.toPath(), updatePath, StandardCopyOption.REPLACE_EXISTING); 
    } 
} // closes. 

Один из способов вывести URI является префикс "банка:" к File.toURI().

Это немного более элегантно и абстрактно, а также позволяет делать файлы и файлы в ZIP-архивах. Что-то держать в одном сундуке.

+0

это замечательно. Я видел сообщение об использовании File.toURI(). Я не понимаю, как и почему он работает с этим подходом. Могу ли я получить полные коды, чтобы я мог видеть от начала до конца? Thx много! – mk7

+0

Готово, файл 'File.toURI()' prepends ':/", превращает Windows' \ 'в'/'и заменяет пробелы на'% 20'. Java имеет встроенный обработчик протокола для 'jar:' для любого формата zip. –