Java 替换文本文件中的行

38

如何替换文本文件中的一行?

我有一个字符串,例如:

Do the dishes0

并且我希望用以下内容进行更新:

Do the dishes1

我该如何实现这个?

(反之亦然)

ActionListener al = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JCheckBox checkbox = (JCheckBox) e.getSource();
                    if (checkbox.isSelected()) {
                        System.out.println("Selected");
                        String s = checkbox.getText();
                        replaceSelected(s, "1");
                    } else {
                        System.out.println("Deselected");
                        String s = checkbox.getText();
                        replaceSelected(s, "0");
                    }
                }
            };

public static void replaceSelected(String replaceWith, String type) {

}

顺便提一下,我想仅替换已读取的那行内容,而不是整个文件。


9
阅读整个文件。更改该行。写入整个文件。 - nhgrif
我已经尝试使用RandomAccessFile、BufferedReader和BufferedWriters来实现这个目的。我真的需要一些为我的特定目的设计的代码。每次尝试时,我似乎都做错了什么。 - Eveno
现在早已不复存在。正如我所说,我尝试了许多不同的方法。将其存储在临时数组中...创建一个新文件...但这些都没有起作用。 - Eveno
你需要回到实现这些方法,当你遇到困难时,请回到这里并发帖。 - nhgrif
请贴出你的代码。不要期望别人为你编写代码。如果你发表了诚恳的尝试,我们很乐意评论它有什么问题,什么是正确的,以及你需要做哪些改变来使其工作。但是,如果你不能展示你的努力,那么这里没有人会花费太多精力来帮助你。 - Dawood ibn Kareem
显示剩余2条评论
8个回答

51

在底部,我有一个用于替换文件中行的通用解决方案。但首先,这里是针对具体问题的答案。帮助函数:

public static void replaceSelected(String replaceWith, String type) {
    try {
        // input the file content to the StringBuffer "input"
        BufferedReader file = new BufferedReader(new FileReader("notes.txt"));
        StringBuffer inputBuffer = new StringBuffer();
        String line;

        while ((line = file.readLine()) != null) {
            inputBuffer.append(line);
            inputBuffer.append('\n');
        }
        file.close();
        String inputStr = inputBuffer.toString();

        System.out.println(inputStr); // display the original file for debugging

        // logic to replace lines in the string (could use regex here to be generic)
        if (type.equals("0")) {
            inputStr = inputStr.replace(replaceWith + "1", replaceWith + "0"); 
        } else if (type.equals("1")) {
            inputStr = inputStr.replace(replaceWith + "0", replaceWith + "1");
        }

        // display the new file for debugging
        System.out.println("----------------------------------\n" + inputStr);

        // write the new string with the replaced line OVER the same file
        FileOutputStream fileOut = new FileOutputStream("notes.txt");
        fileOut.write(inputStr.getBytes());
        fileOut.close();

    } catch (Exception e) {
        System.out.println("Problem reading file.");
    }
}

然后将其称为:

public static void main(String[] args) {
    replaceSelected("Do the dishes", "1");   
}

洗碗1
喂狗0
打扫房间1


请注意,如果文本文件内容为:

洗碗1
喂狗0
打扫房间1

你使用方法 replaceSelected("洗碗", "1"); 将不会改变文件。


由于这个问题比较具体,我会在这里添加一个更一般化的解决方案供未来读者参考(基于标题)。

// read file one line at a time
// replace line as you read the file and store updated lines in StringBuffer
// overwrite the file with the new lines
public static void replaceLines() {
    try {
        // input the (modified) file content to the StringBuffer "input"
        BufferedReader file = new BufferedReader(new FileReader("notes.txt"));
        StringBuffer inputBuffer = new StringBuffer();
        String line;

        while ((line = file.readLine()) != null) {
            line = ... // replace the line here
            inputBuffer.append(line);
            inputBuffer.append('\n');
        }
        file.close();

        // write the new string with the replaced line OVER the same file
        FileOutputStream fileOut = new FileOutputStream("notes.txt");
        fileOut.write(inputBuffer.toString().getBytes());
        fileOut.close();

    } catch (Exception e) {
        System.out.println("Problem reading file.");
    }
}

