因為工作上有對Properties文件進行修改屬性值的操作,於是寫了一個RandomAccessFile的擴展類,可以在文件指定位置插入內容、刪除指定位置之後自定義大小的內容、替換內容。
附上代碼:
/**
* RandomAccessFile的擴展類
* 新增了在文件指定位置插入內容、刪除指定位置之後自定義大小的內容、替換內容等功能
* @author objcfeng
*/
public class RandomAccessFileExt extends RandomAccessFile {
public RandomAccessFileExt(String name, String mode) throws FileNotFoundException {
super(name, mode);
}
public RandomAccessFileExt(File file, String mode) throws FileNotFoundException {
super(file, mode);
}
/**
* 功能:在文件指定位置插入內容
* 實現過程:
* 將添加位置之後的文件內容使用字節數組保存,
* 向文件寫入插入的內容,再寫入字節數組中的內容
* 注意:
* 調用此方法後後將文件指針修改到文件結尾
*
* @param bytes 添加的內容
* @param off 添加的位置,按字節算而不是字符
*/
public void insert(byte[] bytes, int off) throws IOException {
byte[] dst = getTheRest(off);
write(bytes);
write(dst);
seek(off);
}
/**
* 功能:刪除指定位置之後自定義大小的內容
* 實現過程:
* 使用字節數組記錄off+len之後的內容,
* 再把字節數組寫入off開始的位置,
* 相當於把off+len之後的內容覆蓋在off位置上
* 最後把文件長度設為原長度-len
*
* @param off 刪除的位置
* @param len 刪除的字節數
*/
public void delete(int off, int len) throws IOException {
byte[] theRest = getTheRest(off + len);
seek(off);
write(theRest);
setLength(length() - len);
seek(off);
}
/**
* 功能:替換內容
* 實現過程:先在指定位置刪除內容再插入內容
* @param bytes 替換內容
* @param off 替換起始點
* @param len 替換長度
*/
public void replace(byte[] bytes,int off,int len) throws IOException {
delete(off, len);
insert(bytes,off);
}
/**
* 功能:獲取off之後剩餘的內容,存儲在byte數組中
* 注意:
* 此方法適用於小文件
*
* @param off 位置
* @return 存儲文件剩餘的內容的字節數組
*/
private byte[] getTheRest(int off) throws IOException {
long fileLength = length();
if (fileLength > Integer.MAX_VALUE) {
throw new RuntimeException("文件太大,不支持插入數據");
}
//將添加位置之後的文件內容使用字節數組保存
byte[] dst = new byte[(int) fileLength - off];
//因為readFully方法是從文件指針之後開始讀取的,所以先將指針指向off
seek(off);
readFully(dst);
//將指針指回off位置
seek(off);
return dst;
}
}
順便也附上操作Properties文件的工具類:
/**
* properties配置文件工具類
* 單例
* @author objcfeng
*/
public class PropertiesUtil {
private String propertiesName;
private static volatile PropertiesUtil propertiesUtil;
private PropertiesUtil(String propertiesName) {
this.propertiesName = propertiesName;
}
/**
* 獲取工具類實例
* @param propertiesName propertiesName文件名,無需後綴
* @return 工具類實例
*/
public static PropertiesUtil getInstance(String propertiesName) {
if (propertiesUtil == null) {
synchronized (PropertiesUtil.class) {
if (propertiesUtil == null) {
propertiesUtil = new PropertiesUtil(propertiesName);
}
}
}
return propertiesUtil;
}
/**
* 根據鍵獲取值,若值為空,則返回空字符串""
* @param key 鍵
* @return 值
*/
public String getPropertyValue(String key) {
//properties文件名
ResourceBundle resourceBundle = ResourceBundle.getBundle(propertiesName);
return resourceBundle.getString(key);
}
/**
* 修改屬性,若value長度小於原值的長度,則
* @param key 鍵
* @param value 值
*/
public void setPropertyValue(String key, String value) {
//使用隨機訪問流
RandomAccessFileExt randomAccessFile = null;
//文件路徑
final String path = "src/main/resources/" + propertiesName + ".properties";
try {
//採用讀寫模式
randomAccessFile = new RandomAccessFileExt(new File(path), "rw");
//讀取到的行
String line;
//記錄上一次
long filePointer = 0;
while ((line = randomAccessFile.readLine()) != null) {
//將讀取到的字符串以=分隔,得到的數組有如下情況 [key,value]、[comment]、[key]
String[] kv = line.split("=");
//獲取key
String k = kv[0];
if (k.trim().equals(key)) {
randomAccessFile.seek(filePointer);
String writeKV = k + "=" + value;
//替換這一行
randomAccessFile.replace(writeKV.getBytes(), (int) filePointer, line.getBytes().length);
break;
}
filePointer = randomAccessFile.getFilePointer();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (randomAccessFile != null) {
randomAccessFile.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}