2011-06-03 15 views
18

मेरे एप्लिकेशन को कॉन्फ़िगरेशन के लिए .properties फ़ाइल का उपयोग करने की आवश्यकता है। गुण फ़ाइलों में, उपयोगकर्ता पथ निर्दिष्ट करने की अनुमति देते हैं।मूल्यों से बचने के बिना जावा प्रॉपर्टी फ़ाइल पढ़ना

समस्या

गुण फ़ाइलें,, मूल्यों भाग निकले जाने की जरूरत है जैसे

dir = c:\\mydir 

मैं किसी तरह से एक गुण फ़ाइल जहां मूल्यों भाग निकले नहीं कर रहे हैं स्वीकार करने की जरूरत की आवश्यकता ताकि उपयोगकर्ता निर्दिष्ट कर सकें:

dir = c:\mydir 

उत्तर

18

क्यों डबल फॉरवर्ड स्लैश को अलग करने के लिए गुण वर्ग को विस्तारित नहीं करते हैं। इसकी एक अच्छी विशेषता यह होगी कि आपके शेष कार्यक्रम के माध्यम से आप अभी भी मूल Properties कक्षा का उपयोग कर सकते हैं।

PropertiesEx p = new PropertiesEx(); 
p.load(new FileInputStream("C:\\temp\\demo.properties")); 
p.list(System.out); 

अलग करना कोड भी पर सुधार किया जा सकता है लेकिन सामान्य सिद्धांत है:

public class PropertiesEx extends Properties { 
    public void load(FileInputStream fis) throws IOException { 
     Scanner in = new Scanner(fis); 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 

     while(in.hasNext()) { 
      out.write(in.nextLine().replace("\\","\\\\").getBytes()); 
      out.write("\n".getBytes()); 
     } 

     InputStream is = new ByteArrayInputStream(out.toByteArray()); 
     super.load(is); 
    } 
} 

नया वर्ग के रूप में उपयोग में सरल है।

+0

इस संकेत के लिए धन्यवाद। मैंने संपत्ति फ़ाइलों को लोड और सहेजने के लिए एक स्थिर उपयोगिता वर्ग बनाया था लेकिन आपका तरीका बहुत साफ है। बीटीडब्ल्यू, नेटबैन गुण फ़ाइल (जैसे प्रोजेक्ट.प्रोपर्टीज) को लोड करने के लिए जरूरी है, खासकर गतिशीलता पैक का उपयोग करते समय। – Snicolas

6

दो विकल्प:

  • XML properties प्रारूप का उपयोग करने के बजाय
  • लेखक पलायन
+1

xml गुणों का उपयोग नहीं करना चाहते हैं। – pdeva

2

आप अमरूद के Splitter का उपयोग कर की कोशिश कर सकते बिना एक संशोधित .properties प्रारूप के लिए अपने स्वयं के पार्सर: '=' पर विभाजन और निर्माण परिणामस्वरूप Iterable से नक्शा।

इस समाधान का नुकसान यह है कि यह टिप्पणियों का समर्थन नहीं करता है।

+2

इसके अलावा: गैर-बच निकले मानों के साथ '.properties' फ़ाइल को कड़ाई से बोलना '.properties' फ़ाइलों के लिए निर्दिष्ट प्रारूप में नहीं है। प्रारूप कई लोगों के विचार से अधिक जटिल है (उदाहरण के लिए, यह हमेशा आईएसओ -885 9 -1 एन्कोडिंग में निर्दिष्ट होता है और '\ u' यूनिकोड से बचता है) का समर्थन करता है। –

6

आप "preprocess" गुण लोड करने से पहले फ़ाइल, उदाहरण के लिए कर सकते हैं:

public InputStream preprocessPropertiesFile(String myFile) throws IOException{ 
    Scanner in = new Scanner(new FileReader(myFile)); 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    while(in.hasNext()) 
     out.write(in.nextLine().replace("\\","\\\\").getBytes()); 
    return new ByteArrayInputStream(out.toByteArray()); 
} 

और अपने कोड इस तरह से

Properties properties = new Properties(); 
properties.load(preprocessPropertiesFile("path/myfile.properties")); 

ऐसा लग सकता है, अपने .properties फ़ाइल प्रकार दिखाई देगा आपको चाहिए, लेकिन आपके पास गुणों के उपयोग के लिए तैयार मूल्य होंगे।

* मुझे पता है कि फाइलों में हेरफेर करने के बेहतर तरीके होने चाहिए, लेकिन मुझे आशा है कि इससे मदद मिलेगी।

2

@pdeva: एक और समाधान

//Reads entire file in a String 
//available in java1.5 
Scanner scan = new Scanner(new File("C:/workspace/Test/src/myfile.properties")); 
scan.useDelimiter("\\Z"); 
String content = scan.next(); 

//Use apache StringEscapeUtils.escapeJava() method to escape java characters 
ByteArrayInputStream bi=new ByteArrayInputStream(StringEscapeUtils.escapeJava(content).getBytes()); 

//load properties file 
Properties properties = new Properties(); 
properties.load(bi); 
+0

आप 'नया स्कैनर (...)' और '.getBytes()' का उपयोग कर रहे हैं, तो (के रूप में यह है कि क्या properties.load द्वारा प्रयोग किया जाता है, ISO-8859-1) यकीन है कि वे सही चारसेट यहाँ का उपयोग कर रहे हैं। लेकिन बेहतर डेटा को बाइट्स और बैक में परिवर्तित करने के बजाय चरित्र रूप में रहने दें, यानी बाइटएरेइन इनपुट स्ट्रीम के बजाय स्ट्रिंग रीडर का उपयोग करें। –

3

सही तरीके से एक संपत्ति फ़ाइल संपादक (या उनके पसंदीदा पाठ संपादक के लिए एक प्लगइन) जो उन्हें पाठ के रूप में शुद्ध पाठ दर्ज की अनुमति देता है के साथ अपने उपयोगकर्ताओं को प्रदान किया जाएगा , और फ़ाइल फ़ाइल प्रॉपर्टी फ़ाइल में सहेज लेगा।

यदि आप यह नहीं चाहते हैं, तो आप संपत्ति फ़ाइलों के समान सामग्री मॉडल के प्रभावी रूप से (या उप-समूह) सामग्री प्रारूप को परिभाषित कर रहे हैं।

पूरी तरह से जाओ और वास्तव में अपने प्रारूप निर्दिष्ट करें और फिर एक तरह से या तो

  • विहित एक करने के लिए प्रारूप को बदलने के लिए के बारे में सोचते हैं, और फिर फ़ाइलों लोड करने के लिए इस का उपयोग करें, या
  • इस प्रारूप को पार्स करें और इससे Properties ऑब्जेक्ट पॉप्युलेट करें।

ये दोनों दृष्टिकोण केवल तभी काम करेंगे यदि आप वास्तव में अपनी संपत्ति वस्तु के निर्माण को नियंत्रित कर सकते हैं, अन्यथा आपको अपने आवेदन के साथ रूपांतरित प्रारूप को स्टोर करना होगा।


तो, देखते हैं कि हम इसे कैसे परिभाषित कर सकते हैं। सामान्य संपत्ति फ़ाइलों की सामग्री मॉडल सरल है:

  • एक स्ट्रिंग मूल्यों, दोनों की अनुमति के मनमाने ढंग से जावा तार करने के लिए स्ट्रिंग चाबियों का नक्शा।

जिस भागने से आप बचाना चाहते हैं, वह केवल मनमाने ढंग से जावा स्ट्रिंग्स की अनुमति देता है, न केवल इन सबसेट का।

