简体   繁体   English

如何在java中以务实的方式从jar中删除特定的文件/文件夹

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

How to delete a specific File/Folder from a jar pragmatically in java.如何在 java 中以务实的方式从 jar 中删除特定的文件/文件夹。

I have a jar ABC.jar contains files, folder and another jars say child.jar.我有一个 jar ABC.jar 包含文件、文件夹和另一个 jars 说 child.jar。 under child.jar I want to delete a specific file.在 child.jar 下我想删除一个特定的文件。 How can I do?我能怎么做? so that my ABC.jar structure remains same.这样我的 ABC.jar 结构保持不变。

Any help will be appreciate.任何帮助将不胜感激。

Thanks in Advance.提前致谢。

As answered by @icza we have to iterate through original jar file and deleting the entry we don't want. 正如@icza所回答的,我们必须遍历原始jar文件并删除我们不想要的条目。 Here is the java code you can refer. 这是您可以参考的Java代码。

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

} }

Jar/zip files are not editable. Jar / zip文件不可编辑。 You can't delete an entry from a jar/zip file. 您无法从jar / zip文件中删除条目。

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. 你可以做的是“重新创建”这样的jar文件:启动一个新的jar文件,迭代当前jar文件的条目,并将这些条目添加到你不想删除的新jar文件中。


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): 从理论上讲,可以删除这样的条目(但标准的Java lib不适合这个,意思是ZipFileZipInputStreamJarFileJarInputStream类):

Entries in a jar/zip file are sequencial. jar / zip文件中的条目是顺序的。 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. 或者您的其他选项包括不通过Java执行此操作,而是使用zip -d命令本身等外部工具。

Sun/Oracle bug database asks for this feature to be implemented in the java api. Sun / Oracle错误数据库要求在java api中实现此功能。

Check here 点击这里

There is a simple way to delete a file from a JAR by executing a command shell during runtime. 有一种通过在运行时执行命令shell从JAR中删除文件的简单方法。 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. 其中path是jar文件的绝对路径, some_file.txt是要删除的文件。 In this example the file resides on the main folder of the jar. 在此示例中,文件驻留在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: 你可能知道jar本身的路径,或者可以根据你执行命令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());
    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"));
}

You can use the Zip File System to treat zip/jar files as a file system.您可以使用 Zip 文件系统将 zip/jar 文件视为文件系统。 This will allow you to edit, delete, and add files to the jar file.这将允许您编辑、删除和向 jar 文件添加文件。

See Appending files to a zip file with Java请参阅使用 Java 将文件附加到 zip 文件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM