2011-07-20 5 views
13

File.mkdir का उपयोग करते समय, और दोस्तों को लगता है कि वे विफलता पर अपवाद नहीं फेंकते हैं! शुक्र है कि FindBugs ने इसे इंगित किया और अब मेरा कोड कम से कम वापसी मूल्य की जांच करता है लेकिन मुझे अभी भी के बारे में सार्थक जानकारी प्राप्त करने का कोई तरीका नहीं दिख रहा है क्यों कॉल विफल हो जाती है!जावा फ़ाइल ऑब्जेक्ट्स में विफल कॉल के लिए एक सार्थक संदेश कैसे प्राप्त करें (mkdir, नाम बदलें, हटाएं)

मुझे कैसे पता चलेगा कि इन फ़ाइल विधियों को कॉल क्यों विफल हो जाती है? क्या कोई अच्छा विकल्प या पुस्तकालय है जो इसे संभालता है?

मैंने एसओ और Google पर कुछ खोज यहां की हैं और इस विषय पर आश्चर्यजनक छोटी जानकारी मिली है।

[अपडेट] मैंने वीएफएस को एक कोशिश दी है और इसके अपवाद में अब और उपयोगी जानकारी नहीं है। उदाहरण के लिए हाल ही में हटाई गई निर्देशिका को स्थानांतरित करने का प्रयास किया गया जिसके परिणामस्वरूप Could not rename file "D:\path\to\fileA" to "file:///D:/path/do/fileB". कोई उल्लेख नहीं हुआ कि फ़ाइल अब मौजूद नहीं है।

[अद्यतन] व्यापार आवश्यकताओं, केवल 1.6 समाधान JDK करने के लिए मुझे की सीमा तो JDK 1.7 बाहर है

+0

मुझे नहीं पता। लेकिन यह देखने के लिए कि निर्देशिका बनाने की प्रक्रिया में किस प्रकार के अपवाद फेंक दिए जाएंगे और इसलिए, यह असफल क्यों होगा, मैं स्रोत कोड की जांच करने की सिफारिश करता हूं। – Moonbeam

+0

@ मूनबीन: मुद्दा यह है कि उन मामलों के लिए अपवाद नहीं फेंक दिया गया है जो निर्देशिका के रूप में पहले से मौजूद हैं। –

उत्तर

8

आप मूल विधियों को कॉल कर सकते हैं, और इस तरह से उचित त्रुटि कोड प्राप्त कर सकते हैं। उदाहरण के लिए, सी फ़ंक्शन mkdir में EEXIST और ENOSPC जैसे त्रुटि कोड हैं। आप इन देशी कार्यों को आसानी से एक्सेस करने के लिए JNA का उपयोग कर सकते हैं। यदि आप * निक्स और विंडोज़ का समर्थन कर रहे हैं तो आपको इस कोड के दो संस्करणों को बनाने की आवश्यकता होगी।

linux आप ऐसा कर सकते हैं पर JNA mkdir का एक उदाहरण के लिए,

import java.io.IOException; 

import com.sun.jna.LastErrorException; 
import com.sun.jna.Native; 

public class FileUtils { 

    private static final int EACCES = 13; 
    private static final int EEXIST = 17; 
    private static final int EMLINK = 31; 
    private static final int EROFS = 30; 
    private static final int ENOSPC = 28; 
    private static final int ENAMETOOLONG = 63; 

    static void mkdir(String path) throws IOException { 

    try { 
     NativeLinkFileUtils.mkdir(path); 

    } catch (LastErrorException e) { 
     int errno = e.getErrorCode(); 
     if (errno == EACCES) 
     throw new IOException(
      "Write permission is denied for the parent directory in which the new directory is to be added."); 
     if (errno == EEXIST) 
     throw new IOException("A file named " + path + " already exists."); 
     if (errno == EMLINK) 
     throw new IOException(
      "The parent directory has too many links (entries). Well-designed file systems never report this error, because they permit more links than your disk could possibly hold. However, you must still take account of the possibility of this error, as it could result from network access to a file system on another machine."); 
     if (errno == ENOSPC) 
     throw new IOException(
      "The file system doesn't have enough room to create the new directory."); 
     if (errno == EROFS) 
     throw new IOException(
      "The parent directory of the directory being created is on a read-only file system and cannot be modified."); 
     if (errno == EACCES) 
     throw new IOException(
      "The process does not have search permission for a directory component of the file name."); 
     if (errno == ENAMETOOLONG) 
     throw new IOException(
      "This error is used when either the total length of a file name is greater than PATH_MAX, or when an individual file name component has a length greater than NAME_MAX. See section 31.6 Limits on File System Capacity."); 
     else 
     throw new IOException("unknown error:" + errno); 
    } 




    } 
} 

class NativeLinkFileUtils { 
    static { 
    try { 
     Native.register("c"); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 

    static native int mkdir(String dir) throws LastErrorException; 

} 
+0

कोड उदाहरण के लिए धन्यवाद, भले ही यह ऐप विंडोज केंद्रित है, यह एक आसान अनुवाद होना चाहिए। मेरा एकमात्र उत्कृष्ट सवाल यह है कि यह विंडोज यूएनसी पथों के साथ कैसे सहभागिता करता है? मैंने सी से विंडो आधारित नेटवर्क पथों के साथ कभी काम नहीं किया है। मुझे लगता है कि मैं हमेशा इसे खुद देख सकता हूं लेकिन आपको पता है कि आप पहले से ही यहां जवाब दे सकते हैं :) –

+0

मेरी खिड़कियां और सी ज्ञान काफी सीमित है, लेकिन यह एक अच्छा लगता है ढेर अतिप्रवाह के लिए सवाल। – sbridges

5

आप इस तरह की कुछ सामग्री के साथ एक उपयोगिता वर्ग बना सकते हैं:

public int mkdir(File dirToCreate) throws IOException 
{ 
    if (dirToCreate.exists()) 
     throw new IOException("Folder already exists"); 

    if (!dirToCreate.getParent().canWrite()) 
     throw new IOException("No write access to create the folder"); 

    return dirToCreate.mkdir(); 
} 


public int rename(File from, File to) throws IOException, FileNotFoundException 
{ 
    if (from.equals(to)) 
     throw new IllegalArgumentException("Files are equal"); 

    if (!from.exists()) 
     throw new FileNotFoundException(from.getAbsolutePath() + " is not found"); 

    if (!to.getParent().exists()) 
     throw new IllegalAccessException("Parent of the destination doesn't exist"); 

    if (!to.getParent().canWrite()) 
     throw new IllegalAccessException("No write access to move the file/folder"); 

    return from.renameTo(to); 
} 
बेशक

यह पूरा नहीं है, लेकिन आप इस विचार को पूरा कर सकते हैं।

+3

संभव लगता है लेकिन "सही" पाने के लिए मुश्किल हो सकता है। परीक्षण करने के लिए इतनी सारी संभावनाएं हैं कि अंतर्निहित प्रणाली को "जानना" चाहिए। उदाहरण के लिए, यह पता लगाना कि नेटवर्क त्रुटि के कारण mkdir om नेटवर्क पथ विफल रहा है। –

+2

और डिस्क पूर्ण होने पर क्या होगा? – Arjan

+4

यह दृष्टिकोण दौड़ की स्थिति से भी भरा हुआ है। –

1

इसके बजाए आप जकार्ता वीएफएस का उपयोग कर सकते हैं। FileObject.createFolder()FileSystemException फेंकता है जो त्रुटि कोड रखता है। यह @Martijn Courteaux

+0

'FileObject' इंटरफ़ेस में' createFolder' विधि नहीं है। – Arjan

+0

@ अरजन: http://commons.apache.org/vfs/apidocs/org/apache/commons/vfs/FileObject.html#createFolder() –

+0

@Andrew: मैं सही खड़ा हूं, मुझे केवल http: // डाउनलोड मिला। oracle.com/javase/6/docs/api/javax/tools/FileObject.html – Arjan

4

द्वारा प्रदान किए गए तर्क को लागू करने के बजाय जेडीके 7 के new file API का उपयोग करें। इसमें बहुत बेहतर ओएस एकीकरण है और अधिक विस्तृत प्रतिक्रिया प्रदान करता है। उदाहरण के लिए docs for moving/renaming देखें।

+0

एह, यह बहुत अच्छा है और सभी आवश्यकताएं केवल जेडीके 1.6 का उपयोग करना है। –

4

आप कमांड निष्पादित और err उत्पादन है, जो एक सार्थक संदेश है ले सकता है।

public static void main(String[] args) throws Exception { 
    System.out.println(getErrorMessage("cp fake.file x")); 
    System.out.println(getErrorMessage("cp /tmp /tmp")); 
    System.out.println(getErrorMessage("mkdir /Volumes")); 
    System.out.println(getErrorMessage("mv /tmp /")); 
    System.out.println(getErrorMessage("mv fake.file /tmp")); 
} 

:

import org.apache.commons.exec.*; 

public static String getErrorMessage(String command) { 
    CommandLine cmdLine = CommandLine.parse(command); 
    DefaultExecutor executor = new DefaultExecutor(); 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    ByteArrayOutputStream err = new ByteArrayOutputStream(); 
    executor.setStreamHandler(new PumpStreamHandler(out, err)); 
    try { 
     executor.execute(cmdLine); 
    } catch (Exception e) { 
     return err.toString().trim(); 
    } 
    return null; // no error occurred 
} 

यहाँ फ़ाइल आपरेशन त्रुटि स्थिति की एक किस्म दिखा इस कोड का एक परीक्षण है:

यहाँ कुछ न्यूनतम निष्पादन योग्य कोड (जो apache commons-exec उपयोग करता है) यह दर्शाता है कि यह कैसे काम कर सकता है आउटपुट (मैक ओएसएक्स पर चलाएं):

cp: fake.file: No such file or directory 
cp: /tmp is a directory (not copied). 
mkdir: /Volumes: File exists 
mv: /tmp and /tmp are identical 
mv: rename fake.file to /tmp/fake.file: No such file or directory 

आप कर सकते थे

if (message.endsWith("No such file or directory")) 
    throw new FileNotFoundException(); // Use IOExceptions if you can 
if (message.endsWith("are identical")) 
    throw new IdenticalFileException(); // Create your own Exceptions that extend IOException 

आप हैं: एक विधि है कि IOException फेंकता है कि, संदेश मिला है, रेगुलर एक्सप्रेशन मिलान या विशेष IOExceptions को contains का उपयोग कर कुंजी मापदंडों और नक्शा संदेशों के लिए यह पार्स और उन्हें फेंक सकता है, जैसे में उपरोक्त विधि लपेट कई ओएस स्वादों पर उपयोग के लिए इसे सार करना चाहता था, आपको प्रत्येक प्लेटफ़ॉर्म के लिए कोड लागू करना होगा (विंडोज़ और * निक्स किसी भी दिए गए फ़ाइल ऑपरेशन/परिणाम के लिए अलग-अलग खोल कमांड/त्रुटि संदेश का उपयोग करें)।

यदि इस उत्तर में बक्षीस दिया जाता है, तो मैं एक पूर्ण साफ, कार्य कोड के संस्करण को पोस्ट करूंगा, जिसमें स्टाइलिश enum फ़ाइल संचालन के लिए होगा।

+0

मैं मानता हूं कि यह एक बिल्कुल वैध समाधान है। ऐसा लगता है कि इनपुट को स्वच्छ करने के लिए एक निश्चित लालित्य और महान देखभाल की आवश्यकता होगी। –

+0

जब तक बदसूरत कार्यान्वयन सुरुचिपूर्ण facades के पीछे छिपे हुए हैं (माइक्रोसॉफ्ट सॉफ्टवेयर की तरह थोड़ा ;-)), यह स्वीकार्य हो सकता है – Bohemian