如何更新 java 中文本文件的特定部分?

How can I update specific parts of a text file in java?

该程序应该接收有关球员姓名、助攻、玩过的游戏、得分等的用户输入,并将其打印在 .txt 文件中。当 updateData();方法被调用 我希望能够向用户询问玩家姓名和他们想要更新的数据,然后我应该能够编辑文本的特定部分。我该怎么做呢?

主要Class

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;

public class TextReader {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("/Users/Coding/Desktop/myFile.txt").toAbsolutePath();
        try (Scanner scan = new Scanner(System.in);
             BufferedReader fileReader = new BufferedReader(new FileReader(String.valueOf(path)));
             BufferedWriter fileWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {

            Reader reader = new Reader(scan, path, fileWriter, fileReader);
            reader.menu();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}



Reader Class

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

public class Reader {

    Path path;
    Scanner scan;
    BufferedWriter fileWriter;
    BufferedReader fileReader;


    Reader(Scanner scan, Path path, BufferedWriter fileWriter, BufferedReader fileReader) {

        this.scan = scan;
        this.path = path;
        this.fileWriter = fileWriter;
        this.fileReader = fileReader;
    }

    public void menu() throws IOException {
        String task;

        do{
            System.out.print("What would you like to do today?: ");
            task = scan.nextLine();
            switch (task) {
                case "1":
                    addData();
                    break;
                case "2":
                    updateData();
                    break;
                case "6":
                    System.out.println("Goodbye!");
                    System.exit(0);
            }
        }while(!task.equals("6"));


    }

    void addData() throws IOException {
        boolean cont;

        DateTimeFormatter log = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        LocalDateTime time = LocalDateTime.now();
        String logTime = log.format(time);

        do try {
            System.out.print("Enter Name of Player: ");
            String playerName = scan.nextLine();

            System.out.print("Enter Number of Games Played: ");
            int gamesPlayed = Integer.parseInt(scan.nextLine());

            System.out.print("Enter Number of Goals Made: ");
            int goals = Integer.parseInt(scan.nextLine());

            System.out.print("Enter Number of Assists Made: ");
            int assists = Integer.parseInt(scan.nextLine());

            System.out.print("Enter Number of Points Scored: ");
            int points = Integer.parseInt(scan.nextLine());

            System.out.print("Enter Number of Saves Made: ");
            int saves = Integer.parseInt(scan.nextLine());

            System.out.print("Enter Number of Shots Made: ");
            int shotsOnGoal = Integer.parseInt(scan.nextLine());

            fileWriter.write(
                    playerName + " " + gamesPlayed + " " + goals + " " +
                            assists + " " + points + " " + saves + " " + shotsOnGoal + " (" + logTime + ") \n");
            cont = false;
        } catch(NumberFormatException e){
            System.out.println("Enter Valid Input");
            cont = true;
        }while(cont);


    }

    void updateData() throws IOException {
        System.out.print("Enter Player Name To Edit Data: ");
        String playerName = scan.nextLine();

        System.out.print("Enter Stat You Want To Change: ");
        String stat = scan.nextLine().toLowerCase().trim();

        if(fileReader.readLine().contains(playerName)){
            String statSearch = fileReader.readLine();
            

            }
        }

    }


}


文本文件格式:

名称 GP G A P S S%

鲍比 2 3 6 14 7 50

乔治 1 3 14 2 9 23

因此,如果用户想要编辑姓名:George,键入:Assists,则只会编辑 Georges 姓名旁边的值 14

我曾尝试使用 if 语句在文本中找到字符串并将其附加,但我无法弄清楚如何只更改指定的数字而不更改找到的所有数字。例如:如果在上面的示例中附加了 14,则两个都将被更改,而不是一个

如果您获准参与此项目(即,不是学校作业),我建议使用 JSON、YAML 或 XML。推荐使用这些类型文件的 Java 库太多,但您可以搜索“Java JSON 库”,例如。

首先,需要解决一些问题...

Scanner scan = new Scanner(System.in); 放在 try-with-resource 中不是好的做法。它将自动关闭 System.in 并且在您的 Reader class 中使用后将无法使用。相反,只需这样做:

Scanner scan = new Scanner(System.in);
Reader reader = new Reader(scan, path, fileWriter, fileReader);

或者,更好的是,不要将它传递给构造函数,而只是在构造函数中将 scan 设置为 this.scan = new Scanner(System.in);

接下来,对于 fileReader,您可以像对 fileWriter 一样进行初始化:

BufferedReader fileReader = Files.newBufferedReader(path, StandardCharsets.UTF_8);

接下来,这一行:

BufferedWriter fileWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8)

每次这个程序运行,这一行都会把文件覆盖为空,这可能不是你想要的。您可以添加 StandardOpenOption.APPEND,但这意味着您只会写入文件末尾。

更新数据时,您还会遇到需要“下推”更新后的所有数据的问题。例如:

Bobby 1 2 3 4 5
Fred 1 2 3 4 5

如果您将名称 Bobby 更改为更长的名称,例如 Mr. President,那么它将覆盖其后的数据。

虽然有不同的选择,但最好和最简单的方法是只读取整个文件并将每一位数据存储在 class(名称、分数等)中,然后关闭 fileReader。

然后当用户更新一些数据时,更改 class 中的数据(实例变量),然后将所有数据写入文件。

这是一些伪代码:

class MyProg {
  // This could be a Map/HashMap instead.
  // See updateData().
  public List<Player> players = new ArrayList<>();

  public void readData(String filename) throws IOException {
    Path path = Paths.get(filename);
    
    try(BufferedReader fileReader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
      // Read each Player (using specific format)
      // and store in this.players
    }
  }

  public void writeData(String filename) throws IOException {
    Path path = Paths.get(filename);

    try(BufferedWriter fileWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
      // Write each Player from this.players in specific format
    }
  }

  public void updateData() {
    // 1. Find user-requested Player from this.players
    // 2. Update that specific Player class
    // 3. Call writeData()
    
    // If you are familiar with Maps, then it would be faster
    // to use a Map/HashMap with the key being the player's name.
  }
}

class Player {
  public String name;
  public int games;
  public int goals;
  //...
}