में अक्सर पर्याप्त सबसेट होगा:

  • स्ट्रिंग कुंजी स्ट्रिंग मूल्यों के लिए (किसी भी प्रमुख युक्त या सफेद स्थान या पंक्ति विराम अनुगामी नहीं) (कोई श्वेत रिक्ति, : या = युक्त नहीं) का एक नक्शा।

अपने उदाहरण dir = c:\mydir में, कुंजी dir और मूल्य c:\mydir होगा।

यदि हम चाहते हैं कि हमारी चाबियाँ और मानों में कोई यूनिकोड वर्ण (उल्लिखित वर्जित लोगों के अलावा) शामिल है, तो हमें स्टोरेज एन्कोडिंग के रूप में यूटीएफ -8 (या यूटीएफ -16) का उपयोग करना चाहिए - क्योंकि हमारे पास वर्णों से बचने का कोई तरीका नहीं है भंडारण एन्कोडिंग के बाहर। अन्यथा, यूएस-एएससीआईआईआई या आईएसओ -885 9 -1 (सामान्य संपत्ति फाइलों के रूप में) या जावा द्वारा समर्थित किसी अन्य एन्कोडिंग पर्याप्त होगा, लेकिन सामग्री मॉडल के अपने विनिर्देशन में इसे शामिल करना सुनिश्चित करें (और इसे इस तरह से पढ़ना सुनिश्चित करें)।

के बाद से हम अपनी सामग्री मॉडल प्रतिबंधित ताकि सभी "खतरनाक" वर्ण रास्ते से हट रहे, अब हम फ़ाइल स्वरूप बस इस के रूप में परिभाषित कर सकते हैं: अब या तो कुंजी या मान में होने वाली

<simplepropertyfile> ::= (<line> <line break>)* 
<line>    ::= <comment> | <empty> | <key-value> 
<comment>   ::= <space>* "#" < any text excluding line breaks > 
<key-value>   ::= <space>* <key> <space>* "=" <space>* <value> <space>* 
<empty>    ::= <space>* 
<key>    ::= < any text excluding ':', '=' and whitespace > 
<value>    ::= < any text starting and ending not with whitespace, 
          not including line breaks > 
<space>    ::= < any whitespace, but not a line break > 
<line break>   ::= < one of "\n", "\r", and "\r\n" > 

हर \वास्तविक बैकस्लैश है, कुछ भी नहीं जो कुछ और से बचता है।

public DoubleBackslashFilter extends FilterReader { 
    private boolean bufferedBackslash = false; 

    public DoubleBackslashFilter(Reader org) { 
     super(org); 
    } 

    public int read() { 
     if(bufferedBackslash) { 
      bufferedBackslash = false; 
      return '\\'; 
     } 
     int c = super.read(); 
     if(c == '\\') 
      bufferedBackslash = true; 
     return c; 
    } 

    public int read(char[] buf, int off, int len) { 
     int read = 0; 
     if(bufferedBackslash) { 
      buf[off] = '\\'; 
      read++; 
      off++; 
      len --; 
      bufferedBackslash = false; 
     } 
     if(len > 1) { 
      int step = super.read(buf, off, len/2); 
      for(int i = 0; i < step; i++) { 
       if(buf[off+i] == '\\') { 
        // shift everything from here one one char to the right. 
        System.arraycopy(buf, i, buf, i+1, step - i); 
        // adjust parameters 
        step++; i++; 
       } 
      } 
      read += step; 
     } 
     return read; 
    } 
} 

फिर हम (हमारे गुण वस्तु को यह रीडर पास या बचत होगी: इस प्रकार, मूल स्वरूप में बदलने के लिए, हम बस यह दोगुना करने की जरूरत है, जैसे Grekz एक फ़िल्टर रीडर में, उदाहरण के लिए प्रस्तावित एक नई फाइल के लिए सामग्री)।

इसके बजाए, हम बस इस प्रारूप को स्वयं पार्स कर सकते हैं।

