2015-09-15 8 views
5

एक नया, अद्वितीय फ़ाइल नाम बनाने के लिए, मैं निम्नलिखित कोड का उपयोग करें:बनाना नई फ़ाइलें समवर्ती

File file = new File(name); 
synchronized (sync) { 
    int cnt = 0; 
    while (file.exists()) { 
     file = new File(name + " (" + (cnt++) + ")"); 
    } 
    file.createNewFile(); 
} 

इसके बाद, मैं फ़ाइल का उपयोग करें और इसे हटा दें। file.createNewFile() पर अपवाद जब मैं एक बहु स्थिति में ऐसा करते हैं, मैं कभी कभी मिलता है:

final int runs = 1000; 
final int threads = 5; 
final String name = "c:\\temp\\files\\file"; 
final byte[] bytes = getSomeBytes(); 
final Object sync = new Object(); 

ExecutorService exec = Executors.newFixedThreadPool(threads); 
for (int thread = 0; thread < threads; thread++) { 
    final String id = "Runnable " + thread; 
    exec.execute(new Runnable() { 
     public void run() { 
      for (int i = 0; i < runs; i++) { 
       try { 
        File file = new File(name); 
        synchronized (sync) { 
         int cnt = 0; 
         while (file.exists()) { 
          file = new File(name + " (" + (cnt++) + ")"); 
         } 
         file.createNewFile(); 
        } 

        Files.write(file.toPath(), bytes); 
        file.delete(); 
       } catch (Exception ex) { 
        System.err.println(id + ": exception after " + i 
          + " runs: " + ex.getMessage()); 
        ex.printStackTrace(); 
        return; 
       } 
      } 
      System.out.println(id + " finished fine"); 
     } 
    }); 
} 
exec.shutdown(); 
while (!exec.awaitTermination(1, TimeUnit.SECONDS)); 

विधि getSomeBytes() बस उत्पन्न करता है:

java.io.IOException: Access is denied 
    at java.io.WinNTFileSystem.createFileExclusively(Native Method) 
    at java.io.File.createNewFile(File.java:1012) 

निम्नलिखित कोड समस्या reproduces (समय की सबसे) बाइट्स की मात्रा, वास्तविक सामग्री महत्वपूर्ण नहीं है:

byte[] getSomeBytes() throws UnsupportedEncodingException, 
     IOException { 
    byte[] alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ1234567890\r\n" 
      .getBytes("UTF-8"); 
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { 
     for (int i = 0; i < 100000; i++) { 
      baos.write(alphabet); 
     } 
     baos.flush(); 
     return baos.toByteArray(); 
    } 
} 

जब मैं इस कोड को निष्पादित करता हूं, तो यह कभी-कभी तों अच्छी तरह से चला जाता है, लेकिन समय की सबसे, यह उदाहरण के लिए नीचे दिए गए आउटपुट की तरह कुछ अपवाद उत्पन्न करता है:

Runnable 1: exception after 235 runs: Access is denied 
java.io.IOException: Access is denied 
    at java.io.WinNTFileSystem.createFileExclusively(Native Method) 
    at java.io.File.createNewFile(File.java:1012) 
    at test.CreateFilesTest$1.run(CreateFilesTest.java:36) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 
Runnable 4: exception after 316 runs: Access is denied 
java.io.IOException: Access is denied 
    at java.io.WinNTFileSystem.createFileExclusively(Native Method) 
    at java.io.File.createNewFile(File.java:1012) 
    at test.CreateFilesTest$1.run(CreateFilesTest.java:36) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 
Runnable 2: exception after 327 runs: Access is denied 
java.io.IOException: Access is denied 
    at java.io.WinNTFileSystem.createFileExclusively(Native Method) 
    at java.io.File.createNewFile(File.java:1012) 
    at test.CreateFilesTest$1.run(CreateFilesTest.java:36) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 
Runnable 3 finished fine 
Runnable 0 finished fine 

कोई भी विचार? मैंने विंडोज 8 मशीन पर जावा 1.7.0_45 और 1.8.0_31 के साथ एक ही परिणाम दोनों परीक्षण किए हैं।

