在Java中,如何覆盖文件中某行的特定部分



我有一个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示例

没有更好的解决方案,因为这取决于平台。更具体地说,它取决于所使用的文件系统,例如NTFSFAT32等等。
通常,他们通过将文件拆分为几个包来存储文件。然后,这些包会保存在你的硬盘上,它会把它们放在最适合的地方。文件系统会在master table中保存一个指向文件的每个启动包的指针。然后,每个包都保存一个指向下一个包的指针,依此类推,直到到达EOF

你看,在不改变以前的一切的情况下,很容易改变中间的一些东西。但是您可能需要更改后面的内容,因为您无法控制OS如何将新数据拆分为包。如果您进入非常低级别,您可以控制单个包并注入数据,而无需更改之后的所有内容。但我认为您不想这样做:)

不幸的是,除了将所有文件数据加载到某个可变对象中,然后将其全部写回文件之外,(据我所知)真的没有办法做到这一点。

Files类提供了一种将整个文件读取到List 中的方便方法


正如@Zabuza在评论中提到的,Java提供了一个名为RandomAccessFile的类,它可以导航到文件中的特定位置并覆盖字节。你可能感兴趣的方法是:

  • getFilePointer()-返回当前文件偏移量
  • seek(long pos)-将文件偏移量提前pos
  • write(byte[] b)-将b写入当前文件位置

希望这能帮助

相关内容

  • 没有找到相关文章

最新更新