如何更新 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;
//...
}
该程序应该接收有关球员姓名、助攻、玩过的游戏、得分等的用户输入,并将其打印在 .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;
//...
}