এটি ঘটতে পারে এমন আরেকটি কোণার ক্ষেত্রে: আপনি যদি একটি JAR ফাইল একটি / র মাধ্যমে পড়েন URL
এবং পরে একই জেভিএম সেশনের মধ্যে একই ফাইলটি মুছতে চেষ্টা করেন।
File f = new File("/tmp/foo.jar");
URL j = f.toURI().toURL();
URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
URLConnection c = u.openConnection();
try (InputStream i = c.getInputStream()) {
byte[] first16 = new byte[16];
i.read(first16);
System.out.println(new String(first16));
}
System.out.println(f.delete());
কারণটি হ'ল জাভাটির অভ্যন্তরীণ জেআর ফাইল হ্যান্ডলিং লজিক, JarFile
এন্ট্রিগুলিতে ক্যাশে থাকে s
class JarURLInputStream extends FilterInputStream {
JarURLInputStream(InputStream var2) {
super(var2);
}
public void close() throws IOException {
try {
super.close();
} finally {
if (!JarURLConnection.this.getUseCaches()) {
JarURLConnection.this.jarFile.close();
}
}
}
}
এবং প্রতিটি JarFile
(বরং, অন্তর্নিহিত ZipFile
কাঠামো) ফাইলের একটি হ্যান্ডেল ধরে রাখবে, নির্মাণের সময় থেকে close()
ডেকে নেওয়া পর্যন্ত :
public ZipFile(File file, int mode, Charset charset) throws IOException {
jzfile = open(name, mode, file.lastModified(), usemmap);
}
private static native long open(String name, int mode, long lastModified,
boolean usemmap) throws IOException;
নেটবিন্সের এই ইস্যুতে একটি ভাল ব্যাখ্যা রয়েছে ।
স্পষ্টতই এটির "সমাধান" করার দুটি উপায় রয়েছে:
আপনি জেআর ফাইল ক্যাচিং অক্ষম করতে পারেন - বর্তমানের জন্য URLConnection
, বা URLConnection
বর্তমান জেভিএম সেশনে ভবিষ্যতের সমস্ত (বিশ্বব্যাপী) জন্য:
URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
URLConnection c = u.openConnection();
c.setUseCaches(false);
c.setDefaultUseCaches(false);
[হ্যাক সতর্কতা!] আপনি JarFile
যখন এটি সম্পন্ন করেন তখন আপনি ম্যানুয়ালি ক্যাশে থেকে মুছে ফেলতে পারেন । ক্যাশে পরিচালকটি sun.net.www.protocol.jar.JarFileFactory
প্যাকেজ-ব্যক্তিগত, তবে কিছু প্রতিবিম্ব যাদু আপনার পক্ষে কাজটি সম্পন্ন করতে পারে:
class JarBridge {
static void closeJar(URL url) throws Exception {
Class<?> jarFactoryClazz = Class.forName("sun.net.www.protocol.jar.JarFileFactory");
Method getInstance = jarFactoryClazz.getMethod("getInstance");
getInstance.setAccessible(true);
Object jarFactory = getInstance.invoke(jarFactoryClazz);
Method get = jarFactoryClazz.getMethod("get", URL.class);
get.setAccessible(true);
Object jarFile = get.invoke(jarFactory, url);
Method close = jarFactoryClazz.getMethod("close", JarFile.class);
close.setAccessible(true);
close.invoke(jarFactory, jarFile);
((JarFile) jarFile).close();
}
}
JarBridge.closeJar(j);
System.out.println(f.delete());
দয়া করে নোট করুন: এগুলি সমস্ত জাভা 8 কোডবাসের উপর ভিত্তি করে ( 1.8.0_144
); তারা অন্যান্য / পরবর্তী সংস্করণগুলির সাথে কাজ নাও করতে পারে।