public Properties parse(Reader in) { 
    BufferedReader r = new BufferedReader(in); 
    Properties prop = new Properties(); 
    Pattern keyValPattern = Pattern.compile("\s*=\s*"); 
    String line; 
    while((line = r.readLine()) != null) { 
     line = line.trim(); // remove leading and trailing space 
     if(line.equals("") || line.startsWith("#")) { 
      continue; // ignore empty and comment lines 
     } 
     String[] kv = line.split(keyValPattern, 2); 
     // the pattern also grabs space around the separator. 
     if(kv.length < 2) { 
      // no key-value separator. TODO: Throw exception or simply ignore this line? 
      continue; 
     } 
     prop.setProperty(kv[0], kv[1]); 
    } 
    r.close(); 
    return prop; 
} 

फिर, Properties.store() इस के बाद का उपयोग कर, हम इसे मूल स्वरूप में निर्यात कर सकते हैं।

0

यह आपके प्रश्न का सटीक उत्तर, लेकिन एक अलग समाधान है कि अपनी आवश्यकताओं के उपयुक्त हो सकता है नहीं है। जावा में, आप पथ विभाजक के रूप में / का उपयोग कर सकते हैं और यह विंडोज, लिनक्स और ओएसएक्स दोनों पर काम करेगा। यह सापेक्ष पथ के लिए विशेष रूप से उपयोगी है।

अपने उदाहरण में, आप इस्तेमाल कर सकते हैं:

dir = c:/mydir 
+0

हमारे उपयोगकर्ताओं को '/' ऑफहैंड का उपयोग करने के बारे में पता नहीं होगा। अगर हमें उन्हें '/' का उपयोग करने के लिए कहना है, तो हम उन्हें \\ उपयोग करने के लिए भी कह सकते थे – pdeva

3

@Ian हारिगान के आधार पर, यहाँ Netbeans गुण फ़ाइल प्राप्त करने के लिए एक पूर्ण समाधान है (और अन्य भागने गुण फ़ाइल) सही से और पाठ फ़ाइलें ASCII करने के लिए :

import java.io.BufferedReader; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.io.Reader; 
import java.io.Writer; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 
import java.util.Properties; 

/** 
* This class allows to handle Netbeans properties file. 
* It is based on the work of : http://stackoverflow.com/questions/6233532/reading-java-properties-file-without-escaping-values. 
* It overrides both load methods in order to load a netbeans property file, taking into account the \ that 
* were escaped by java properties original load methods. 
* @author stephane 
*/ 
public class NetbeansProperties extends Properties { 
    @Override 
    public synchronized void load(Reader reader) throws IOException { 
     BufferedReader bfr = new BufferedReader(reader); 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 

     String readLine = null; 
     while((readLine = bfr.readLine()) != null) { 
      out.write(readLine.replace("\\","\\\\").getBytes()); 
      out.write("\n".getBytes()); 
     }//while 

     InputStream is = new ByteArrayInputStream(out.toByteArray()); 
     super.load(is); 
    }//met 

    @Override 
    public void load(InputStream is) throws IOException { 
     load(new InputStreamReader(is)); 
    }//met 

    @Override 
    public void store(Writer writer, String comments) throws IOException { 
     PrintWriter out = new PrintWriter(writer); 
     if(comments != null) { 
      out.print('#'); 
      out.println(comments); 
     }//if 
     List<String> listOrderedKey = new ArrayList<String>(); 
     listOrderedKey.addAll(this.stringPropertyNames()); 
     Collections.sort(listOrderedKey); 
     for(String key : listOrderedKey) { 
      String newValue = this.getProperty(key); 
      out.println(key+"="+newValue ); 
     }//for 
    }//met 

    @Override 
    public void store(OutputStream out, String comments) throws IOException { 
     store(new OutputStreamWriter(out), comments); 
    }//met 
}//class 
संबंधित मुद्दे