2011-05-04 2 views
9

मैं यह पता लगाने के लिए एक कुशल तरीका ढूंढ रहा हूं कि दो java.io.File एक ही भौतिक फ़ाइल का संदर्भ लें। दिए गए वस्तु के साथ समानता के लिएजावा, लिनक्स: यह पता लगाने के लिए कि क्या दो java.io.Files एक ही भौतिक फ़ाइल को संदर्भित करते हैं

टेस्ट इस सार पथ नाम: डॉक्स के अनुसार, File.equals() काम करना चाहिए। सत्य लौटाता है अगर केवल तर्क शून्य नहीं है और अमूर्त पथनाम है जो को इस फ़ाइल या निर्देशिका को सार पथनाम के रूप में दर्शाता है।

हालांकि

, एक FAT32 विभाजन (वास्तव में एक TrueCrypt कंटेनर), जिस पर/मीडिया/truecrypt1 घुड़सवार दिया:

new File("/media/truecrypt1/File").equals(new File("/media/truecrypt1/file")) == false 

क्या आप कहेंगे कि इस विनिर्देशों के अनुरूप? और इस मामले में, उस समस्या के आसपास कैसे काम करें?

अपडेट: जावा 7 के लिए टिप्पणी करने वालों के लिए धन्यवाद, मुझे java.io.Files.isSameFile() मिल गया है जो मेरे लिए काम करता है।

+1

मुझे यकीन नहीं है (यही कारण है कि मैं इसे एक टिप्पणी के रूप में पोस्ट करता हूं), लेकिन शायद ['getCanonicalFile()'] (http://download.oracle.com/javase/6/docs/api/java/io /File.html#getCanonicalFile()) मदद करता है। –

+1

यूनिक्स पर, ये फ़ाइलें समान नहीं हैं। ;) –

+0

@ पीटर: सामान्य रूप से नहीं, लेकिन यदि '/ media/truecrypt1' एक एफएटी फाइल सिस्टम है, तो वे (डिफ़ॉल्ट माउंट विकल्प दिए गए) सटीक उसी सामग्री का संदर्भ लेंगे। –

उत्तर

14

@ में जवाब जोआचिम की टिप्पणी सामान्य रूप से सही है। यह निर्धारित करने का तरीका है कि दो File ऑब्जेक्ट एक ही ओएस फ़ाइल का संदर्भ है getCanonicalFile() या getCanonicalPath() प्राप्त करने के लिए। जावाडोक इस कहते हैं:

"एक विहित पथ दोनों पूर्ण और अद्वितीय है [...] हर पथ नाम है कि किसी मौजूदा फ़ाइल को दर्शाता है या निर्देशिका एक अनूठा विहित प्रपत्र है।।"

तो निम्नलिखित चाहिए काम:।

File f1 = new File("/media/truecrypt1/File"); // different capitalization ... 
File f2 = new File("/media/truecrypt1/file"); // ... but same OS file (on Windows) 
if (f1.getCanonicalPath().equals(f2.getCanonicalPath())) { 
    System.out.println("Files are equal ... no kittens need to die."); 
} 

हालांकि, यह प्रकट होता यदि आप एक FAT32 फाइल सिस्टम यूनिक्स/लिनक्स पर रखा देख रहे हैं कि AFAIK, जावा नहीं है जानते हैं कि यह हो रहा है, और केवल फाइल नामों के लिए सामान्य यूनिक्स/लिनक्स नियम लागू कर रहा है ... जो इस परिदृश्य में गलत जवाब देता है।

