How to delete a specific File/Folder from a jar pragmatically in java

生来就可爱ヽ(ⅴ<●) 提交于 2021-01-22 08:01:40

问题


How to delete a specific File/Folder from a jar pragmatically in java.

I have a jar ABC.jar contains files, folder and another jars say child.jar. under child.jar I want to delete a specific file. How can I do? so that my ABC.jar structure remains same.

Any help will be appreciate.

Thanks in Advance.


回答1:


As answered by @icza we have to iterate through original jar file and deleting the entry we don't want. Here is the java code you can refer.

 public static void main(String[] args) throws IOException {


  String jarName = args[0];
  String fileName = args[1];

  // Create file descriptors for the jar and a temp jar.

  File jarFile = new File(jarName);
  File tempJarFile = new File(jarName + ".tmp");

  // Open the jar file.

  JarFile jar = new JarFile(jarFile);
  System.out.println(jarName + " opened.");

  // Initialize a flag that will indicate that the jar was updated.

  boolean jarUpdated = false;

  try {
     // Create a temp jar file with no manifest. (The manifest will
     // be copied when the entries are copied.)

     Manifest jarManifest = jar.getManifest();
     JarOutputStream tempJar =
        new JarOutputStream(new FileOutputStream(tempJarFile));

     // Allocate a buffer for reading entry data.

     byte[] buffer = new byte[1024];
     int bytesRead;

     try {
        // Open the given file.

        FileInputStream file = new FileInputStream(fileName);

        try {
           // Create a jar entry and add it to the temp jar.

           JarEntry entry = new JarEntry(fileName);
           tempJar.putNextEntry(entry);

           // Read the file and write it to the jar.

           while ((bytesRead = file.read(buffer)) != -1) {
              tempJar.write(buffer, 0, bytesRead);
           }

           System.out.println(entry.getName() + " added.");
        }
        finally {
           file.close();
        }

        // Loop through the jar entries and add them to the temp jar,
        // skipping the entry that was added to the temp jar already.

        for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
           // Get the next entry.

           JarEntry entry = (JarEntry) entries.nextElement();

           // If the entry has not been added already, add it.

           if (! entry.getName().equals(fileName)) {
              // Get an input stream for the entry.

              InputStream entryStream = jar.getInputStream(entry);

              // Read the entry and write it to the temp jar.

              tempJar.putNextEntry(entry);

              while ((bytesRead = entryStream.read(buffer)) != -1) {
                 tempJar.write(buffer, 0, bytesRead);
              }
           }
        }

        jarUpdated = true;
     }
     catch (Exception ex) {
        System.out.println(ex);

        // Add a stub entry here, so that the jar will close without an
        // exception.

        tempJar.putNextEntry(new JarEntry("stub"));
     }
     finally {
        tempJar.close();
     }
  }
  finally {
     jar.close();
     System.out.println(jarName + " closed.");

     // If the jar was not updated, delete the temp jar file.

     if (! jarUpdated) {
        tempJarFile.delete();
     }
  }

  // If the jar was updated, delete the original jar file and rename the
  // temp jar file to the original name.

  if (jarUpdated) {
     jarFile.delete();
     tempJarFile.renameTo(jarFile);
     System.out.println(jarName + " updated.");
  }

}




回答2:


Sun/Oracle bug database asks for this feature to be implemented in the java api.

Check here




回答3:


There is a simple way to delete a file from a JAR by executing a command shell during runtime. Executing the command below does the job:

Runtime.getRuntime().exec("zip -d path\my.jar some_file.txt");

Where path is the absolute path to the jar file and some_file.txt is the file to be deleted. In this example the file resides on the main folder of the jar. You may need to provide its relative path if the file resides on a different folder

The path of the jar itself you may know ahead or can find it relatively based on the class you are executing the command shell:

String path = SomeClass.class.getProtectionDomain().getCodeSource().getLocation().getPath();

You can trace the execution of the process by listening to the available streams:

    Process p = Runtime.getRuntime().exec("zip -d path\my.jar some_file.txt");
    BufferedReader reader = 
            new BufferedReader(new InputStreamReader(p.getInputStream()));

       String line = "";    
       StringBuilder sb = new StringBuilder();
       while ((line = reader.readLine())!= null) {
           sb.append(line + "\n");
           System.out.println(line);
       }
       System.out.println(sb.toString());



回答4:


Jar/zip files are not editable. You can't delete an entry from a jar/zip file.

What you can do is "re-create" the jar file like this: start a new jar file, iterate over the entries of the current jar file, and add those entries to the new jar file which you do not want to delete.


Theoretically it would be possible to delete an entry like this (but the standard Java lib is not suitable for this, meaning the ZipFile, ZipInputStream, JarFile, JarInputStream classes):

Entries in a jar/zip file are sequencial. Each entry has a header with info about the entry (which may be a file or folder entry). This header also contains the byte-length of the entry. So you could iterate over the entries sequencially, and if you encounter an entry which you want to delete (and you know its size from its header), you could copy the remaining of the file (content after this entry) to the begining of the current entry (obviously the file size should be trunced by the length of the current / deleted entry).


Or your other options include not doing this via Java but using an external tool like the zip -d command itself.




回答5:


    public static void filterJar(Path jarInFileName, String skipRegex, Path jarOutFileName) throws IOException {
        ZipEntry entry;
        ZipInputStream zis = null;
        JarOutputStream os = null;
        FileInputStream is = null;
        try {
            is = new FileInputStream(jarInFileName.toFile());
            Pattern pattern = Pattern.compile(skipRegex);
            zis = new ZipInputStream(is);
            os = new JarOutputStream(new FileOutputStream(jarOutFileName.toFile())); 
            while ((entry = zis.getNextEntry()) != null) {
                if (pattern.matcher(entry.getName()).matches()) continue;
                os.putNextEntry(entry);
                if (!entry.isDirectory()) {
                    byte[] bytes = toBytes(zis);
                    os.write(bytes);
                }
            }
        }
        catch (Exception ex) {
           throw new IOException("unable to filter jar:" + ex.getMessage());
        }
        finally {
            closeQuietly(is);
            closeQuietly(os);
        }
    }
    public static void closeQuietly(final Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        }
        catch (final Exception e) {}
    }
    public static byte[] toBytes(InputStream aInput) throws IOException {
        byte[] bucket = new byte[5 * 1024];
        ByteArrayOutputStream result = null;
        result = new ByteArrayOutputStream(bucket.length);
        int bytesRead = 0;
        while (bytesRead != -1) {
            bytesRead = aInput.read(bucket);
            if (bytesRead > 0) {
                result.write(bucket, 0, bytesRead);
            }
        }
        return result.toByteArray();
    }

public static void main(String[] args) throws IOException {
  filterJar(Paths.get("./old.jar"), "BOOT-INF/lib.*", Paths.get("./new.jar"));
}


来源:https://stackoverflow.com/questions/25440540/how-to-delete-a-specific-file-folder-from-a-jar-pragmatically-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!