2016-09-02 5 views
6

मैंने देखा है कि java.io और java.nio यादृच्छिक एक्सेस फ़ाइलों के कार्यान्वयन FileLocks के संबंध में थोड़ा अलग हैं।यादृच्छिक अभिगम फ़ाइल फ़ाइल लॉक: java.io बनाम java.nio

ऐसा लगता है कि (विंडोज़ पर) java.io आपको एक अनिवार्य फ़ाइल लॉक देता है और java.nio आपको क्रमशः अनुरोध करने पर सलाहकार फ़ाइल लॉक देता है। एक अनिवार्य फ़ाइल लॉक का अर्थ है कि लॉक सभी प्रक्रियाओं के लिए है और एक सलाहकार अच्छी प्रक्रियाओं के लिए रखता है जो समान लॉकिंग प्रोटोकॉल का पालन करते हैं।

यदि मैं निम्नलिखित उदाहरण चलाता हूं, तो मैं *.nio फ़ाइल मैन्युअल रूप से हटा सकता हूं, जबकि *.io फ़ाइल हटाई जाने से इंकार कर दिया जाता है।

import java.io.*; 
import java.lang.management.ManagementFactory; 
import java.nio.*; 
import java.nio.channels.*; 
import java.nio.file.*; 

public class NioIoLock { 

    public static void main(String[] args) throws IOException, InterruptedException { 
     String workDir = System.getProperty("user.dir"); 

     FileChannel channelIo, channelNio; 
     FileLock lockIo, lockNio; 

     // use io 
     { 
      String fileName = workDir 
        + File.separator 
        + ManagementFactory.getRuntimeMXBean().getName() 
        + ".io"; 
      File lockFile = new File(fileName); 
      lockFile.deleteOnExit(); 
      RandomAccessFile file = new RandomAccessFile(lockFile, "rw");    

      channelIo = file.getChannel(); 
      lockIo = channelIo.tryLock(); 
      if (lockIo != null) {     
       channelIo.write(ByteBuffer.wrap("foobar".getBytes("UTF-8"))); 
      } 

     } 

     // use nio 
     { 
      Path workDirPath = Paths.get(workDir); 
      Path file = workDirPath.resolve(
        Paths.get(ManagementFactory.getRuntimeMXBean().getName() + ".nio")); 

      // open/create test file 
      channelNio = FileChannel.open(
        file, StandardOpenOption.READ, StandardOpenOption.WRITE, 
        StandardOpenOption.CREATE, StandardOpenOption.DELETE_ON_CLOSE); 

      // lock file 
      lockNio = channelNio.tryLock(); 
      if (lockNio != null) { 
       channelNio.write(ByteBuffer.wrap("foobar".getBytes("UTF-8"))); 
      } 

     } 

     // do not release locks for some time 
     Thread.sleep(10000); 

     // release io lock and channel 
     if (lockIo != null && lockIo.isValid()) { 
      lockIo.release(); 
     } 
     channelIo.close(); 

     // release nio lock and channel 
     if (lockNio != null && lockNio.isValid()) { 
      lockNio.release(); 
     } 
     channelNio.close(); 
    } 

} 

क्या इसका कोई कारण है? क्या इन दोनों को विकल्प के रूप में भी माना जाता है या क्या वे अनिश्चित काल तक सह-अस्तित्व में हैं?

+0

एनआईओ संस्करण में 'SYNC, DSYNC' जोड़ने से कोई फर्क पड़ता है? तो यह एक प्रदर्शन विचार किया गया होगा। –

+0

'SYNC, DSYNC' जोड़ने से कोई फर्क नहीं पड़ता – starikoff

उत्तर

6

टीएल; डीआर: यह ताले के बारे में नहीं है, यह फाइलों को खोले जाने के तरीके के बारे में है। io में आप जो देखते हैं वह विंडोज 2000 से पहले सबसे अच्छा विंडोज़ कर सकता है, और ऐसा तब भी हुआ जब फाइलें केवल पढ़ने के लिए खोली गईं - उस फ़ाइल को हटाना संभव नहीं था। nio में आप जो देखते हैं वह एक सुधार है जो विंडोज 2000 के बाद से एक नई क्षमता का उपयोग करता है, लेकिन यदि आप चुनते हैं तो भी nio में आपका पुराना व्यवहार हो सकता है। यह निर्णय लिया गया कि io में उस क्षमता को बंद न करें।

पूर्ण कहानी: मैंने लॉकिंग से संबंधित सभी कोड हटा दिए हैं (नीचे देखें) साथ ही फाइलों को लिखना और यह आपके कोड के समान ही काम करता है; हालांकि, मैंने यह भी पाया कि यदि आप "nio" चैनल खोलते समय ExtendedOpenOption.NOSHARE_DELETE निर्दिष्ट करते हैं, तो जब आप दो फ़ाइलों में से किसी एक को हटाने का प्रयास करते हैं तो व्यवहार समान होता है (कोड में इसे असम्बद्ध करें और प्रयास करें)। this question भी मिला और इसमें कुछ स्पष्टीकरण है, यकीन नहीं है कि यह मदद करेगा या नहीं।

import java.io.*; 
import java.lang.management.ManagementFactory; 
import java.nio.*; 
import java.nio.channels.*; 
import java.nio.file.*; 

public class NioIoLock { 

    public static void main(String[] args) 
      throws IOException, InterruptedException { 
     String workDir = System.getProperty("user.dir"); 

     FileChannel channelIo, channelNio; 
     FileLock lockIo, lockNio; 

     // use io 
     { 
      String fileName = workDir + File.separator 
       + ManagementFactory.getRuntimeMXBean().getName() + ".io"; 
      File lockFile = new File(fileName); 
      lockFile.deleteOnExit(); 
      RandomAccessFile file = new RandomAccessFile(lockFile, "rw"); 
      channelIo = file.getChannel(); 
     } 

     // use nio 
     { 
      Path workDirPath = Paths.get(workDir); 
      Path file = workDirPath.resolve(Paths 
       .get(ManagementFactory.getRuntimeMXBean().getName() + ".nio")); 

      // open/create test file 
      channelNio = FileChannel.open(file, StandardOpenOption.READ, 
       StandardOpenOption.WRITE, StandardOpenOption.CREATE, 
       StandardOpenOption.DELETE_ON_CLOSE 
       /*, com.sun.nio.file.ExtendedOpenOption.NOSHARE_DELETE*/); 
     } 

     // do not release locks for some time 
     Thread.sleep(10000); 
    } 
} 

अद्यतन 1: वास्तव में, मैं अभी भी इस के पीछे तर्क पता नहीं है, लेकिन यांत्रिकी स्पष्ट कर रहे हैं:

FD 
winFileHandleOpen(JNIEnv *env, jstring path, int flags) 
{ 
    ... 
    const DWORD sharing = 
     FILE_SHARE_READ | FILE_SHARE_WRITE; 
    ... // "sharing" not updated anymore 
    h = CreateFileW(
     pathbuf,   /* Wide char path name */ 
     access,    /* Read and/or write permission */ 
     sharing,   /* File sharing flags */ 
     NULL,    /* Security attributes */ 
     disposition,  /* creation disposition */ 
     flagsAndAttributes, /* flags and attributes */ 
     NULL); 
    ... 
} 
: RandomAccessFile निर्माता अंततः io_util_md.c से method winFileHandleOpen से निम्न मूल कोड कॉल

तो, FILE_SHARE_DELETE ध्वज सेट नहीं है और आप इसे सेट करने के लिए कुछ भी नहीं कर सकते हैं।

private static FileDescriptor open(String pathForWindows, 
             String pathToCheck, 
             Flags flags, 
             long pSecurityDescriptor) 
     throws WindowsException 
    { 
     ... 
     int dwShareMode = 0; 
     if (flags.shareRead) 
      dwShareMode |= FILE_SHARE_READ; 
     if (flags.shareWrite) 
      dwShareMode |= FILE_SHARE_WRITE; 
     if (flags.shareDelete) 
      dwShareMode |= FILE_SHARE_DELETE; 
     ... 
     // open file 
     long handle = CreateFile(pathForWindows, 
           dwDesiredAccess, 
           dwShareMode, 
           pSecurityDescriptor, 
           dwCreationDisposition, 
           dwFlagsAndAttributes); 
     ... 
    } 

अद्यतन 2: दूसरी ओर, बुला java.nio.channels.FileChannel.open(Path, OpenOption...)eventually खाते में इस ध्वज लेताJDK-6607535 से:

सुझाव साझा करने मोड बदलने के लिए यह बहुत अच्छा होगा RFE 6357433. है ऐसा करने के लिए, लेकिन यह मौजूदा अनुप्रयोगों को तोड़ सकता है (चूंकि वर्तमान व्यवहार jdk1.0 के बाद से मौजूद है)। विंडोज़ मुद्दों के आसपास काम करने के लिए RandomAccessFile को एक विशेष मोड जोड़ना शायद सही दृष्टिकोण नहीं है। साथ ही, कुछ सुझाव भी हैं कि यह फाइल मैपिंग वाली फ़ाइलों को हटाने के मुद्दे से मदद कर सकता है। ऐसा नहीं है, क्योंकि फ़ाइल मैपिंग अभी भी एक फ़ाइल को हटाए जाने से रोकती है। वैसे भी, jdk7 के लिए हम एक नई फाइल सिस्टम एपीआई पर काम कर रहे हैं जो यहां कुछ आवश्यकताओं को संबोधित करेगा। विंडोज कार्यान्वयन सही चीज करता है ताकि खुले फाइलों को हटाया जा सके।

भी देखें JDK-6357433 वहाँ से संदर्भित:

एक ग्राहक java.net मंचों कि विंडोज पर कोई फ़ाइल खोलने एक FileInputStream का उपयोग करने पर बताया गया है फ़ाइल को नष्ट करने में असमर्थ होने के लिए अन्य प्रक्रियाओं का कारण बनता है। यह वांछित व्यवहार है क्योंकि कोड वर्तमान में लिखा गया है, क्योंकि फ़ाइल के उद्घाटन के दौरान निर्दिष्ट साझाकरण झंडे FILE_SHARE_READ और FILE_SHARE_WRITE हैं। Io_util_md.c देखें, फ़ाइल खोलें। हालांकि, विंडोज 2000 एक नया ध्वज, FILE_SHARE_DELETE प्रदान करता है, जो फ़ाइल को तब भी हटाने की अनुमति देता है जब यह अभी भी खुला रहता है।

और अंत में

कार्यों के बीच

jdk7 के लिए, वैकल्पिक हल नई फ़ाइल सिस्टम API का प्रयोग है। तो नए FileInputStream (f) और नए FileOutputStream (f) के बजाय, f.toPath() का उपयोग करें। NewInputStream() और f.toPath()। NewOutputStream()।

+1

ग्रेट विश्लेषण। मैंने कभी भी ताले को नहीं माना क्योंकि यह कारण नहीं है। – predi

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