1 import java.io.BufferedWriter; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.OutputStreamWriter; 9 import java.util.ArrayList; 10 import java.util.Enumeration; 11 import java.util.List; 12 import java.util.Properties; 13 14 /** 15 * @Description:对输出的properties文件内容按key排序 18 */ 19 public class OrderedProperties extends Properties { 20 21 private static final long serialVersionUID = 1L; 22 23 private List<Object> keyList = new ArrayList<Object>(); 24 25 /** 26 * 默认构造方法 27 */ 28 public OrderedProperties() { 29 30 } 31 32 /** 33 * 从指定路径加载信息到Properties 34 * 35 * @param path 36 */ 37 public OrderedProperties(String path) { 38 try { 39 InputStream is = new FileInputStream(path); 40 this.load(is); 41 } catch (FileNotFoundException e) { 42 e.printStackTrace(); 43 throw new RuntimeException("指定文件不存在!"); 44 } catch (IOException e) { 45 e.printStackTrace(); 46 } 47 } 48 49 /** 50 * 重写put方法,按照property的存入顺序保存key到keyList,遇到重复的后者将覆盖前者。 51 */ 52 @Override 53 public synchronized Object put(Object key, Object value) { 54 this.removeKeyIfExists(key); 55 keyList.add(key); 56 return super.put(key, value); 57 } 58 59 /** 60 * 重写remove方法,删除属性时清除keyList中对应的key。 61 */ 62 @Override 63 public synchronized Object remove(Object key) { 64 this.removeKeyIfExists(key); 65 return super.remove(key); 66 } 67 68 /** 69 * keyList中存在指定的key时则将其删除 70 */ 71 private void removeKeyIfExists(Object key) { 72 keyList.remove(key); 73 } 74 75 /** 76 * 获取Properties中key的有序集合 77 * 78 * @return 79 */ 80 public List<Object> getKeyList() { 81 return keyList; 82 } 83 84 /** 85 * 保存Properties到指定文件,默认使用UTF-8编码 86 * 87 * @param path 指定文件路径 88 */ 89 public void store(String path) { 90 this.store(path, "UTF-8"); 91 } 92 93 /** 94 * 保存Properties到指定文件,并指定对应存放编码 95 * 96 * @param path 指定路径 97 * @param charset 文件编码 98 */ 99 public void store(String path, String charset) { 100 if (path != null && !"".equals(path)) { 101 try { 102 OutputStream os = new FileOutputStream(path); 103 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, charset)); 104 this.store(bw, null); 105 bw.close(); 106 } catch (FileNotFoundException e) { 107 e.printStackTrace(); 108 } catch (IOException e) { 109 e.printStackTrace(); 110 } 111 } else { 112 throw new RuntimeException("存储路径不能为空!"); 113 } 114 } 115 116 /** 117 * 重写keys方法,返回根据keyList适配的Enumeration,且保持HashTable keys()方法的原有语义, 118 * 每次都调用返回一个新的Enumeration对象,且和之前的不产生冲突 119 */ 120 @Override 121 public synchronized Enumeration<Object> keys() { 122 return new EnumerationAdapter<Object>(keyList); 123 } 124 125 /** 126 * List到Enumeration的适配器 127 */ 128 private static class EnumerationAdapter<T> implements Enumeration<T> { 129 private int index = 0; 130 private final List<T> list; 131 private final boolean isEmpty; 132 133 public EnumerationAdapter(List<T> list) { 134 this.list = list; 135 this.isEmpty = list.isEmpty(); 136 } 137 138 public boolean hasMoreElements() { 139 // isEmpty的引入是为了更贴近HashTable原有的语义,在HashTable中添加元素前调用其keys()方法获得一个Enumeration的引用, 140 // 之后往HashTable中添加数据后,调用之前获取到的Enumeration的hasMoreElements()将返回false,但如果此时重新获取一个 141 // Enumeration的引用,则新Enumeration的hasMoreElements()将返回true,而且之后对HashTable数据的增、删、改都是可以在 142 // nextElement中获取到的。 143 return !isEmpty && index < list.size(); 144 } 145 146 public T nextElement() { 147 if (this.hasMoreElements()) { 148 return list.get(index++); 149 } 150 return null; 151 } 152 153 } 154 155 }