file.delete () file.exists (), file.canRead (), file.canWrite (), file.canExecute () সমস্ত প্রত্যাবর্তনের পরেও মিথ্যা ফিরিয়ে দেয়


90

আমি একটি ফাইল মুছে ফেলতে, এটা কিছু লেখার পর চেষ্টা করছি FileOutputStream। আমি লেখার জন্য এই কোডটি ব্যবহার করি:

private void writeContent(File file, String fileContent) {
    FileOutputStream to;
    try {
        to = new FileOutputStream(file);
        to.write(fileContent.getBytes());
        to.flush();
        to.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

যেমনটি দেখা যায়, আমি ফ্লাশটি প্রবাহিত করি এবং বন্ধ করি, কিন্তু যখন আমি মোছার চেষ্টা করি তখন file.delete()মিথ্যা ফিরিয়ে দেয়।

আমি মুছে ফেলার আগে চেক করা ফাইলটি বিদ্যমান দেখতে পাও ও: file.exists(), file.canRead(), file.canWrite(), file.canExecute()সব আগমন সত্য। এই পদ্ধতিগুলি বলার পরেও আমি চেষ্টা করে file.delete()মিথ্যা প্রত্যাবর্তন করি ।

আমি কি কিছু ভুল করেছি?


আমি উল্লেখ করতে ভুলে গেছি যে কোনও ব্যতিক্রম ধরা পড়ে না।
জেনি স্মিথ

আপনি কি নিশ্চিত যে ফাইলটি অন্য কোনও প্রক্রিয়া দ্বারা ব্যবহৃত হয়নি? আপনি এটি লক করেছেন? এটি কী মুছে ফেলা ছাড়িয়ে কাজ করে?
উদাহরণস্বরূপ আমার

আপনি কোন ওএস চালাচ্ছেন? আপনি নিজে ফাইলটি মুছতে পারেন? কিছু ফাইলের জন্য একটি উন্মুক্ত হ্যান্ডেল ধরে রাখতে পারে।
আকনারোকদ

এটি অন্য প্রক্রিয়া দ্বারা ব্যবহৃত হয়েছে কিনা তা আমি কীভাবে জানতে পারি? আমি এটি লক না। আমি ডিলিটঅনএক্সিট পদ্ধতিটি ব্যবহার করতে পারি না, কারণ এর পরে আমার ফাইলটি মুছে ফেলা এবং আমার অ্যাপ্লিকেশনটি চালিয়ে নেওয়া দরকার idea ধারণাটি হ'ল আমি একটি অস্থায়ী ফোল্ডারটি বের করার চেষ্টা করি যা একটি সেশনের জন্য আলাদা ফোল্ডার থেকে ফাইলগুলি সঞ্চয় করতে ব্যবহৃত হয়। আমি যখন আমার অ্যাপ্লিকেশনটিতে খোলা বোতাম টিপছি তখন এর অর্থ ফোল্ডারটি খালি করতে হবে, অন্য কোনও ফাইলের জন্য জায়গা তৈরি করতে। আমি যখন সেই ফাইলটিতে লিখি তখন আমি যদি অংশটি এড়িয়ে যাই তবে এটি ঠিক আছে, এবং আমি এটি মুছতে পারি।
জেনি স্মিথ

4
আপনি কি দয়া করে আপনার ফ্লাশটি মোড়ানো এবং শেষ অবধি বন্ধ করতে পারেন? আমি জানি আপনি এটি করেছেন এবং এটি কার্যকর হয় না তবে এটি আপনার প্রশ্নের স্পষ্টতা যোগ করবে।
ভরাল

উত্তর:


100

জাভাতে আরও একটি বাগ। আমি খুব কমই তাদের খুঁজে পাই, আমার 10 বছরের কেরিয়ারে এটি আমার দ্বিতীয়। এটি আমার সমাধান, যেমন অন্যরা উল্লেখ করেছেন। আমি নেট ব্যবহার করা হয়েছে System.gc()। তবে এখানে, আমার ক্ষেত্রে এটি একেবারে গুরুত্বপূর্ণ। অদ্ভুত? হ্যাঁ!

finally
{
    try
    {
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        System.gc();
    }
    catch (IOException e)
    {
        logger.error(e.getMessage());
        e.printStackTrace();
    }
}

7
যদিও আমি এটিকে কোনও ধরণের স্ট্রিম দিয়ে খোলেনি (কেবল একটি করে new File(path)), আমি একই সমস্যার মুখোমুখি হয়েছি এবং এটি তৈরির System.gc()আগে যুক্ত delete()করেছিলাম!
ixM

4
অন্য বাগ কি?
বোগদান.মুষ্টিয়াটা

আমার জন্য না। যে ফাইলটি আমি মুছতে পারছি না তা হ'ল ডাউনলোড করা ফর্ম URL ফাইলের একটি জিপ ফাইল। সুন্দর জিনিসটি ডাউনলোড করা ফাইলটি মুছে ফেলা হবে। কোন ধারণা?
Andrea_86

আমার জন্য কাজ করেছেন। এবং @ অ্যানড্রেডি আমি কখনও আমার কোডে ফাইলচ্যানেল.ম্যাপ ব্যবহার করি নি। দেখে মনে হচ্ছে যে এই ত্রুটিটি অমীমাংসিত হিসাবে বন্ধ হয়ে গেছে যা আমাকে অবিশ্বাস্য করে তোলে কারণ System.gcকৌশলটি প্রতিবার কাজ করে।
অ্যাডাম

একক জিসি () নাও সাহায্য করতে পারেSystem.gc(); result = file.delete(); if (!result){ Thread.sleep(100); System.gc(); result = file.delete(); }
নোটস-জেজে

48

এটি কাজটি বেশ অদ্ভুত কৌশল ছিল। জিনিসটি যখন আমি আগে ফাইলটির বিষয়বস্তু পড়েছি, তখন আমি ব্যবহার করেছি BufferedReader। পড়ার পরে আমি বাফারটি বন্ধ করে দিয়েছি।

ইতিমধ্যে আমি স্যুইচ করেছি এবং এখন ব্যবহার করে সামগ্রীটি পড়ছি FileInputStream। পড়া শেষ করার পরেও আমি স্ট্রিমটি বন্ধ করে দিই। এবং এখন এটি কাজ করে।

সমস্যাটি হ'ল এর জন্য আমার কাছে ব্যাখ্যা নেই।

আমি জানি না BufferedReaderএবং FileOutputStreamবেমানান হতে পারি ।


4
আমি তর্ক করব এটি তখন একটি বাগ: java.sun.com/javase/6/docs/api/java/io/… এটি সেখানে বলেছে যে পদ্ধতিটি স্ট্রিমটি এবং এর সাথে সম্পর্কিত যে কোনও সংস্থান বন্ধ করে দেওয়া উচিত। আমি সাধারণত IOUtils.closeQuietly ব্যবহার করে উল্টো ক্রমের সমস্ত স্ট্রিমগুলি (সর্বশেষ উন্মুক্ত হওয়ার আগে বন্ধ হওয়া প্রথমে বন্ধ করতে চাই) তবে এটি ওভারকিলের প্রবণতা রাখে।
রবি ওয়ালাউ

4
আমার এই সঠিক সমস্যাটি হচ্ছিল আমি এবং আমি ভেবেছিলাম আমি পাগল হয়ে যাচ্ছি। সমাধানের জন্য ধন্যবাদ!
ইলেক্ট্রন_আহয়

14
এটি জেডিকে 7 নিয়ে 2011 এবং এখনও সমস্যাটি স্থির হয়নি। আমি এই সুতোটি পেয়েছি বলে আমি খুব আনন্দিত - আমি কী ভুল ছিল তা সহজেই অনুধাবন করতে পারি না ...
ডেভিড

আমি যে ফাইলটি পড়েছিলাম এবং বন্ধ করে দিয়ে মুছে ফেলার চেষ্টা করেছি তার সাথে আমার খুব বিরক্তিকর সমস্যা হয়েছিল। এখানে উল্লিখিত কিছুই সাহায্য করেনি। তারপরে এক ঘন্টা পরে আমি আবিষ্কার করেছি যে এটি কেবল ফাইলের অধিকার ছিল, যেহেতু ফাইলটি অন্য একজন ব্যবহারকারী তৈরি করেছেন :
ডি

অন্ধকারে কেবল ছুরিকাঘাত ... আপনি কি finalize()ক্লিনআপ নিশ্চিত করতে ফোন করতে পারেন ? নাকি সেট করেছেন to = null? দেখুন চূড়ান্ত এবং বর্জ্য সংগ্রহ অত্যাচার
jww

19

আমি এই সহজ জিনিসটি চেষ্টা করেছি এবং মনে হচ্ছে এটি কাজ করছে।

file.setWritable(true);
file.delete();

এটা আমার জন্য কাজ করে.

যদি এটি কাজ না করে তবে আপনার জাভা অ্যাপ্লিকেশনটি সুডো দিয়ে লিনাক্স এবং উইন্ডোতে প্রশাসক হিসাবে চালানোর চেষ্টা করুন। জাভা ফাইলের বৈশিষ্ট্য পরিবর্তন করার অধিকার আছে তা নিশ্চিত করার জন্য।


4
এই সমস্যার জন্য; সাধারণত লোকেরা রেফারেন্সগুলি নাল হিসাবে কল করা বা system.gc () কল করার বিষয়ে কথা বলে; সার্ভার পুনরায় চালু করার পরেও আমার জন্য ফাইলগুলি মুছে ফেলা হচ্ছে না !! কিন্তু file.setWritable (সত্য); সবেমাত্র কাজ করেছেন ..
দীপক সিংহল

6

কোনও ফাইল মুছে ফেলার / নাম পরিবর্তন করার চেষ্টা করার আগে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে সমস্ত পাঠক বা লেখক (উদাহরণস্বরূপ: BufferedReader/ InputStreamReader/ BufferedWriter) সঠিকভাবে বন্ধ রয়েছে closed

আপনি যখন কোনও ফাইল থেকে / আপনার ডেটা পড়ার / লেখার চেষ্টা করেন, তখন ফাইলটি প্রক্রিয়াটি ধারণ করে এবং প্রোগ্রামের সম্পাদনা শেষ না হওয়া অবধি প্রকাশিত হয় না। আপনি যদি প্রোগ্রামটি শেষ হওয়ার আগে মুছে ফেলা / পুনরায় নামকরণের ক্রিয়াকলাপ সম্পাদন করতে চান close()তবে java.io.*ক্লাসগুলির সাথে আসা পদ্ধতিটি আপনাকে অবশ্যই ব্যবহার করতে হবে ।


4
এটি শুধুমাত্র উইন্ডোজে সত্য। যে কোনও বাস্তব ও / এস-তে আপনি মুছে ফেলা ফাইলগুলি পুনরায় নামকরণ ও নামকরণ করতে পারেন।
আর্চি

3

জোন স্কিট যেমন মন্তব্য করেছেন, আপনার ফাইলটি সর্বদা বন্ধ রয়েছে তা নিশ্চিত করার জন্য অবশেষে {...} ব্লক করা উচিত। এবং, ই.প্রিন্টস্ট্যাকট্রেসের সাথে ব্যতিক্রমগুলি গিলে ফেলার পরিবর্তে কেবল পদ্ধতিটির স্বাক্ষরে ব্যতিক্রমটি ধরুন এবং যুক্ত করবেন না। যদি আপনি কোনও কারণে না পারেন তবে কমপক্ষে এটি করুন:

catch(IOException ex) {
    throw new RuntimeException("Error processing file XYZ", ex);
}

এখন, প্রশ্ন নম্বর # 2:

আপনি যদি এটি করেন তবে:

...
to.close();
System.out.println("Please delete the file and press <enter> afterwards!");
System.in.read();
...

আপনি কি ফাইলটি মুছতে পারবেন?

ফাইলগুলি বন্ধ হয়ে গেলে ফ্লাশ করা হয়। আমি IOUtils.closeQuietly (...) ব্যবহার করি, তাই ফাইলটি বন্ধ করার চেষ্টা করার আগে ফাইলের বিষয়বস্তুগুলি সেখানে রয়েছে তা নিশ্চিত করার জন্য আমি ফ্লাশ পদ্ধতিটি ব্যবহার করি (আইউইটিএলস.ক্লোজসিউটিলি ব্যতিক্রম ছুঁড়ে না ফেলে)। এটার মতো কিছু:

...
try {
    ...
    to.flush();
} catch(IOException ex) {
    throw new CannotProcessFileException("whatever", ex);
} finally {
    IOUtils.closeQuietly(to);
}

সুতরাং আমি জানি যে ফাইলের বিষয়বস্তু সেখানে আছে। যেহেতু সাধারণত আমার কাছে এটি গুরুত্বপূর্ণ হয় যে ফাইলটির বিষয়বস্তুগুলি লিখিত আছে এবং ফাইলটি বন্ধ করা যায় কিনা তা নয়, ফাইলটি বন্ধ ছিল কিনা তা আসলেই কিছু যায় আসে না। আপনার ক্ষেত্রে যেমন এটি গুরুত্বপূর্ণ, আমি নিজেই ফাইলটি বন্ধ করে দেওয়া এবং কোনও ব্যতিক্রম অনুযায়ী আচরণের পরামর্শ দেব।


আমি প্রথম জিনিসটি চেষ্টা করেছিলাম - শেষ অবধি আউটপুট স্ট্রিমটি বন্ধ করে দিচ্ছি। এবং এটি কাজ করে না। এর পরে যদি আমি পড়ার চেষ্টা করি তবে কী হয়েছিল তা হ'ল আমি একটি বার্তা পেয়েছি যে বলে স্ট্রিমটি বন্ধ রয়েছে। ফাইলআউটপুট রিডার দিয়ে ফাইলটি স্যুইচ করার সময় এবং পড়ার সময়, উপরে বর্ণিত "খারাপ" জিনিসগুলির কোনওটিই ঘটেনি।
জেনি স্মিথ

2

আপনার এই ফাইলটি মুছতে সক্ষম হবেন না এমন কোনও কারণ নেই। এই ফাইলটি কার হাতে রয়েছে তা আমি দেখতে চাই। ইউনিক্স / লিনাক্সে, ফাইলের মধ্যে কোন প্রক্রিয়াটির লক রয়েছে তা পরীক্ষা করতে আপনি lsof ইউটিলিটিটি ব্যবহার করতে পারেন। উইন্ডোগুলিতে, আপনি প্রক্রিয়া এক্সপ্লোরার ব্যবহার করতে পারেন।

Lsof এর জন্য, এটি বলার মতোই সহজ:

lsof /path/and/name/of/the/file

প্রক্রিয়া অন্বেষণকারীর জন্য আপনি সন্ধানী মেনুটি ব্যবহার করতে পারেন এবং হ্যান্ডেলটি দেখানোর জন্য ফাইলের নাম প্রবেশ করতে পারবেন যা আপনাকে ফাইলটি লক করার প্রক্রিয়াটি নির্দেশ করবে।

এখানে কিছু কোড রয়েছে যা আমার মনে হয় যা আপনার করা দরকার:

FileOutputStream to;

try {
    String file = "/tmp/will_delete.txt";
    to = new FileOutputStream(file );
    to.write(new String("blah blah").getBytes());
    to.flush();
    to.close();
    File f = new File(file);
    System.out.print(f.delete());
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

এটি ওএস এক্সে দুর্দান্ত কাজ করে I আমি উইন্ডোজ আর্ট ফাইল হ্যান্ডলিংয়ে কিছু অপ্রত্যাশিত আচরণ দেখে স্বীকারও করব।


4
উইন্ডোজের জন্য, আপনি এমএস থেকে ফ্রি প্রসেস এক্সপ্লোরারটি ডাউনলোড করতে পারেন: টেকনেট.মাইক্রোসফট /en-us/sysinternals/bb896653.aspx
আকারোকড

2

আপনি যদি এক্লিপস আইডিইতে কাজ করছেন তবে এর অর্থ এই হতে পারে যে আপনি অ্যাপ্লিকেশনটির আগের প্রবর্তনে ফাইলটি বন্ধ করেননি। যখন আমার কোনও ফাইল মুছতে চেষ্টা করার সময় একই ত্রুটি বার্তাটি ছিল তখনই এটি কারণ ছিল। দেখে মনে হচ্ছে, একটি অ্যাপ্লিকেশন সমাপ্তির পরে Eclipse IDE সমস্ত ফাইল বন্ধ করে না।


1

আশা করি এটি সাহায্য করবে। আমার জাভা কোডটি অন্য ফোল্ডারে সামগ্রীর অনুলিপি তৈরি করার পরে আমি আমার একই সমস্যাটি দেখতে পেয়েছি যেখানে আমি আমার ফাইলটি মুছতে পারি না। ব্যাপক গুগল করার পরে, আমি স্পষ্টভাবে প্রতিটি ফাইল অপারেশন সম্পর্কিত ভেরিয়েবলগুলি ঘোষণা করে এবং প্রতিটি ফাইল অপারেশন অবজেক্টের ক্লোজ () পদ্ধতিটি ডেকে এনে NULL এ সেট করেছিলাম। তারপরে, সিস্টেম.gc () নামে একটি ফাংশন রয়েছে যা আই / ও ম্যাপিং ফাইলটি সাফ করবে (আমি নিশ্চিত নই, আমি কেবল ওয়েবসাইটগুলিতে কী দেওয়া আছে তা বলি)।

এখানে আমার উদাহরণ কোড:

public void start() {
    File f = new File(this.archivePath + "\\" + this.currentFile.getName());
    this.Copy(this.currentFile, f);

    if(!this.currentFile.canWrite()){
        System.out.println("Write protected file " +
           this.currentFile.getAbsolutePath());

        return;
    }


    boolean ok = this.currentFile.delete();
    if(ok == false){
        System.out.println("Failed to remove " + this.currentFile.getAbsolutePath());
        return;
    }
}

private void Copy(File source, File dest) throws IOException {
    FileInputStream fin;
    FileOutputStream fout;
    FileChannel cin = null, cout = null;
    try {
        fin = new FileInputStream(source);
        cin = fin.getChannel();
        fout = new FileOutputStream(dest);
        cout = fout.getChannel();

        long size = cin.size();
        MappedByteBuffer buf = cin.map(FileChannel.MapMode.READ_ONLY, 0, size);

        cout.write(buf);
        buf.clear();
        buf = null;

        cin.close();
        cin = null;

        fin.close();
        fin = null;

        cout.close();
        cout = null;

        fout.close();
        fout = null;

        System.gc();

    } catch (Exception e){
        this.message = e.getMessage();
        e.printStackTrace();
    }
}

1

উত্তরটি যখন আপনি ফাইলটি লোড করেন তখন আপনার "কোড" পদ্ধতি প্রয়োগ করতে হবে, কোডের যে কোনও লাইনে, আমার সাথে কাজ করে


0

রুবিতে একবার সমস্যা হয়েছিল যেখানে উইন্ডোতে থাকা ফাইলগুলিকে "ফিসাইঙ্ক" দরকার ছিল যাতে ফাইলটি লেখার পরে এবং এটি বন্ধ করে পুনরায় পড়তে সক্ষম হয়। সম্ভবত এটি একটি অনুরূপ প্রকাশ (এবং যদি তাই হয় তবে আমি মনে করি একটি উইন্ডোজ বাগ সত্যই)।


0

এখানে তালিকাবদ্ধ সমাধানগুলির মধ্যে কোনওটিই আমার পরিস্থিতিতে কাজ করে নি। আমার সমাধানটি ছিল কিছুক্ষণ লুপ ব্যবহার করা, সুরক্ষার জন্য 5 সেকেন্ডের (কনফিগারযোগ্য) সীমা সহ ফাইলটি মুছে ফেলার চেষ্টা করা।

File f = new File("/path/to/file");

int limit = 20; //Only try for 5 seconds, for safety
while(!f.delete() && limit > 0){
    synchronized(this){
        try {
            this.wait(250); //Wait for 250 milliseconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    limit--;
}

উপরের লুপটি ব্যবহার করে কোনও ম্যানুয়াল আবর্জনা সংগ্রহ বা স্ট্রিমটি নালায় সেট করা না করেই কাজ করা হয়েছে etc.


আপনি কি ব্যবহার করেন? আপনার যদি স্ট্রিমে অ্যাক্সেস থাকতে পারে তবে এগুলি বন্ধ করুন, এটি কার্যকর হবে। তবে যদি ফাইলটি "ইতিমধ্যে" লক করা থাকে তবে আপনার সমস্যা আছে।
মার্কোলপস

4
কোনও ফাইল মুছতে আপনার কোডে লুপিং কোনও দুর্দান্ত ধারণা নয়। কেন শুধু কাজ করে না জিসি () বিকল্পটি?
ভরাল

@ ভারাল নোটিশ আমি উপরে উল্লেখ করেছি যে অন্য কোনও সমাধান (জিসি () সহ) আমার বিশেষ ক্ষেত্রে কার্যকর হয়নি। যদিও আমি কিছুক্ষণ লুপ ব্যবহার করা আদর্শ নয় তবে এটি নির্দিষ্ট পরিস্থিতিতে উপযুক্ত সমাধান হতে পারে। উপরের কোডে একটি অতিরিক্ত চেক যুক্ত করা, যেমন একটি টাইমআউট বা সর্বাধিক পুনরাবৃত্তির পরিবর্তনশীল, সময় লুপটিকে আরও নিরাপদ করার পক্ষে একটি ভাল উপায়।
এটেক

@Etech আপনার ফাইলটি যদি কখনও না থাকে তবে আপনি সবেমাত্র একটি অসীম লুপ তৈরি করেছেন।
ভর্তা

0

সমস্যাটি হতে পারে যে ফাইলটি এখনও কোনও প্রোগ্রামের দ্বারা খোলা এবং লক হিসাবে দেখা যায়; অথবা হতে পারে এটি আপনার প্রোগ্রামের একটি উপাদান যা এটি চালু হয়েছিল, সুতরাং আপনাকে dispose()সমস্যাটি সমাধানের জন্য পদ্ধতিটি ব্যবহার করা নিশ্চিত করতে হবে ensure অর্থাত্JFrame frame; .... frame.dispose();


0

আপনাকে সমস্ত স্ট্রিম বন্ধ করতে হবে বা রিসোর্স ব্লক ব্যবহার করে চেষ্টা করতে হবে

static public String head(File file) throws FileNotFoundException, UnsupportedEncodingException, IOException
{
    final String readLine;
    try (FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            LineNumberReader lnr = new LineNumberReader(isr))
    {
        readLine = lnr.readLine();
    }
    return readLine;
}

0

যদি ফাইল.ডিলেট () মিথ্যা প্রেরণ করে থাকে তবে বেশিরভাগ ক্ষেত্রে আপনার বাফারড্রেডার হ্যান্ডেলটি বন্ধ করা হবে না। কেবল কাছেই এবং এটি আমার পক্ষে স্বাভাবিকভাবে কাজ করে বলে মনে হচ্ছে।


0

উইন্ডোজেও আমার একই সমস্যা ছিল। আমি স্কেল লাইনে ফাইলটি লাইনে পড়তাম

Source.fromFile(path).getLines()

এখন পুরোটা দিয়ে পড়লাম

import org.apache.commons.io.FileUtils._

// encoding is null for platform default
val content=readFileToString(new File(path),null.asInstanceOf[String])

যা এখন পড়ার পরে ফাইলটি সঠিকভাবে বন্ধ করে দেয়

new File(path).delete

কাজ করে।


0

Eclipse / NetBeans এর জন্য

আপনার আইডিই পুনরায় চালু করুন এবং আপনার কোডটি আবার চালান এটি এক ঘন্টা দীর্ঘ সংগ্রামের পরে আমার পক্ষে কেবল কৌশল।

আমার কোডটি এখানে:

File file = new File("file-path");
if(file.exists()){
  if(file.delete()){
     System.out.println("Delete");
  }
  else{

       System.out.println("not delete");
  }
}

আউটপুট:

মুছে ফেলা


0

এটি ঘটতে পারে এমন আরেকটি কোণার ক্ষেত্রে: আপনি যদি একটি 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();

// open a Jar entry in auto-closing manner
try (InputStream i = c.getInputStream()) {

    // just read some stuff; for demonstration purposes only
    byte[] first16 = new byte[16];
    i.read(first16);
    System.out.println(new String(first16));
}

// ...

// i is now closed, so we should be good to delete the jar; but...
System.out.println(f.delete());     // says false!

কারণটি হ'ল জাভাটির অভ্যন্তরীণ জেআর ফাইল হ্যান্ডলিং লজিক, JarFileএন্ট্রিগুলিতে ক্যাশে থাকে s

// inner class of `JarURLConnection` that wraps the actual stream returned by `getInputStream()`

class JarURLInputStream extends FilterInputStream {
    JarURLInputStream(InputStream var2) {
        super(var2);
    }

    public void close() throws IOException {
        try {
            super.close();
        } finally {

            // if `getUseCaches()` is set, `jarFile` won't get closed!

            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();
    
    // for only c
    c.setUseCaches(false);
    
    // globally; for some reason this method is not static,
    // so we still need to access it through a URLConnection instance :(
    c.setDefaultUseCaches(false);
    
  • [হ্যাক সতর্কতা!] আপনি JarFileযখন এটি সম্পন্ন করেন তখন আপনি ম্যানুয়ালি ক্যাশে থেকে মুছে ফেলতে পারেন । ক্যাশে পরিচালকটি sun.net.www.protocol.jar.JarFileFactoryপ্যাকেজ-ব্যক্তিগত, তবে কিছু প্রতিবিম্ব যাদু আপনার পক্ষে কাজটি সম্পন্ন করতে পারে:

    class JarBridge {
    
        static void closeJar(URL url) throws Exception {
    
            // JarFileFactory jarFactory = JarFileFactory.getInstance();
            Class<?> jarFactoryClazz = Class.forName("sun.net.www.protocol.jar.JarFileFactory");
            Method getInstance = jarFactoryClazz.getMethod("getInstance");
            getInstance.setAccessible(true);
            Object jarFactory = getInstance.invoke(jarFactoryClazz);
    
            // JarFile jarFile = jarFactory.get(url);
            Method get = jarFactoryClazz.getMethod("get", URL.class);
            get.setAccessible(true);
            Object jarFile = get.invoke(jarFactory, url);
    
            // jarFactory.close(jarFile);
            Method close = jarFactoryClazz.getMethod("close", JarFile.class);
            close.setAccessible(true);
            //noinspection JavaReflectionInvocation
            close.invoke(jarFactory, jarFile);
    
            // jarFile.close();
            ((JarFile) jarFile).close();
        }
    }
    
    // and in your code:
    
    // i is now closed, so we should be good to delete the jar
    JarBridge.closeJar(j);
    System.out.println(f.delete());     // says true, phew.
    

দয়া করে নোট করুন: এগুলি সমস্ত জাভা 8 কোডবাসের উপর ভিত্তি করে ( 1.8.0_144); তারা অন্যান্য / পরবর্তী সংস্করণগুলির সাথে কাজ নাও করতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.