यदि यह है कि क्या वास्तव में हो रहा है, मुझे नहीं लगता कि शुद्ध हालांकि जावा 6. में एक विश्वसनीय समाधान है,

  • आप कुछ बालों JNI सामान कर सकता है; जैसे फ़ाइल डिस्क्रिप्टर नंबर प्राप्त करें और उसके बाद देशी कोड में, दो फ़ाइलों के डिवाइस और इनोड संख्याओं को पकड़ने और उनसे तुलना करने के लिए fstat(2) सिस्टम कॉल का उपयोग करें।

  • जावा 7 java.nio.file.Path.equals(Object) लगता है कि यह अगर आप पहले सिमलिंक हल करने रास्तों पर resolve() फोन सही जवाब दे सकता है। (यह है कि क्या लिनक्स पर प्रत्येक घुड़सवार फाइल सिस्टम एक अलग FileSystem वस्तु के अनुरूप होगा जावाडोक से थोड़ी स्पष्ट नहीं है।)

  • जावा 7 ट्यूटोरियल देखकर this section अगर दो Path वस्तुओं एक ही फाइल के लिए कर रहे हैं ... जो का उपयोग कर java.nio.file.Files.isSameFile(Path, Path)


क्या आप कहेंगे कि इस विनिर्देशों के अनुरूप सिफारिश की गई है?

नहीं और हाँ।

  • इस अर्थ में कि getCanonicalPath() विधि प्रत्येक मौजूदा OS फ़ाइल ... है जो आप जावाडोक पढ़ने से उम्मीद थी के लिए एक ही मूल्य नहीं लौटा रहा है में नहीं।

  • हाँ तकनीकी ज्ञान में जावा कोडबेस (जावाडॉक नहीं) अंतिम विनिर्देश है ... दोनों सिद्धांत और अभ्यास में।

+0

मैं आखिरी वस्तु से असहमत हूं: अगर मैंने इस कथन को साहित्यिक लिया है, तो जावा में कोई बग * नहीं हो सकता है, क्योंकि प्रत्येक बग विनिर्देश का हिस्सा होगा। यह अतीत में गलत साबित हुआ है ;-) –

+0

लेकिन बिंदु है ... भले ही यह एक बग है, सूर्य/ओरेकल अक्सर "ठीक नहीं होगा" कहेंगे ... और जावडोक को भी सही नहीं करेगा। आईआईआरसी, जब टीकेसी अनुरूपता के लिए नियम का परीक्षण कर रहा है वह करना है जो सूर्य जेआरई करता है ... जवाडोक क्या नहीं कहता है। असल में, पुस्तकालय कोड अनुरूपता के लिए स्वर्ण मानक है, कोई दस्तावेज नहीं। इससे कक्षा पुस्तकालयों को फिर से लागू करने की कोशिश करने वाले किसी भी व्यक्ति के लिए यह अंतिम विनिर्देश बनता है ... क्योंकि जीएनयू क्लासपाथ और अपाचे हार्मनी ने किया है। –

+0

रवैया कि एक संदर्भ निहितार्थ सही प्रभाव है, वास्तव में जब एक दस्तावेज का नमूना मौजूद होता है (जो संदर्भ प्रत्यारोपण का विरोध करता है), तो यह एक बहुत ही गलत रवैया है। यह एक व्यावहारिक दृष्टिकोण हो सकता है, लेकिन एक विशिष्टता का स्वास्थ्य केवल उतना ही अच्छा है जितना आसानी से शामिल विभिन्न पार्टियों द्वारा spec के अनुरूप है। – Chii

1

* निक्स सिस्टम पर, का महत्व है। fileFile या fiLe जैसा नहीं है।

+0

मैं एक FAT32 विभाजन पर हूं, यहां 'फ़ाइल' और 'फ़ाइल' समान हैं। – mstrap

+0

अच्छी तरह से अगर ओएस मामले को मानता है, तो मुझे लगता है कि जावा सिस्टम को यह जानने का कोई तरीका नहीं है कि वे फाइल सिस्टम के बावजूद समान हैं। –

1

equals() की एपीआई दस्तावेज़ कहते हैं (सही अपने उद्धरण के बाद):

यूनिक्स सिस्टम पर वर्णमाला मामले pathnames की तुलना में महत्वपूर्ण है; पर माइक्रोसॉफ्ट विंडोज सिस्टम यह नहीं है।

1

आप

ls -i /fullpath/File # extract the inode number. 
df /fullpath/File # extract the "Mounted on" field. 

की Runtime.exec() की कोशिश कर सकते माउंट बिंदु और "आईनोड" नंबर एक ही है, तो वे एक ही फाइल कर रहे हैं कि क्या आप सांकेतिक लिंक या केस-संवेदी है फाइल सिस्टम

या यहां तक ​​कि

bash test "file1" -ef "file2" 

File1 और करें 2 एक ही डिवाइस और आईनोड संख्या

+1

मुझे लगता है कि हम एक ही पंक्ति के साथ सोचते हैं। :) – tchrist

1

पारंपरिक यूनिक्स रास्ता है कि क्या दो फ़ाइल नाम उन्हें stat के समान ही अंतर्निहित फाइल सिस्टम वस्तु का उल्लेख किया जाता है का परीक्षण और परीक्षण करते हैं कि वे एक ही [dev,ino] जोड़ी है।

हालांकि, यह कोई अनावश्यक माउंट नहीं मानता है। अगर उन्हें अनुमति है, तो आपको इसके बारे में अलग-अलग जाना होगा।

2

एक मौका है कि एक ही फ़ाइल में दो पथ हैं (उदा। नेटवर्क \\localhost\file और \\127.0.0.1\file पर एक ही फ़ाइल को एक अलग पथ के साथ संदर्भित किया जाएगा)। मैं यह निर्धारित करने के लिए दोनों फाइलों की खुदाई की तुलना करने के साथ जाऊंगा कि वे समान हैं या नहीं।इस

public static void main(String args[]) { 
    try { 
     File f1 = new File("\\\\79.129.94.116\\share\\bots\\triplon_bots.jar"); 
     File f2 = new File("\\\\triplon\\share\\bots\\triplon_bots.jar"); 
     System.out.println(f1.getCanonicalPath().equals(f2.getCanonicalPath())); 
     System.out.println(computeDigestOfFile(f1).equals(computeDigestOfFile(f2))); 
    } 
    catch(Exception e) { 
     e.printStackTrace(); 
    } 
} 

private static String computeDigestOfFile(File f) throws Exception { 
    MessageDigest md = MessageDigest.getInstance("MD5"); 
    InputStream is = new FileInputStream(f); 
    try { 
     is = new DigestInputStream(is, md); 
     byte[] buffer = new byte[1024]; 
     while(is.read(buffer) != -1) { 
      md.update(buffer); 
     } 
    } 
    finally { 
     is.close(); 
    } 
    return new BigInteger(1,md.digest()).toString(16); 
} 

की तरह कुछ यह आउटपुट

false 
true 

यह दृष्टिकोण पाठ्यक्रम पथ तुलना किसी भी प्रकार का तुलना में धीमी गति की है, यह भी फ़ाइलों के आकार पर निर्भर करता है। एक और संभावित साइड इफेक्ट यह है कि दो फाइलों को उनके स्थानों से समान रूप से समान समझा जाएगा।

+1

हर बार जब मैं उन सभी बैकस्लाशों को देखें जिन्हें मैं अनुशंसा करना चाहता हूं कि कुछ प्राचीन डिजाइनर को उनके सिर की जांच हो। पथ पथक के रूप में बचने वाले चरित्र का चयन करना माइक्रोसॉफ्ट ने कभी भी बेवकूफ चीजों में से एक था, और अरबों लोग हमेशा उस मूर्खता की कीमत का भुगतान कर रहे हैं। उचित उपयोग करना बैकस्लैश को भ्रमित करने के बजाए इस्तेमाल होने वाले साधनों को धीमा कर देता है, जिससे सभी को दुःख का सामना करना पड़ेगा। – tchrist

+2

कंप्यूटिंग पाचन जांचने के लिए कि वे एक ही फाइल हैं या नहीं, क्योंकि वे एक फ़ाइल हो सकती हैं जो कि दूसरी की एक प्रति है - इस प्रकार एक ही "शारीरिक रूप से" – Chii