यह सुनिश्चित नहीं है कि समस्या this question में समान है, लेकिन यह हो सकती है। एक ही प्रक्रिया में कई धागे का उपयोग करना मेरी राय के लिए समस्या का हिस्सा है, लेकिन मैं इसके बारे में निश्चित नहीं हो सकता, हालांकि यह तेजी से पुन: उत्पन्न होता है।

+2

'File.createTempFile() 'यहां एक क्लीनर दृष्टिकोण हो सकता है, इस पर ध्यान दिए बिना कि फ़ाइल वास्तव में अस्थायी होने का इरादा है या नहीं। – Sneftel

+0

@Sneftel: हालांकि, मैं सहमत हूं कि फाइल का नाम कोई फर्क नहीं पड़ता है, इसलिए मैं फ़ाइल.क्रेटटेम्फाइल का उपयोग नहीं कर सकता – Steven

उत्तर

5

कि लगता है विंडोज मंच createNewFile पर बेतरतीब ढंग से विफल हो सकता है अगर एक ही नाम के साथ फाइल अभी भी एकल पिरोया आवेदन पर हटाया गया था। विवरण के लिए this question देखें। अपनी समस्या को ठीक करने के लिए, आप से createNewFile से अनदेखा करने और जारी रखने का प्रयास कर सकते हैं। कुछ इस तरह:

synchronized (sync) { 
    int cnt = 0; 
    while (true) { 
     try { 
      if(file.createNewFile()) 
       break; 
     } catch (IOException e) { 
      // continue; 
     } 
     file = new File(name + " (" + (cnt++) + ")"); 
    } 
} 

ध्यान दें कि आप के रूप में createNewFile() सुविधा देता है कि क्या यह फ़ाइल सफलतापूर्वक बनाया file.exists() कॉल की जांच की जरूरत नहीं है।

ध्यान दें कि यदि आप अपनी सभी अस्थायी फ़ाइलों को नियंत्रित करते हैं और सटीक फ़ाइल नाम की परवाह नहीं करते हैं, तो आमतौर पर लॉक करने की कोई आवश्यकता नहीं होती है। आप फ़ाइल नाम पर अगली फ़ाइल नाम प्राप्त करने या थ्रेड आईडी जोड़ने के लिए वैश्विक AtomicLong का उपयोग कर सकते हैं।

+0

चूंकि समस्या शायद बाहरी कारक के कारण होती है, मुझे लगता है कि मैं इस मामले में समस्या से खुद को पकड़ने/पकड़ने वाला हूं – Steven

0

आपका लूप असफल-सुरक्षित नहीं है। एक समय-खिड़की की समस्या है। इसे और अधिक इस तरह होना चाहिए:

while (!file.createNewFile()) { 
     file = new File(name + " (" + (cnt++) + ")"); 
    } 
+1

क्या आप इस सिंक्रनाइज़ किए गए सेक्शन में "टाइमिंग-विंडो" पर थोड़ा और वर्बोज़ बन सकते हैं? इसके अलावा आपका निश्चित कोड ओपीएस कोड के समान ही विफल रहता है। –

+0

@TagirValeev 'मौजूद()' और 'createNewFile()' के बीच एक समय खिड़की है जिसके दौरान फ़ाइल किसी अन्य थ्रेड द्वारा बनाई जा सकती है। 'CreateNewFile()' के परिणाम की जांच करने में विफलता भी है। यदि मैंने यहां पोस्ट की गई दो-पंक्ति लूप विफल हो गई है, तो इस विधि के साथ एक प्लेटफ़ॉर्म समस्या होनी चाहिए जो विज्ञापन के रूप में काम नहीं कर रही है। वास्तव में कैच ब्लॉक की तुलना में इस लूप और आपके उत्तर में कोड के बीच कोई अंतर नहीं है। आप उसे कैसे समझायेंगे? – EJP

+1

कृपया ध्यान दें कि सभी धागे एक ही मॉनिटर पर सिंक्रनाइज़ किए जाते हैं, इस प्रकार कोई अन्य धागा ऐसा नहीं कर सकता है। –

संबंधित मुद्दे