实现对properties文件的有序读写

最近遇到一项需求,要求把properties文件中的内容读取出来供用户修改,修改完后需要再重新保存到properties文件中。很简单的需求吧,可问题是Properties是继承自HashTable的,直接通过keySet()、keys()或entrySet()方法对Properties中的元素进行遍历时取出来的内容顺序与properties文件中的顺序不一致,这是问题一;问题二是就算取出来的时候是有序的,保存到文件中时又是无序的了。

当然,解决这两个问题的方法有很多。我最终采用的方法是自定义一个PropertiesUtil类,该类继承自Properties。PropertiesUtil提供一个返回由key按照存入顺序组成的List的方法,getKeyList(),这样问题一就解决了。那如何保证getKeyList()方法返回的就是有序的key组成的集合呢?我查看了一下Properties方法的源码,发现其setProperty()方法实际上就是调用了父类HashTable的put()方法,其次Properties在从文件中加载内容时是按照文件顺序进行读取,然后调用父类HashTable的put()方法进行储存。所以问题的解决办法就是PropertiesUtil持有一个私有的可以有序存储key的集合,然后重写父类的put()方法,在方法体中照常通过super.put()进行属性的存储,同时将key添加到存储key的集合中。

Properties提供有save()方法和store()方法可以将当前对象的内容存放到指定的输出流中,但它们的底层逻辑都是一样的。通过调用keys()方法获取一个Enumeration,然后对该Enumeration进行遍历,依次将对应的key和value写入到输出流中,所以要保证写入是有序的,就要保证遍历keys()返回的Enumeration时取出的元素key是有序的。所以解决方法是重写keys()方法,保证遍历返回的Enumeration时得到的key是有序的。完整代码如下:

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

public class PropertiesUtil extends Properties {

    private static final long serialVersionUID = 1L;

    private List<Object> keyList = new ArrayList<Object>();

    /**
     * 默认构造方法
     */
    public PropertiesUtil() {

    }