+0

यदि आप इसके लिए एमएस से इतना नफरत करते हैं, तो आपको कुछ देखना चाहिए जावास्क्रिप्ट उत्पन्न करने और कुछ regexes से मेल करने के लिए जेएसपी इंजेक्शन के लिए कोड (यहां एक स्निपेट है: loopCall + = (loopCall.equals ("")? "": ",") + "{\\\\ 'bibtex \\\\': \\\\ '" + bibtexLink + "\\\\'," + "\\\\ 'उद्धृत \\\ \ ': "+" \\\\' "+ URLEncoder.encode (citedLink, util.getSessionCharset()) +" \\\\ ', \\\\' प्लेसहोल्डर \\\\ ': \\\\' "+ प्लेसहोल्डर +" \\\\ '} ";)। तो हो सकता है कि यह बचने वाला चरित्र था जो गलत था ... –

3

आप एक exclusive write lock on the file प्राप्त करने के लिए कोशिश कर सकते, और देखते हैं कि अगर विफल रहता है:

boolean isSame; 
try { 
    FileOutputStream file1 = new FileOutputStream (file1); 
    FileOutputStream file2 = new FileOutputStream (file2); 
    FileChannel channel1 = file1.getChannel(); 
    FileChannel channel2 = file2.getChannel(); 
    FileLock fileLock1 = channel1.tryLock(); 
    FileLock fileLock2 = channel2.tryLock(); 
    isSame = fileLock2 != null; 
} catch(/*appropriate exceptions*/) { 
    isSame = false; 
} finally { 
    fileLock1.unlock(); 
    fileLock2.unlock(); 
    file1.close(); 
    file2.close(); 
    ///cleanup etc... 
} 
System.out.println(file1 + " and " + file2 + " are " + (isSame?"":"not") + " the same"); 

यह हमेशा सही यद्यपि होने की गारंटी नहीं है - आप के लिए असफल क्योंकि किसी अन्य प्रक्रिया संभावित ताला प्राप्त किया जा सकता था, और इस तरह । लेकिन कम से कम आपको बाहरी प्रक्रिया में खोलने की आवश्यकता नहीं है।

+0

धन्यवाद! जिसने मुझे बहुत मदद की, क्योंकि लिनक्स में प्रतीकात्मक लिंक को कैनोनिकल पथों का उपयोग करके किसी कारण से समाप्त नहीं किया गया था :( – Gal

+1

आपको इस तंत्र का उपयोग करके थोड़ा सावधान रहना होगा - यह सिस्टम के मूल फ़ाइल ताले का उपयोग करता है, और इसलिए आपके प्रोग्राम का व्यवहार थोड़ा अलग हो सकता है ओएस और फाइल सिस्टम प्रकार (उदाहरण के लिए, यदि आपने इसे एक एनएफएस माउंट का उपयोग किया है, तो यह संभवतः काम नहीं कर सकता क्योंकि एनएफएस में असली ताले iirc नहीं है) – Chii

1

फ़ाइलें.इससमैफ़ विधि वास्तव में इस तरह के उपयोग के लिए जोड़ा गया था - यानी, आप यह जांचना चाहते हैं कि दो गैर-बराबर पथ एक ही फ़ाइल का पता लगाते हैं या नहीं।

+2

अफसोस की बात नहीं है कि हर डेवलपर (अभी भी, 2013 में) जावा का उपयोग करने के लिए लक्जरी है 1.7 और जावा के 1.6 और पिछले संस्करणों के लिए समर्थन छोड़ दें। –

+0

आप निर्देशिका के लिए यह कैसे करते हैं, यह "अपवाद" निर्देशिका है और कोई भी पथ काम नहीं करता है, तो यह अपवाद फेंकता है। कैननिकल में '~' हो सकता है एक मामले में और किसी अन्य मामले में नहीं, लेकिन दोनों स्थान एक ही भौतिक निर्देशिका हैं। क्या यह एक आम बात नहीं होनी चाहिए? – pferrel

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