当您完成流操作时,您需要确保关闭它们。 - Sammy Guergachi
1
@SammyGuergachi 你是对的。我总是变得懒惰,不去做那件事。如果你建议一个编辑,我会批准它。 - Michael Yaworski
为了最佳实践,您还应该使用StringBuilder而不是“while(...)input + = line +'\n'”。 https://dev59.com/JnI_5IYBdhLWcg3wFu_L - user2602807
1
考虑将“String input”替换为“StringBuilder input”,并使用它作为输入.append(line + "\n);”。字符串是不可变对象,而StringBuilder则不是。因此,每次修改字符串时都会创建一个新对象。完成数据后,请使用“input.toString()”获取字符串。 - Redauser
@Redauser replace方法只在inputStr上调用一次,因此切换到StringBuilder不会减少创建的对象数量。 - Kröw
显示剩余5条评论

49

自Java 7开始,这非常容易且直观。

List<String> fileContent = new ArrayList<>(Files.readAllLines(FILE_PATH, StandardCharsets.UTF_8));

for (int i = 0; i < fileContent.size(); i++) {
    if (fileContent.get(i).equals("old line")) {
        fileContent.set(i, "new line");
        break;
    }
}

Files.write(FILE_PATH, fileContent, StandardCharsets.UTF_8);

基本上你需要将整个文件读取到一个List中,编辑该列表,最后将列表写回文件。

FILE_PATH表示文件的Path


建议:还要解释一下如何重要地写入临时文件,然后将该文件移动到第一个文件的位置,以使更改具有原子性。(欢迎来到StackOverflow!) - rrauenza
1
@rrauenza 这并不是必要的,而且大多数情况下都会过度杀伤力。话虽如此,用几行代码实现肯定不难。如果你想证明这一点,为什么不自己回答(或建议编辑)呢? - Tuupertunut
我需要参考http://www.java2s.com/Tutorials/Java/java.nio.file/Files/Java_Files_readAllLines_Path_path_Charset_cs_.htm,因为上面的答案不完整。 - vikramvi
2
以上答案出现了错误: 类型Files中的方法write(Path, byte[], OpenOption...)不适用于参数(Path, byte[], Charset)。 - Max Alexander Hanna
无论如何,第二个参数不应该是 byte[]。看起来你将 "fileContent" 列表作为 byte[] 而不是 List<String> 或者以其他方式无效。 - Tuupertunut
显示剩余3条评论

3

分享 Java Util Stream 的经验

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;    

public static void replaceLine(String filePath, String originalLineText, String newLineText) {
            Path path = Paths.get(filePath);
            // Get all the lines
            try (Stream<String> stream = Files.lines(path, StandardCharsets.UTF_8)) {
                // Do the line replace
                List<String> list = stream.map(line -> line.equals(originalLineText) ? newLineText : line)
                        .collect(Collectors.toList());
                // Write the content back
                Files.write(path, list, StandardCharsets.UTF_8);
            } catch (IOException e) {
                LOG.error("IOException for : " + path, e);
                e.printStackTrace();
            }
        }

使用方法

replaceLine("test.txt", "Do the dishes0", "Do the dishes1");

2

我本来要回答这个问题。但是我看到它被标记为与这个问题重复,而我已经编写了代码,所以我要在这里发布我的解决方案。

请注意,您必须重新编写文本文件。首先,我读取整个文件,并将其存储在一个字符串中。然后我将每一行存储为字符串数组的索引,例如第一行=数组索引0。然后我编辑对应于您要编辑的行的索引。完成后,我将数组中的所有字符串连接成单个字符串。然后将新字符串写入文件,覆盖旧内容。不用担心丢失旧内容,因为已经使用编辑写入了它们。下面是我使用的代码。

public class App {

public static void main(String[] args) {

    String file = "file.txt";
    String newLineContent = "Hello my name is bob";
    int lineToBeEdited = 3;

    ChangeLineInFile changeFile = new ChangeLineInFile();
    changeFile.changeALineInATextFile(file, newLineContent, lineToBeEdited);



}

}

还有这个类。

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

public class ChangeLineInFile {

public void changeALineInATextFile(String fileName, String newLine, int lineNumber) {
        String content = new String();
        String editedContent = new String();
        content = readFile(fileName);
        editedContent = editLineInContent(content, newLine, lineNumber);
        writeToFile(fileName, editedContent);

    }

private static int numberOfLinesInFile(String content) {
    int numberOfLines = 0;
    int index = 0;
    int lastIndex = 0;

    lastIndex = content.length() - 1;

    while (true) {

        if (content.charAt(index) == '\n') {
            numberOfLines++;

        }

        if (index == lastIndex) {
            numberOfLines = numberOfLines + 1;
            break;
        }
        index++;

    }

    return numberOfLines;
}

private static String[] turnFileIntoArrayOfStrings(String content, int lines) {
    String[] array = new String[lines];
    int index = 0;
    int tempInt = 0;
    int startIndext = 0;
    int lastIndex = content.length() - 1;

    while (true) {

        if (content.charAt(index) == '\n') {
            tempInt++;

            String temp2 = new String();
            for (int i = 0; i < index - startIndext; i++) {
                temp2 += content.charAt(startIndext + i);
            }
            startIndext = index;
            array[tempInt - 1] = temp2;

        }

        if (index == lastIndex) {

            tempInt++;

            String temp2 = new String();
            for (int i = 0; i < index - startIndext + 1; i++) {
                temp2 += content.charAt(startIndext + i);
            }
            array[tempInt - 1] = temp2;

            break;
        }
        index++;

    }

    return array;
}

private static String editLineInContent(String content, String newLine, int line) {

    int lineNumber = 0;
    lineNumber = numberOfLinesInFile(content);

    String[] lines = new String[lineNumber];
    lines = turnFileIntoArrayOfStrings(content, lineNumber);

    if (line != 1) {
        lines[line - 1] = "\n" + newLine;
    } else {
        lines[line - 1] = newLine;
    }
    content = new String();

    for (int i = 0; i < lineNumber; i++) {
        content += lines[i];
    }

    return content;
}

private static void writeToFile(String file, String content) {

    try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"))) {
        writer.write(content);
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static String readFile(String filename) {
    String content = null;
    File file = new File(filename);
    FileReader reader = null;
    try {
        reader = new FileReader(file);
        char[] chars = new char[(int) file.length()];
        reader.read(chars);
        content = new String(chars);
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    return content;
}

}

2

如果替换内容长度不同:

  1. 读取文件,直到找到要替换的字符串。
  2. 将要替换的文本后面的部分全部读入内存。
  3. 将文件截断为要替换的部分的开头。
  4. 写入替换内容。
  5. 从步骤2中写入文件的剩余部分。

如果替换内容长度相同:

  1. 读取文件,直到找到要替换的字符串。
  2. 将文件位置设置为要替换的部分的开头。
  3. 写入替换内容,覆盖文件的一部分。

这是在您提出的问题的约束条件下可以得到的最佳解决方案。但是,至少在此示例中,替换的字符串长度相同,因此第二种方法应该可行。

还要注意:Java字符串是Unicode文本,而文本文件是带有某些编码的字节。如果编码是UTF8,并且您的文本不是Latin1(或纯7位ASCII),则必须检查编码字节数组的长度,而不是Java字符串的长度。


1
        //Read the file data
        BufferedReader file = new BufferedReader(new FileReader(filepath));
        StringBuffer inputBuffer = new StringBuffer();
        String line;

        while ((line = file.readLine()) != null) {
            inputBuffer.append(line);
            inputBuffer.append('\n');
        }
        file.close();
        String inputStr = inputBuffer.toString();


        // logic to replace lines in the string (could use regex here to be generic)

            inputStr = inputStr.replace(str, " ");
        //'str' is the string need to update in this case it is updating with nothing

        // write the new string with the replaced line OVER the same file
        FileOutputStream fileOut = new FileOutputStream(filer);
        fileOut.write(inputStr.getBytes());
        fileOut.close();

0

如何替换字符串 :) 就像我所做的那样 第一个参数将是文件名,第二个目标字符串,第三个是要替换目标字符串的字符串

public class ReplaceString{
      public static void main(String[] args)throws Exception {
        if(args.length<3)System.exit(0);
        String targetStr = args[1];
        String altStr = args[2];
        java.io.File file = new java.io.File(args[0]);
        java.util.Scanner scanner = new java.util.Scanner(file);
        StringBuilder buffer = new StringBuilder();
        while(scanner.hasNext()){
          buffer.append(scanner.nextLine().replaceAll(targetStr, altStr));
          if(scanner.hasNext())buffer.append("\n");
        }
        scanner.close();
        java.io.PrintWriter printer = new java.io.PrintWriter(file);
        printer.print(buffer);
        printer.close();
      }
    }

0

我会调查一下。谢谢。你介意发一个快速示例,以便我了解整体情况吗? - Eveno
你可以在Java教程中找到你需要的一切。 - MarsAtomic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接