    /**
     * 从指定路径加载信息到Properties
     * @param path
     */
    public PropertiesUtil(String path) {
        try {
            InputStream is = new FileInputStream(path);
            this.load(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("指定文件不存在!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 重写put方法,按照property的存入顺序保存key到keyList,遇到重复的后者将覆盖前者。
     */
    @Override
    public synchronized Object put(Object key, Object value) {
        this.removeKeyIfExists(key);
        keyList.add(key);
        return super.put(key, value);
    }

    /**
     * 重写remove方法,删除属性时清除keyList中对应的key。
     */
    @Override
    public synchronized Object remove(Object key) {
        this.removeKeyIfExists(key);
        return super.remove(key);
    }

    /**
     * keyList中存在指定的key时则将其删除
     */
    private void removeKeyIfExists(Object key) {
        keyList.remove(key);
    }

    /**
     * 获取Properties中key的有序集合
     * @return
     */
    public List<Object> getKeyList() {
        return keyList;
    }

    /**
     * 保存Properties到指定文件,默认使用UTF-8编码
     * @param path 指定文件路径
     */
    public void store(String path) {
        this.store(path, "UTF-8");
    }

    /**
     * 保存Properties到指定文件,并指定对应存放编码
     * @param path 指定路径
     * @param charset 文件编码
     */
    public void store(String path, String charset) {
        if (path != null && !"".equals(path)) {
            try {
                OutputStream os = new FileOutputStream(path);
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, charset));
                this.store(bw, null);
                bw.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            throw new RuntimeException("存储路径不能为空!");
        }
    }

    /**
     * 重写keys方法,返回根据keyList适配的Enumeration,且保持HashTable keys()方法的原有语义,
     * 每次都调用返回一个新的Enumeration对象,且和之前的不产生冲突
     */
    @Override
    public synchronized Enumeration<Object> keys() {
        return new EnumerationAdapter<Object>(keyList);
    }

    /**
     * List到Enumeration的适配器
     */
    private class EnumerationAdapter<T> implements Enumeration<T> {
        private int index = 0;
        private final List<T> list;
        private final boolean isEmpty;

        public EnumerationAdapter(List<T> list) {
            this.list = list;
            this.isEmpty = list.isEmpty();
        }

        public boolean hasMoreElements() {
            //isEmpty的引入是为了更贴近HashTable原有的语义,在HashTable中添加元素前调用其keys()方法获得一个Enumeration的引用,
            //之后往HashTable中添加数据后,调用之前获取到的Enumeration的hasMoreElements()将返回false,但如果此时重新获取一个
            //Enumeration的引用,则新Enumeration的hasMoreElements()将返回true,而且之后对HashTable数据的增、删、改都是可以在
            //nextElement中获取到的。
            return !isEmpty && index < list.size();
        }

        public T nextElement() {
            if (this.hasMoreElements()) {
                return list.get(index++);
            }
            return null;
        }

    }

}
时间: 2024-11-01 18:07:31

实现对properties文件的有序读写的相关文章

C#实现对Word文件读写[转]

手头上的一个项目报表相对比较简单,所以报表打印采用VBA引擎,通过定制Word模版,然后根据模版需要填充数据,然后OK,打印即可. 实现方法:首先需要引用VBA组建,我用的是Office2003 Professional,Dll版本号为Microsoft Word11.0 另外当然还需要引用Interop.Word.Dll. 代码如下: ///#region 打开Word文档,并且返回对象wDoc,wDoc /// /// 打开Word文档,并且返回对象wDoc,wDoc /// /// 完整W

php如何利用python实现对pdf文件的操作(读写、合并分割)

php如何利用python实现对pdf文件的操作 需求:在PHP里实现了把8.pdf的前4页pdf文件截取出来生成新的pdf文件. 详细步骤如下: 1. 安装python第三方库PyPDF2 前提:python必须是3.x版本以上,必要时需要升级pip3,命令如下:pip3 install --upgrade pipPyPDF 自 2010年 12月开始就不在更新了,PyPDF2 接棒 PyPDF, 在此使用PyPDF2. 安装命令:pip install PyPDF2 2.编写python脚本

Windows下使用scapy+python2.7实现对pcap文件的读写操作

scapy在linux环境中对pcap文件进行操作非常方便,但在windows下,特别是在python2.7环境下却会碰到各种各样的依赖包无法使用的问题,最明显的可能就属dnet和pcap的python依赖包了,因为scapy的conf.use_pcap和conf.use_dnet在windows环境下无法进行配置,在scapy\arch\windows\__init__.py中都被强行置为1了,也就是必须使用pcap和dnet依赖包.具体代码如下所示 from scapy.sendrecv i

用.net dynamic实现对JSON文件的读写操作

现在VS2015支持生成Codorva程序了.在Javascript下,JSON格式使用的很多,但是.net framework下,使用起来很不方便,不能像Javascript那么随意.有一个专门的类库Newtonsoft.Json可以使用,但是公司比较正规,不好随便乱用三方的库,而且这个库也比较大,比较重,学习和使用成本都比较高. 后来,我想到了,现在的.net是支持dynamic关键字的,是不是可以利用它来方便的对JSON进行操作.下面是我写的代码,以供参考. using System; u

linux下使用libxml2实现对xml文件的读取及查询

由于项目需要,这两天在用C++做XML文件解析的工作.在linux下有个很方便的操作xml文件的库——libxml2,它提供了一套创建和查询xml文件的C语言的接口.这篇博客主要介绍如何使用libxml2读取并解析xml文件. 下载并安装libxml2 下载地址:ftp://xmlsoft.org/libxml2/ 下载最新的版本,我下载的是libxml2-2.9.1.tar.gz.下载后将文件解压到合适的位置,进入解压后的目录. 编译命令非常简单(注意:如果configure文件没有可执行权限

基于Python实现对PDF文件的OCR识别

http://www.jb51.net/article/89955.htm https://pythontips.com/2016/02/25/ocr-on-pdf-files-using-python/ 大家可能听说过使用Python进行OCR识别操作.在Python中,最出名的库便是Google所资助的tesseract.利用tesseract可以很轻松地对图像进行识别.现在问题来了,如果想对一个PDF文档进行OCR识别,该怎么做呢?下面一起来看看. 最近在做一个项目的时候,需要将PDF文件

让你轻松实现对PDF文件的编辑修改

对于经常使用的word.ppt等格式的文档我们直接打开就能够进行编辑修改,而PDF这种格式文档很多人却都不怎么会进行编辑修改.这是因为很多人不知道阅读器只能用来查看而不能修改文档.那如何编辑修改PDF页面内容呢? 一般普通的文字类型的PDF文件都可以通过PDF编辑软件来修改编辑.所以要编辑PDF文件就需要PDF编辑器而不是用阅读器来打开PDF. 打开文档后,选择工具栏上的编辑内容工具,然后就可以在页面选择对象进行编辑了. 文字的操作和PPT一样,都是在对应的文本框中进行编辑的,可以选择添加文本工

java中实现对lib文件中的jar包快速buildpath

当我们把jar文件全部复制到lib后,如果一个一个去buildpath是很麻烦的,这里其实有小技巧的,我们点击第一个jar文件,然后按着shift,再点击最后一个jar文件,就可以实现全选jar包,然后右键-->buildpath即可.

Java实现对xml文件的增删改查

package com.HeiBeiEDU.test2; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.junit.Test; import org.w3c.dom.*; import org.xml.sax.SAXException; import javax.xml.parser