`
tianshui0
  • 浏览: 88180 次
  • 性别: 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重新发一次

分享到:
评论

相关推荐

    Mybatis3系列课程-db.properties

    1. 加载`db.properties`:使用`java.util.Properties`类读取配置文件,解析成键值对。 2. 创建`SqlSessionFactoryBuilder`:利用配置信息实例化`SqlSessionFactoryBuilder`对象。 3. 构建`SqlSessionFactory`:调用`...

    Java工程师应用技术汇总

    - **Properties**:用于处理键值对的属性文件。 **1.2.11 Annotation** - **注解**:提供元数据的方式,可被编译器或运行时解析。 **1.2.12 JMS** - **消息服务**:Java Messaging Service,用于生产者和消费者...

    多端小程序商城、App商城。使用Java开发,SpringBoot框架、MyBatis-plus持久层框架、Redi.zip

    MyBatis-plus在SQL映射文件的基础上增加了实体类和注解,使得数据库操作更加直观和便捷。在商城系统中,MyBatis-plus可以有效地处理商品、订单、用户等数据的增删改查,提高了开发效率。 Redis是一款高性能的键值...

    java的redis项目

    Spring Data Redis提供了`RedisTemplate`和`StringRedisTemplate`,用于操作Redis中的键值对。前者是通用模板,支持各种数据类型,后者专为字符串操作优化。 5. **缓存管理** Spring Boot可以通过`@Cacheable`、`...

    SpringBoot使用注解实现 Redis 数据库的切换.zip

    Redis作为一种高性能的键值数据存储系统,常被用作缓存或持久化数据库,以提升应用性能。本教程将深入讲解如何在SpringBoot项目中通过注解方式实现Redis数据库的切换。 首先,我们需要理解SpringBoot与Redis的集成...

    SpringBoot集成Redis应用配置(附完整配置文件)

    配置完成后,Spring Boot会自动创建一个RedisTemplate实例,你可以通过@Autowired注解注入到你的服务类中,如下所示: ```java @Autowired private RedisTemplate, Object&gt; redisTemplate; ``` 为了方便操作,...

    java资源之Mybatis基础入门学习笔记

    Mybatis是一款广泛使用的Java持久层框架,它的主要目标是简化对数据库的操作,提供更加灵活的SQL映射机制。Mybatis起源于Apache组织的ibatis框架,历经发展,在2010年迁移到Google Code并改名为Mybatis,最终在2013...

    hibernate开发的工具包(注解包,mysql包,日志log4j包)

    Hibernate使得Java对象可以直接参与到数据库操作中,极大地提高了开发效率。 5. **依赖管理**: 在实际开发中,这些jar包可能还需要其他依赖,如JTA(Java Transaction API)用于处理分布式事务,或者其他的ORM...

    SpringBoot技术分享(培训ppt文档).pptx

    `.properties`采用键值对的形式,而`.yml`以树状结构展示,更易读。在编写配置文件时,需要注意键值间的分隔符和缩进规则。 Spring Boot的视图层技术可以整合JSP或Thymeleaf。Thymeleaf是Spring官方推荐的模板引擎...

    iBatis和MyBatis对比

    1. `properties`:定义了一系列的属性键值对,这些属性可以在配置文件的其他部分被引用。 2. `settings`:用来调整MyBatis的行为,例如是否启用延迟加载(LazyLoading)、日志配置等。 3. `typeAliases`:为Java类...

    Java面试框架高频问题2019

    - **properties**:使用键值对的形式。 - **yml/yaml**:使用层级结构,支持数组和复杂对象。 **5.SpringBoot的核心注解是哪个?它主要由哪几个注解组成的?** - **@SpringBootApplication**:组合注解,包括`@...

    java springboot redisson mybatis maven.zip

    MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 4. **Maven**: Maven是Apache软件基金会开发的一个项目管理工具,它...

    总结一天学会MyBatis框架所有知识.docx

    MyBatis是一个轻量级的Java持久层框架,它的核心目标是简化JDBC的开发流程,实现事务管理和实体类与SQL命令的动态映射。MyBatis起源于Apache的Ibatis项目,在2010年迁移到Google,然后在2013年进一步迁移到Github,...

    SSH2 框架实现增删改查

    在Action中,我们可以使用国际化资源文件中的键值对来获取错误消息或其他提示信息,以适应不同地区的用户。 总结起来,SSH2框架在实现增删改查功能时,涉及了Struts2的请求处理、Spring的依赖注入和事务管理、...

    基于spring+mybatis+redis 封装的高易用性的框架.zip

    其次,MyBatis是一个轻量级的持久层框架,它将SQL语句与Java代码解耦,通过XML或注解的方式配置映射,使得数据库操作更为直观和灵活。在Spring+MyBatis的集成中,Spring管理MyBatis的SqlSessionFactory和SqlSession...

    4-1_SpringBoot敏捷开发技术.pdf

    只需在配置文件中定义新的键值对,然后在Java类中使用`@ConfigurationProperties`注解将它们绑定到一个Java Bean。 #### 5. 随机数配置 Spring Boot提供了生成随机数的能力,可以通过配置文件定义随机数的范围和...

    sprint boot数据库操作(jpa)

    在Spring Boot中集成JPA(Java Persistence API)可以方便地进行数据库操作,包括CRUD(创建、读取、更新和删除)等基本操作。本篇文章将深入探讨Spring Boot结合JPA进行数据库操作的相关知识点。 1. **JPA介绍** ...

    springboot_redis.zip

    Redis是一种高性能的键值数据存储系统,常用于缓存、消息队列和数据持久化等场景。Spring Boot提供了便捷的方式与Redis进行交互,通过集成Spring Data Redis模块,我们可以轻松地在Java应用程序中操作Redis。 首先...

    SpringBoot 整合 Redis、mybatis 完整项目源码下载

    5. **RedisUtil工具类**: 封装通用的Redis操作,如设置、获取、删除键值对等,便于代码复用和管理。 **SpringBoot整合MyBatis** 1. **添加依赖**: 在`pom.xml`文件中添加MyBatis和MyBatis-Spring-Boot-Starter依赖...

    springboot demo

    3. 创建 mapper 接口和对应的 XML 映射文件,实现 SQL 查询和操作。 4. 使用 `@Mapper` 注解标记 mapper 接口,Spring Boot 会自动扫描并注入。 5. 在主应用类或配置类中启用 Mybatis 配置,使用 `@EnableMybatis` ...

Global site tag (gtag.js) - Google Analytics