用python 实现 java.util.Properties 类的一些基本操作
By:Roy.LiuLast updated:2014-03-09
	    
	        在java 编程中,很多配置文件用键值对的方式存储在 properties 文件中,可以读取,修改。而且在java 中有 java.util.Properties 这个类,可以很方便的处理properties 文件, 在python 中虽然也有读取配置文件的类ConfigParser, 但如果习惯java 编程的人估计更喜欢下面这个用python 实现的读取  properties 文件的类:
当然,测试这个类你需要在程序目录下简历test2.properties 文件。才可以看到效果,基本可以达到用python 读写 properties 文件的效果.
	    
	    
	    
	
"""
A Python replacement for java.util.Properties class
This is modelled as closely as possible to the Java original. 
"""
import sys,os
import re
import time
class IllegalArgumentException(Exception):
    def __init__(self, lineno, msg):
        self.lineno = lineno
        self.msg = msg
    def __str__(self):
        s='Exception at line number %d => %s' % (self.lineno, self.msg)
        return s
                 
class Properties(object):
    """ A Python replacement for java.util.Properties """
    
    def __init__(self, props=None):
        # Note: We don't take a default properties object
        # as argument yet
        # Dictionary of properties.
        self._props = {}
        # Dictionary of properties with 'pristine' keys
        # This is used for dumping the properties to a file
        # using the 'store' method
        self._origprops = {}
        # Dictionary mapping keys from property
        # dictionary to pristine dictionary
        self._keymap = {}
        
        self.othercharre = re.compile(r'(?',line
                # Means we need to split by space.
                first, last = m2.span()
                sepidx = first
            elif m:
                # print 'Other match=>',line
                # No matching wspace char found, need
                # to split by either '=' or ':'
                first, last = m.span()
                sepidx = last - 1
                # print line[sepidx]
                
                
            # If the last character is a backslash
            # it has to be preceded by a space in which
            # case the next line is read as part of the
            # same property
            while line[-1] == '\\':
                # Read next line
                nextline = i.next()
                nextline = nextline.strip()
                lineno += 1
                # This line will become part of the value
                line = line[:-1] + nextline
            # Now split to key,value according to separation char
            if sepidx != -1:
                key, value = line[:sepidx], line[sepidx+1:]
            else:
                key,value = line,''
            self.processPair(key, value)
            
    def processPair(self, key, value):
        """ Process a (key, value) pair """
        oldkey = key
        oldvalue = value
        
        # Create key intelligently
        keyparts = self.bspacere.split(key)
        # print keyparts
        strippable = False
        lastpart = keyparts[-1]
        if lastpart.find('\\ ') != -1:
            keyparts[-1] = lastpart.replace('\\','')
        # If no backspace is found at the end, but empty
        # space is found, strip it
        elif lastpart and lastpart[-1] == ' ':
            strippable = True
        key = ''.join(keyparts)
        if strippable:
            key = key.strip()
            oldkey = oldkey.strip()
        
        oldvalue = self.unescape(oldvalue)
        value = self.unescape(value)
        
        self._props[key] = value.strip()
        # Check if an entry exists in pristine keys
        if self._keymap.has_key(key):
            oldkey = self._keymap.get(key)
            self._origprops[oldkey] = oldvalue.strip()
        else:
            self._origprops[oldkey] = oldvalue.strip()
            # Store entry in keymap
            self._keymap[key] = oldkey
        
    def escape(self, value):
        # Java escapes the '=' and ':' in the value
        # string with backslashes in the store method.
        # So let us do the same.
        newvalue = value.replace(':','\:')
        newvalue = newvalue.replace('=','\=')
        return newvalue
    def unescape(self, value):
        # Reverse of escape
        newvalue = value.replace('\:',':')
        newvalue = newvalue.replace('\=','=')
        return newvalue    
        
    def load(self, stream):
        """ Load properties from an open file stream """
        
        # For the time being only accept file input streams
        if type(stream) is not file:
            raise TypeError,'Argument should be a file object!'
        # Check for the opened mode
        if stream.mode != 'r':
            raise ValueError,'Stream should be opened in read-only mode!'
        try:
            lines = stream.readlines()
            self.__parse(lines)
        except IOError, e:
            raise
    def getProperty(self, key):
        """ Return a property for the given key """
        
        return self._props.get(key,'')
    def setProperty(self, key, value):
        """ Set the property for the given key """
        if type(key) is str and type(value) is str:
            self.processPair(key, value)
        else:
            raise TypeError,'both key and value should be strings!'
    def propertyNames(self):
        """ Return an iterator over all the keys of the property
        dictionary, i.e the names of the properties """
        return self._props.keys()
    def list(self, out=sys.stdout):
        """ Prints a listing of the properties to the
        stream 'out' which defaults to the standard output """
        out.write('-- listing properties --\n')
        for key,value in self._props.items():
            out.write(''.join((key,'=',value,'\n')))
    def store(self, out, header=""):
        """ Write the properties list to the stream 'out' along
        with the optional 'header' """
        if out.mode[0] != 'w':
            raise ValueError,'Steam should be opened in write mode!'
        try:
            out.write(''.join(('#',header,'\n')))
            # Write timestamp
            tstamp = time.strftime('%a %b %d %H:%M:%S %Z %Y', time.localtime())
            out.write(''.join(('#',tstamp,'\n')))
            # Write properties from the pristine dictionary
            for prop, val in self._origprops.items():
                out.write(''.join((prop,'=',self.escape(val),'\n')))
                
            out.close()
        except IOError, e:
            raise
    def getPropertyDict(self):
        return self._props
    def __getitem__(self, name):
        """ To support direct dictionary like access """
        return self.getProperty(name)
    def __setitem__(self, name, value):
        """ To support direct dictionary like access """
        self.setProperty(name, value)
        
    def __getattr__(self, name):
        """ For attributes not found in self, redirect
        to the properties dictionary """
        try:
            return self.__dict__[name]
        except KeyError:
            if hasattr(self._props,name):
                return getattr(self._props, name)
            
if __name__=="__main__":
    p = Properties()
    p.load(open('test2.properties'))
    p.list()
    print p
    print p.items()
    print p['name3']
    p['name3'] = 'changed = value'
    print p['name3']    
    p['new key'] = 'new value'
    p.store(open('test2.properties','w'))
当然,测试这个类你需要在程序目录下简历test2.properties 文件。才可以看到效果,基本可以达到用python 读写 properties 文件的效果.
From:一号门
Previous:python 序列化成json 乱码问题的解决

COMMENTS