我有一个csv
文件,其格式类似于id,text
。这里有一个例子:
helloText,How are you
goodbyeMessage,Some new text for a change
errorMessage,Oops something went wrong
例如,现在我想将goodbyeMessage
的文本部分(即Some new text for change
)编辑为See you later
生成的csv
应该是这样的:
helloText,How are you
goodbyeMessage,See you later
errorMessage,Oops something went wrong
我有可以写入文件的代码,但当代码完成执行时,这就是生成的csv
文件:
helloText,How are you
goodbyeMessage,Some new text for a change
errorMessage,Oops something went wronggoodbyeMessage,See you later
我知道发生这种情况是因为我将FileWriter的append
值设置为true
。如果我不这样做,一切都会被抹去。
我试过用FileWriter.newLine()
让它看起来更好,但这不是我想要实现的。我仍然希望文件中的行数相同。MyApp.java
public static void main(String[] args) throws FileNotFoundException, IOException {
PropsWriter pw = new PropsWriter("test_props.txt");
pw.updateElementText("goodbyeMessage", "See you later");
}
PropsWriter.java
/**
* Updates the text of a given element in the properties file.
*
* @param id The id of the element
* @param newText The text that will replace the original text.
*
* @throws IOException If I/O error occurs
*/
public void updateElementText(String id, String newText) throws IOException {
Assertions.checkNotNull(id, "Id must not be null.");
Assertions.checkNotNull(id, "Id must not be an empty string.");
File file = new File(pathName);
BufferedReader br = new BufferedReader(new FileReader(file));
BufferedWriter wr = new BufferedWriter(new FileWriter(file, true));
try {
String line;
while((line = br.readLine()) != null) {
if(line.contains(id)) {
//returns true
System.out.println("Is line there: " + line.contains(id));
//returns helloText
System.out.println("ID: " + extractId(line));
//returns How are you
System.out.println("TEXT: " + extractText(line));
//returns Some new text for a change
System.out.println("NEW_TEXT: " + newText);
// This is where I am trying to replace the old text
// with new text that came from the main method.
line = line.replaceAll(extractText(line), newText);
//wr.newLine();
wr.write(line);
}
}
} catch(IOException e) {
e.printStackTrace();
} finally {
wr.close();
}
}
/**
* Gets the id part of a line that is stored in the
* properties file.
*
* @param element The element the id is got from.
* @return String representation of the id.
*/
private static String extractId(String line) {
final int commaOccurence = getFirstCommaOccurrence(line);
return line.substring(0, commaOccurence);
}
/**
* Gets the text part of a line that is stored in the
* properties file.
*
* @param element The element the text is got from.
* @return String representation of the text.
*/
private static String extractText(String line) {
final int commaOccurence = getFirstCommaOccurrence(line);
return line.substring(commaOccurence + 1, line.length());
}
/**
* Gets the first occurrence of a comma in any given line of a text file.
* @param element
* @return
*/
private static int getFirstCommaOccurrence(String line) {
return line.indexOf(",");
}
你刚刚说过。不要将FileWriter
设置为true
(因为它只会添加新内容)。您需要读取整个文件,保存所有行(例如在List<String>
中)。然后操作数据。然后重写整个文本(例如,使用上述List<String>
)。
在上面的代码中,这将是第一个用false
:替换true
BufferedWriter wr = new BufferedWriter(new FileWriter(file, false));
第二步,始终写入文件,因为其他行会丢失:
if(line.contains(id)) {
...
line = line.replaceAll(extractText(line), newText);
}
wr.write(line);
但是,如果您有一个非常大的文件,并且不想重写所有行,那么您可以选择更低级的FileWriter
,如RandomAccessFile
。这个概念允许您在给定的位置开始文件操作,而无需重写该位置之前的所有内容。你可以搜索这条线(或者跳下去,如果你知道在哪里的话),做出改变。但是您需要重写更改后出现的所有内容。下面是一个用法示例:RandomAccessFile示例
没有更好的解决方案,因为这取决于平台。更具体地说,它取决于所使用的文件系统,例如NTFS
或FAT32
等等。
通常,他们通过将文件拆分为几个包来存储文件。然后,这些包会保存在你的硬盘上,它会把它们放在最适合的地方。文件系统会在master table
中保存一个指向文件的每个启动包的指针。然后,每个包都保存一个指向下一个包的指针,依此类推,直到到达EOF
。
你看,在不改变以前的一切的情况下,很容易改变中间的一些东西。但是您可能需要更改后面的内容,因为您无法控制OS
如何将新数据拆分为包。如果您进入非常低级别,您可以控制单个包并注入数据,而无需更改之后的所有内容。但我认为您不想这样做:)
不幸的是,除了将所有文件数据加载到某个可变对象中,然后将其全部写回文件之外,(据我所知)真的没有办法做到这一点。
Files
类提供了一种将整个文件读取到List
中的方便方法
正如@Zabuza在评论中提到的,Java提供了一个名为RandomAccessFile
的类,它可以导航到文件中的特定位置并覆盖字节。你可能感兴趣的方法是:
getFilePointer()
-返回当前文件偏移量seek(long pos)
-将文件偏移量提前pos
write(byte[] b)
-将b
写入当前文件位置
希望这能帮助