如何在java中更新文本文件的特定部分?
这个程序应该接收关于球员姓名、助攻、比赛、得分等的用户输入,并将其打印在一个 .txt 文件中.当 updateData();方法被调用我希望能够向用户询问玩家姓名以及他们想要更新的数据,然后我应该能够编辑文本的特定部分.我该怎么做?
This program is supposed to take in user input about a players name, assists, games played, scores, etc and print it in a .txt file. When the updateData(); method is called I want to be able to ask the user for the players name and what data they want to update, then i should be able to edit that specific part of the text. how could i go about doing this?
主类
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();
}
}
}
读者类
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%
Name GP G A P S S%
鲍比 2 3 6 14 7 50
Bobby 2 3 6 14 7 50
乔治 1 3 14 2 9 23
George 1 3 14 2 9 23
所以如果用户想编辑 Name: George,输入:Assists,Georges name 旁边的值 14 将被编辑
So if the user wanted to edit Name: George, type: Assists, the value 14 beside Georges name only would be edited
我曾尝试使用 if 语句来定位文本中的字符串并附加它,但我无法弄清楚如何只更改指定的数字而不更改找到的所有数字.例如:如果在上面的例子中附加了 14 两个都将被更改而不是一个
I have tried using an if statement to locate the string in the text and append it but I could not figure out how to only change the specified number without changing all the numbers found. Ex: if in the example above 14 is appended both would be changed instead of the one
如果您被允许参与此项目(即,不是学校作业),我建议您使用 JSON、YAML 或 XML.有太多的 Java 库推荐用于使用这些类型的文件,但您可以搜索Java JSON 库";例如.
If you are allowed for this project (i.e., not a school assignment), I recommend using JSON, YAML, or XML. There are too many Java libraries to recommend for using these types of files, but you can search "Java JSON library" for example.
首先,需要解决一些问题...
First, need to address some issues...
将 Scanner scan = new Scanner(System.in);
放在 try-with-resource 中不是一个好习惯.它将自动关闭 System.in
并且在您的 Reader
类中使用后将无法使用.相反,只需这样做:
It's not good practice to put Scanner scan = new Scanner(System.in);
in a try-with-resource. It will auto-close System.in
and won't be useable after being used in your Reader
class. Instead, just do this:
Scanner scan = new Scanner(System.in);
Reader reader = new Reader(scan, path, fileWriter, fileReader);
或者,更好的是,不要将其传递给构造函数,而只需在构造函数中将 scan
设置为 this.scan = new Scanner(System.in);代码>
Or, even better, don't pass it to the constructor, but just set scan
to it in the constructor as this.scan = new Scanner(System.in);
接下来,对于 fileReader
,您可以像对 fileWriter
一样对其进行初始化:
Next, for fileReader
, you can just initialize it similarly as you did for fileWriter
:
BufferedReader fileReader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
接下来,这一行:
BufferedWriter fileWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8)
每次运行这个程序时,这一行都会把文件覆盖为空,这可能不是你想要的.您可以添加 StandardOpenOption.APPEND
,但这意味着您只能写入文件的末尾.
Every time this program is run, this line will overwrite the file to empty, which is probably not what you want. You could add StandardOpenOption.APPEND
, but then this means you'll only write to the end of the file.
当您更新数据时,您还会遇到需要推送"数据的问题.将其后的所有数据记录下来.例如:
When you update data, you also have the issue that you'll need to "push" down all of the data that comes after it. For example:
Bobby 1 2 3 4 5
Fred 1 2 3 4 5
如果您将名称 Bobby
更改为更长的名称,例如 Mr.总统
,然后它会覆盖它后面的数据.
If you change the name Bobby
to something longer like Mr. President
, then it will overwrite the data after it.
虽然有不同的选择,但最好和最简单的方法是读取整个文件并将每一位数据存储在一个类中(名称、分数等),然后关闭 fileReader.
While there are different options, the best and simplest is to just read the entire file and store each bit of data in a class (name, scores, etc.) and then close the fileReader.
然后当用户更新某些数据时,更改类中的数据(实例变量),然后将所有数据写入文件.
Then when a user updates some data, change that data (instance variables) in the class and then write all of that data to the file.
这是一些伪代码:
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;
//...
}