`
tianshui0
  • 浏览: 85752 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java操作properties文件持久键值对和注解到文件

    博客分类:
  • Java
 
阅读更多

properties文件在应用系统很长用,写properties文件和加载properties文件都很简单也是很常用的方法。

持久化键值对Properties类提供了store几个方法,其中只能在第一行加入注释,之前写的注释也会丢失并且不支持中文。

因此改进写一下代码,对注解中文的支持以及持久化过程中不丢失注解,不多说,上代码。

package com.zohan.www.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * @ClassName: Properties
 * @Description: 重写Properties类中的部分方法 在保存过程中不丢失注释
 * @author zohan inlw@sina.com
 * @date 2012-10-24 下午10:31:54
 * @version 0.1.1 修改对 键值对中存在等号的
 * 
 */
public class Properties extends java.util.Properties {
	/** 源文件地址 */
	private String filePath = null;
	/** 参考文件地址 */
	private String referFile = null;

	/**
	 * 存放用户放置的 key\value
	 */
	private Map<String, String> map = new HashMap<String, String>();

	/**
	 * @Fields serialVersionUID :(用一句话描述这个变量表示什么)
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * @throws IOException
	 * @Title: load
	 * @Description: 增加load方法,
	 * @param file
	 *            设定文件
	 * @return void 返回类型
	 * @throws
	 */
	public void load(File file) throws IOException {
		if (null != file)
			this.filePath = file.getPath();
		FileInputStream fis = new FileInputStream(file);
		super.load(fis);
		fis.close();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Properties#getProperty(java.lang.String)
	 */
	@Override
	public String getProperty(String key) {
		String value = map.get(key);
		return null == value ? super.getProperty(key) : value;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Properties#setProperty(java.lang.String, java.lang.String)
	 */
	@Override
	public synchronized Object setProperty(String key, String value) {
		return map.put(key, value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Properties#stringPropertyNames()
	 */
	@Override
	public Set<String> stringPropertyNames() {
		return super.stringPropertyNames();
	}

	/**
	 * 
	 * @Title: store
	 * @Description:把键值对持久化,包括注释 加载的时候请使用public void load(File file) 方法
	 * @param target
	 * @param comments
	 * @throws Exception
	 *             设定文件
	 * @return void 返回类型
	 * @throws
	 */
	public void store(String target, String comments) throws Exception {
		// filePath 不为空且存在
		File inFile = null;
		String temp = System.getProperty("java.io.tmpdir");
		temp = temp.endsWith(File.separator) ? temp : temp
				.concat(File.separator);
		if (!StringUtils.isEmpty(filePath)) {
			inFile = new File(filePath);
			if (inFile.exists()) {
				referFile = temp.concat(inFile.getName());
			}
		}

		inFile = new File(filePath);
		// filePath 为null targetFile作为 参考文件读取
		if (StringUtils.isEmpty(filePath) && !inFile.exists()) {
			throw new Exception("参考文件不能为空");
		}
		// referFile 为空选择target 为参照文件
		if (StringUtils.isEmpty(referFile)) {
			referFile = temp.concat(inFile.getName());
		}
		FileUtils.copyFile(inFile, new File(referFile));
		store0(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
				target), "utf-8")), comments, true);
		new File(referFile).delete();
	}

	/**
	 * 
	 * @Title: store0
	 * @Description: 重写父类的写入文件方法,将注释也写入文件
	 * @param @param bw
	 * @param @param comments
	 * @param @param escUnicode
	 * @param @throws IOException 设定文件
	 * @return void 返回类型
	 * @throws
	 */
	private void store0(BufferedWriter bw, String comments, boolean escUnicode)
			throws IOException {
		if (comments != null) {
			writeComments(bw, comments);
		}
		bw.write("#" + new Date().toString());
		bw.newLine();
		synchronized (this) {
			Map<String, String> temp = new HashMap<String, String>();
			for (Enumeration e = keys(); e.hasMoreElements();) {
				String key = (String) e.nextElement();
				String val = (String) get(key);
				temp.put(key, val);
			}
			for (String key : map.keySet()) {
				temp.put(key, map.get(key));
			}
			BufferedReader br = new BufferedReader(new FileReader(referFile));
			String line = "";
			while ((line = br.readLine()) != null) {
				if (line.length() == 0) {
					bw.newLine();
				} else if (line.trim().startsWith("#")) {
					writeCommentsLine(bw, line);
				} else {
					// 获取key(^[^=]*(\\=)?[^=]*)=
					Pattern p = Pattern.compile("(^[^=]*)=");
					Matcher m = p.matcher(line.replaceAll("\\\\=", "ab"));
					String key = "";
					if (m.find()) {
						key = m.group(1);
						key = line.substring(0, key.length());
					}
					key = key.replaceAll("\\\\=", "=");
					String value = temp.remove(key.trim());
					if (StringUtils.isEmpty(value)) {
						String v = line.replace(key, "");
						if (StringUtils.isEmpty(v)) {
							value = "";
						} else {
							if (v.trim().startsWith("=")) {
								value = v.substring(1);
							} else {
								value = temp.get(key);
							}
						}
					}
					key = saveConvert(key.trim(), true, escUnicode);
					/*
					 * No need to escape embedded and trailing spaces for value,
					 * hence pass false to flag.
					 */
					value = saveConvert(value.trim(), false, escUnicode);
					bw.write(key + "=" + value);
					bw.newLine();
				}
			}
			br.close();

			for (String key : temp.keySet()) {
				String value = map.get(key);
				key = saveConvert(key.trim(), true, escUnicode);
				if (!StringUtils.isEmpty(value)) {
					value = saveConvert(value.trim(), false, escUnicode);
				} else {
					value = "";
				}
				bw.write(key + "=" + value);
				bw.newLine();

			}

		}
		bw.flush();

	}

	/*
	 * Converts unicodes to encoded &#92;uxxxx and escapes special characters
	 * with a preceding slash
	 */
	private String saveConvert(String theString, boolean escapeSpace,
			boolean escapeUnicode) {
		int len = theString.length();
		int bufLen = len * 2;
		if (bufLen < 0) {
			bufLen = Integer.MAX_VALUE;
		}
		StringBuffer outBuffer = new StringBuffer(bufLen);

		for (int x = 0; x < len; x++) {
			char aChar = theString.charAt(x);
			// Handle common case first, selecting largest block that
			// avoids the specials below
			if ((aChar > 61) && (aChar < 127)) {
				if (aChar == '\\') {
					outBuffer.append('\\');
					outBuffer.append('\\');
					continue;
				}
				outBuffer.append(aChar);
				continue;
			}
			switch (aChar) {
			case ' ':
				if (x == 0 || escapeSpace)
					outBuffer.append('\\');
				outBuffer.append(' ');
				break;
			case '\t':
				outBuffer.append('\\');
				outBuffer.append('t');
				break;
			case '\n':
				outBuffer.append('\\');
				outBuffer.append('n');
				break;
			case '\r':
				outBuffer.append('\\');
				outBuffer.append('r');
				break;
			case '\f':
				outBuffer.append('\\');
				outBuffer.append('f');
				break;
			case '=': // Fall through
			case ':': // Fall through
			case '#': // Fall through
			case '!':
				outBuffer.append('\\');
				outBuffer.append(aChar);
				break;
			default:
				if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode) {
					outBuffer.append('\\');
					outBuffer.append('u');
					outBuffer.append(toHex((aChar >> 12) & 0xF));
					outBuffer.append(toHex((aChar >> 8) & 0xF));
					outBuffer.append(toHex((aChar >> 4) & 0xF));
					outBuffer.append(toHex(aChar & 0xF));
				} else {
					outBuffer.append(aChar);
				}
			}
		}
		return outBuffer.toString();
	}

	/**
	 * Convert a nibble to a hex character
	 * 
	 * @param nibble
	 *            the nibble to convert.
	 */
	private static char toHex(int nibble) {
		return hexDigit[(nibble & 0xF)];
	}

	/** A table of hex digits */
	private static final char[] hexDigit = { '0', '1', '2', '3', '4', '5', '6',
			'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

	/**
	 * 
	 * @Title: writeCommentsLine
	 * @Description: 无特殊写法
	 * @param @param bw
	 * @param @param comments
	 * @param @throws IOException 设定文件
	 * @return void 返回类型
	 * @throws
	 */
	private static void writeCommentsLine(BufferedWriter bw, String comments)
			throws IOException {
		bw.write(comments);
		bw.newLine();
	}

	/**
	 * 
	 * @Title: writeComments
	 * @Description:拷贝类的写注解方式
	 * @param @param bw
	 * @param @param comments
	 * @param @throws IOException 设定文件
	 * @return void 返回类型
	 * @throws
	 */
	private static void writeComments(BufferedWriter bw, String comments)
			throws IOException {
		bw.write("#");
		int len = comments.length();
		int current = 0;
		int last = 0;
		char[] uu = new char[6];
		uu[0] = '\\';
		uu[1] = 'u';
		while (current < len) {
			char c = comments.charAt(current);
			if (c > '\u00ff' || c == '\n' || c == '\r') {
				if (last != current)
					bw.write(comments.substring(last, current));
				if (c > '\u00ff') {
					uu[2] = toHex((c >> 12) & 0xf);
					uu[3] = toHex((c >> 8) & 0xf);
					uu[4] = toHex((c >> 4) & 0xf);
					uu[5] = toHex(c & 0xf);
					bw.write(new String(uu));
				} else {
					bw.newLine();
					if (c == '\r' && current != len - 1
							&& comments.charAt(current + 1) == '\n') {
						current++;
					}
					if (current == len - 1
							|| (comments.charAt(current + 1) != '#' && comments
									.charAt(current + 1) != '!'))
						bw.write("#");
				}
				last = current + 1;
			}
			current++;
		}
		if (last != current)
			bw.write(comments.substring(last, current));
		bw.newLine();
	}

	/**
	 * @throws Exception
	 * @Title: main
	 * @Description: 测试文件
	 * @param @param args 设定文件
	 * @return void 返回类型
	 * @throws
	 */
	public static void main(String[] args) throws Exception {
		Properties pro = new Properties();
		File file = new File("e:\\ss.properties");
		try {
			// 采用File参数
			pro.load(file);
			pro.setProperty("zohan", "zohan");
			System.out.println(pro.get("zohan"));
			// 持久化键值对
			pro.store("e:\\ss.properties", null);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

    前两天的代码里,有bug,不支持键值对中有等号,今天修复了bug重新发一次

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics