Using File Streaming - java

I want a program that saves what you enter into the Input Dialogs (after you click no on the first message dialog) for the next time you run the program. The next time I run the program and I click yes on the option dialog, I'm trying to get the text field to say what the user entered last time an input was made. The code at the bottom just sets the textfield blank for some reason..
public static String fn;
public static String sn;
public static int n;
File f = new File("test.txt");
public void actionPerformed (ActionEvent e){
Object[] yesNo = {"Yes",
"No",};
n = JOptionPane.showOptionDialog(null,"Would you like to use previously entered data?","Welcome Back?",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE, null, yesNo,yesNo[1]);
if (n == 1){
for(fn=JOptionPane.showInputDialog("What is your first name?");!fn.matches("[a-zA-Z]+");fn.isEmpty()){
JOptionPane.showMessageDialog(null, "Alphabet characters only.");
fn=JOptionPane.showInputDialog("What is your first name?");
}
writeToFile();
for(sn=JOptionPane.showInputDialog("What is your second name?");!sn.matches("[a-zA-Z]+");sn.isEmpty()){
JOptionPane.showMessageDialog(null, "Alphabet characters only.");
sn=JOptionPane.showInputDialog("What is your second name?");
}
if (n == 0){
writeToFile();
String fullName = writeToFile();
text.setText("Welcome " + fullName + ".");
}
}
//text.setText("Welcome " + fn + " " + sn + ".");
b.setVisible(false);
b.setEnabled(false);
text.setVisible(true);
text.setBounds(140,0,220,20);
text.setHorizontalAlignment(JLabel.CENTER);
text.setEditable(false);
text.setBackground(Color.YELLOW);
pnlButton.setBackground(Color.DARK_GRAY);
}
private String writeToFile() {
String nameToWrite = fn;
OutputStream outStream = null;
String savedName = "";
try {
outStream = new FileOutputStream(f);
outStream.write(nameToWrite.getBytes());
if (n==0){
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
savedName = br.readLine();
}
if (n==1){
text.setText("Welcome " + fn + ".");
}
//text.setText("Welcome " + savedName + " " + sn + ".");
//System.out.println(savedName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (null != outStream) {
try {
outStream.close();
} catch (IOException e) {
// do nothing
}
}
}
return savedName;
}

When you open outputStream each time you call writeToFile, it automatically overwrites what was in the file to begin with. This means when you call writeToFile at the beginning of the if statement to handle the Yes option, you erase the previous contents.
To append, use the line outStream = new FileOutputStream(f, true);.
It may be better to consider moving ALL writing into the if block n==1.
An even better solution would be to have two methods; a readFromFile and a writeToFile. Also, consider using parameters that you pass to the methods instead of global variables.

Related

Retrieve lines in txt file and append new inputs from the user java

I'm using an arraylist to append inputs and send the arraylist elements to file. However, everytime I exit the program and run it again, the contents in the written in the file becomes empty.
ArrayList<String> memory = new ArrayList<String>();
public void fileHandling() {
try {
FileWriter fWriter = new FileWriter("notes.data");
for (int x = 0; x <= memory.size() - 1; x++) {
fWriter.write(memory.get(x) + '\n');
}
fWriter.close();
} catch (IOException e) {
System.out.println(e);
}
}
public void createNote() {
Scanner insertNote = new Scanner(System.in);
LocalDate todayDate = LocalDate.now();
LocalTime nowTime = LocalTime.now();
String timeFormat = nowTime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM));
String dateTime = todayDate.toString() + " at " + timeFormat;
while (true) {
System.out.println();
System.out.println("Enter a note");
System.out.print("> ");
String note = insertNote.nextLine();
if (note == null) {
System.out.println("Invalid input! Try again");
break;
} else {
memory.add(note + " /" + dateTime);
fileHandling();
System.out.println("Note is saved!\n");
break;
}
}
I expect the program to save the contents of every input. Then if I exit and run the program again, the contents will go back to the array
Your code currently does the following:
You enter something (X) for the first time:
It gets added to the ArrayList
The ArrayList gets written into the file
Your file now contains: X
You enter something second (Y):
It gets added to the ArrayList (Which now contains: X, Y)
The ArrayList gets written into the file
Your file now contains: X + newline + Y
Your Problem is, that everytime you create a new FileWrite it overwrites your file.
This can be avoided by using the constructor like this:
FileWriter writer = new FileWriter("notes.data", true);
This sets it into the append mode and therefore keeps previous data in the file
You don't need to create a separate Scanner, in method createNote(), in order to get a "note" from the user.
It is usually better to write your code using the interface rather than the specific implementation because then you usually need to change less code if you decide to change the implementation. Hence the type for member variable memory should probably be List rather than ArrayList.
Note that ArrayList may waste memory if the list of "note"s is large. I suggest using LinkedList instead. Alternatively, use an array (rather than a List) and handle expanding the array when adding a "note" as well as reducing the array when removing a "note".
Having an infinite loop, i.e. while (true), which contains a single if-else where both the if block and the else block contain break statements, means that the loop will perform exactly one iteration. May as well remove the while loop – which means also removing the break statements.
Rather than writing the code that generates a timestamp repeatedly, you should adopt the DRY principle and extract that code into a separate method.
The file name should be a constant so as to minimize the amount of code changes you will need to do if you decide to change the file name.
By convention, text files have a filename extension of .txt whereas binary files have the .data extension.
Although you don't need to, I personally prefer to initialize class member variables in the constructor.
The below code is a SSCCE, hence I added a main method. More notes appear after the code.
package Methods;
import java.util.*;
import java.time.format.*;
import java.time.*;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileSys {
private static final String FILENAME = "notes.txt";
private static final String CREATE = "C";
private static final String DELETE = "D";
private static final String FIND = "F";
private static final String QUIT = "Q";
private static final String SHOW = "S";
private static final String UPDATE = "U";
Scanner reader;
List<String> memory;
public FileSys() throws IOException {
reader = new Scanner(System.in);
memory = new LinkedList<String>();
loadFile();
}
public void fileHandling() {
Path path = Paths.get(FILENAME);
try (BufferedWriter bw = Files.newBufferedWriter(path,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
PrintWriter pw = new PrintWriter(bw)) {
for (String write : memory) {
pw.println(write);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public void createNote() {
String dateTime = getTimestamp();
System.out.println();
System.out.println("Enter a note");
System.out.print("> ");
String note = reader.nextLine();
memory.add(note + " / " + dateTime);
fileHandling();
System.out.println("Note is saved!");
}
public void searchNote() {
System.out.print("\nEnter note number: ");
try {
int search = reader.nextInt();
reader.nextLine();
System.out.println("\nSearch result:");
int index = memory.indexOf(memory.get(search - 1));
if (index != -1) {
System.out.println("[" + (index + 1) + "]" + " " + memory.get(search - 1));
}
else {
System.out.println("Note number-" + search + " is not found in the collection!");
}
}
catch (IndexOutOfBoundsException e) {
System.out.println("The note number you have entered is invalid!");
}
}
public void updateNote() {
String dateTime = getTimestamp(); // ZonedDateTime.now(ZoneId.systemDefault()).format(dateTimeObj);
System.out.print("\nEnter note number to change: ");
try {
int search = reader.nextInt();
int index = memory.indexOf(memory.get(search - 1));
String updateLine;
if (index != -1) {
System.out.println("\nCurrent note: ");
System.out.println("[" + (index + 1) + "]" + " " + memory.get(search - 1));
System.out.println("\nThe updated note will be: ");
System.out.print("> ");
reader.nextLine();
updateLine = reader.nextLine();
memory.set(index, updateLine + " /" + dateTime);
System.out.print("Note has been updated successfully!\n");
}
else {
System.out.println(search + " is not found in the collection!");
}
}
catch (IndexOutOfBoundsException e) {
System.out.println("The note number you have entered is invalid!");
}
fileHandling();
}
public void deleteNote() {
System.out.print("\nEnter note number to delete: ");
try {
int search = reader.nextInt();
reader.nextLine();
int index = memory.indexOf(memory.get(search - 1));
System.out.println();
if (index != -1) {
System.out.println("[" + (index + 1) + "]" + " " + memory.get(search - 1));
System.out.print("\nDo you want to delete this note? \n[y] or [n]: ");
char delDecision = reader.nextLine().charAt(0);
if (delDecision == 'y' || delDecision == 'Y') {
memory.remove(index);
System.out.println("Note has been deleted successfully!");
System.out.println();
}
else if (delDecision == 'n' || delDecision == 'N') {
System.out.println("Note was not deleted!");
}
else {
System.out.println("Invalid input!");
}
}
else {
System.out.println(search + " is not found in the collection!");
}
}
catch (IndexOutOfBoundsException e) {
System.out.println("The note number you have entered is invalid!");
}
fileHandling();
}
public void displayNote() {
if (memory.size() > 0) {
int counter = 0;
for (String note : memory) {
System.out.printf("%d. %s%n", ++counter, note);
}
}
else {
System.out.println("There are no notes.");
}
}
private String getTimestamp() {
LocalDate todayDate = LocalDate.now();
LocalTime nowTime = LocalTime.now();
String timeFormat = nowTime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM));
String dateTime = todayDate.toString() + " at " + timeFormat;// ZonedDateTime.now(ZoneId.systemDefault()).format(dateTimeObj);
return dateTime;
}
private void loadFile() throws IOException {
Path path = Paths.get(FILENAME);
if (Files.isRegularFile(path)) {
memory.addAll(Files.readAllLines(path, Charset.defaultCharset()));
}
}
private void showMenu() {
String choice = "";
while (!QUIT.equalsIgnoreCase(choice)) {
System.out.println(CREATE + " - Create note");
System.out.println(DELETE + " - Delete note");
System.out.println(FIND + " - Search notes");
System.out.println(SHOW + " - Show notes");
System.out.println(UPDATE + " - Update note");
System.out.println(QUIT + " - Quit");
System.out.println();
System.out.print("Your choice: ");
choice = reader.nextLine();
if (!choice.isEmpty()) {
choice = choice.substring(0, 1);
choice = choice.toUpperCase();
switch (choice) {
case CREATE -> createNote();
case DELETE -> deleteNote();
case FIND -> searchNote();
case SHOW -> displayNote();
case UPDATE -> updateNote();
case QUIT -> System.out.println("Good bye.");
default -> System.out.println("Invalid: " + choice);
}
}
else {
System.out.println("No selection entered. Retry.");
}
}
}
public static void main(String[] args) {
try {
FileSys fs = new FileSys();
fs.showMenu();
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
Your code does not initially load memory with contents of file notes.txt so I added that in the constructor. Consequently you don't need to append to the file since you simply overwrite it with contents of memory.
The file handling is done using NIO.2 including try-with-resources – which was added in Java 7. There are more NIO.2 examples in the JDK documentation.
Whenever the code throws an unexpected exception, it is nearly always a good idea to print the stack trace.

Java programming project

I am in the middle of a university project, the task being to use a scanner to read the appropriate data of several data files. The project involves a superclass and several subclasses. So far the method below works perfectly and reads data corresponding to a class called Tool and all its fields. However I have recently added a subclass ElectricTool which extends class Tool and also which has introduced two new fields which need reading in the same way as before but within the same method shown below. I have tried a number of things but I can't seem to figure it out. Any suggestions? Preferably as clean/simple code as possible, I think it needs to be a read statement but I am struggling. The method is below:
public void readToolData()
{
Frame myFrame = null;
FileDialog fileBox = new FileDialog(myFrame,"Open", FileDialog.LOAD);
fileBox.setVisible(true);
String directoryPath = fileBox.getDirectory();
String fileName = fileBox.getFile();
File dataFile = new File(fileName);
System.out.println(fileName +" "+ directoryPath);
Scanner scanner = null;
try
{
scanner = new Scanner(dataFile);
}
catch (FileNotFoundException e)
{
System.out.println(e);
}
while( scanner.hasNextLine() )
{
String lineOfText = scanner.nextLine().trim().replaceAll("\\s+","");
if(!lineOfText.isEmpty() && !lineOfText.matches("^//.*") && !lineOfText.substring(0,1).equals("["))
{
System.out.println(lineOfText);
}
else{
continue;
}
Scanner scanner2 = new Scanner(lineOfText).useDelimiter("\\s*,\\s*");
while(scanner2.hasNext())
{
Tool tool = new Tool();
tool.readData(scanner2);
storeToolList(tool);
}
}
scanner.close();
}
electric tool class
tool class
data file
public void readToolData() {
Frame myFrame = null
FileDialog fileBox = new FileDialog(myFrame, "Open", FileDialog.LOAD);
fileBox.setVisible(true);
String directoryPath = fileBox.getDirectory();
String fileName = fileBox.getFile();
File dataFile = new File(directoryPath + fileName);
System.out.println(fileName + " " + directoryPath);
Scanner scanner = null;
try {
scanner = new Scanner(dataFile);
} catch (FileNotFoundException e) {
System.out.println(e);
}
// Current tool type
String toolType = null;
while( scanner.hasNextLine() ) {
String lineOfText = scanner.nextLine().trim();
// Skip empty lines and commentaries
if(lineOfText.isEmpty() || lineOfText.startsWith("//")) {
continue;
}
if (lineOfText.startsWith("[")) {
// Extract the tool type name
String withoutBracket = lineOfText.substring(1);
// Split by spaces and take the first word
String[] words = withoutBracket.split(" ");
toolType = words[0];
System.out.println("Reading information about " + toolType);
continue;
}
System.out.println(lineOfText);
Scanner scanner2 = new Scanner(lineOfText).useDelimiter("\\s*,\\s*");
Tool tool = null;
if ("ElectricTool".equals(toolType)) {
tool = new ElectricTool();
}
// In the future here will come more cases for different types, e.g.:
// else if ("HandTool".equals(toolType)) {
// tool = new HandTool();
// }
if (tool != null) {
tool.readData(scanner2);
storeToolList(tool);
}
}
scanner.close();
}
Remove scanner.skip line in Tool.readData:
public class Tool {
public void readData(Scanner scanner) {
toolName = scanner.next();
itemCode = scanner.next();
timesBorrowed = scanner.nextInt();
onLoan = scanner.nextBoolean();
cost = scanner.nextInt();
weight = scanner.nextInt();
scanner.skip(".*"); // Remove this line
}
}
And implement readTool method in ElectricTool:
#Override
public void readData(Scanner scanner) {
super.readData(scanner);
rechargeable = scanner.nextBoolean();
power = scanner.next(); // Or nextInt? what is the type of power field?
}
To print the information about the tools you should use polymorphism.
Modify your printAllTools method in Shop.java like this:
public void printAllTools() {
System.out.println("Information");
System.out.println("---------->");
for (Tool t : toolList) {
System.out.println("You have selected:\n");
t.printDetails();
}
}
Now, your method printDetails in Tool.java must be looking like this:
public void printDetails() {
System.out.println("Tool name: " + toolName + "\n" +
"Item code: " + itemCode + "\n" +
"Times borrowed: " + timesBorrowed + "\n" +
"On load: " + onLoan + "\n" +
"Cost: " + cost + "\n" +
"Weight: " + weight + "g\n"
);
}
and in the ElectricTool.java:
public void printDetails() {
super.printDetails();
System.out.println("Rechargeable: " + rechargeable + "\n" +
"Power: " + power + "\n"
);
}

Retrieve saved data from a text file but only show a portion of the data Java JGrasp

I have programmed a game were I have made it so that you can save your score, if you have a good score you will be in the top 10. My problem is when I retrieve the data with the saved names, I only want a proportion of that data to be shown, in this case 10 names.
Here is my code.
public static void Highscore(List<Highscore> data) {
String HighscoreList = "";
try {
//Textfilens name
String filname = "Highscore.txt";
Scanner inFil = new Scanner(new File(filname));
while(inFil.hasNext()) {
String name = inFil.next();
String percent = inFil.next();
HighscoreLista += name + "\n" + percent + "%" + "\n\n";
} inFil.close();
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(null,"File was not found!");
}
JOptionPane.showMessageDialog(null, HighscoreList);
}//Highscore ends
How do I only show a proportion of the players in the final message (Highscorelist).
Thank you for helping.
Create a counter variable in the function to track the number of items in the while loop and check the counter variable along with the while condition
public static void Highscore(List<Highscore> data) {
String HighscoreList = "";
int counter =0;
try {
//Textfilens name
String filname = "Highscore.txt";
Scanner inFil = new Scanner(new File(filname));
while(inFil.hasNext() && counter<=10) {
counter++;
String name = inFil.next();
String percent = inFil.next();
HighscoreLista += name + "\n" + percent + "%" + "\n\n";
} inFil.close();
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(null,"File was not found!");
}
JOptionPane.showMessageDialog(null, HighscoreList);
}//Highscore ends

Why does FileWriter overwrite the file even though I did specify it should append

This is what I have:
try{
String filename = "Names.txt";
FileWriter fw = new FileWriter(filename, true);
BufferedWriter buffer = new BufferedWriter(fw);
buffer.append("NAME: " + name + " AGE: " + age + " ID: " + id + "\n\n");
System.out.println("We have succefully created your account.");
buffer.close();
start();
} catch(IOException e){
System.err.println("ERROR");
}
It always overwrites the first line and does not go to a different one. I've used the append. This is my start method:
// this is the start method
public static void start(){
System.out.println("1) Add Account 2) Exit");
System.out.println("What do you want to do: ");
stuff = input.nextInt();
if (stuff == 1) {
try {
x = new Formatter("Names.txt");
} catch (Exception e) {
System.err.println("ERROR" );
}
newRecord();
} else if(stuff == 2) {
System.exit(0);
} else {
System.err.println("ERROR");
}
}
I guess is this line:
x = new Formatter("Names.txt");
From javadoc
public Formatter(String fileName) throws FileNotFoundException
Parameters:
fileName - The name of the file to use as the destination of this formatter. If the file exists then it will be truncated to zero size; otherwise, a new file will be created. The output will be written to the file and is buffered.
(I add emphasis to the part that is cleaning your file).

Java IO. loading from .txt file as a variable

I am making a simple program where I can keep track of my savings. I have included week no., income, and saved fields. I save this data to a text file and then can retrieve it to a text area. How can I keep track of my running total, "total", when closing the program then running it again. I have used an array as a running total, but this starts over when I kill it then reopen it (obviously).
here is my code for the save and read. to sum up I want to be able to retrieve the last field "total" as a variable so it can be added onto the new input.
//get week and validate:
strWeek = txtWeek.getText();
if (strWeek.isEmpty())
{
JOptionPane.showMessageDialog(null, "Enter Week Number");
return;
}
else
week = Integer.parseInt(strWeek);
//get income and validate:
strIncome = txtIncome.getText();
if (strIncome.isEmpty())
{
JOptionPane.showMessageDialog(null, "Enter Income");
return;
}
else
income = Double.parseDouble(strIncome);
//get saved:
strSaved = txtSaved.getText();
if (strSaved.isEmpty())
{
JOptionPane.showMessageDialog(null, "Enter Saved");
return;
}
else
saved = Double.parseDouble(strSaved);
total = total + saved;
txtOutput.append(week + "\t" + income + "\t" + saved + "\t" + total + "\n");
txtWeek.setText(null);
txtIncome.setText(null);
txtSaved.setText(null);
try
{
File output = new File("C:\\savingsApp/Savings.txt");
BufferedWriter outFile = new BufferedWriter (new FileWriter(output.getPath(), true));
outFile.write(week + "\t" + income + "\t" + saved + "\t" + total);
outFile.newLine();
outFile.close();
JOptionPane.showMessageDialog(null, "Savings updated");
}
catch (Exception e)
{
JOptionPane.showMessageDialog(null, "IO file error");
}
txtOutput.setText(null);
//Declare:
String incomingString = "";
int counter = 0;
//get file:
try
{
File inputFile = new File ("C:\\savingsApp/savings.txt");
BufferedReader inFile = new BufferedReader (new FileReader(inputFile));
incomingString = inFile.readLine();
while (incomingString != null)
{
counter++;
txtOutput.append(incomingString + "\n");
incomingString = inFile.readLine();
}
}
catch (Exception e)
{
JOptionPane.showMessageDialog(null, "error loading file");
}
Make runningTotal an ArrayList and save to a separate file before killing your program. This could be in comma (or tab) separated form. For instance runningTotal.csv could look like this:
150,200,50,...,300
When you read in savings.txt you can also read in runningTotal.csv and then add any more totals to the end of the ArrayList. When you close the program again, update runningTotal.csv.
I'm assuming that what you are really asking is a way to parse the text you are getting from the file. The, a way to achieve this could be by using java.util.Scanner for example as shown in here:
private Map<String, String> parseData(String text) {
Map<String, String> data = new HashMap<String, String>();
Scanner scanner = new Scanner(text);
data.put("week", scanner.next());
data.put("income", scanner.next());
data.put("saved", scanner.next());
data.put("total", scanner.next());
return data;
}
Then you could do something like this:
...
while (incomingString != null) {
counter++;
String totalStr = parseData(incomingString).get("total");
txtOutput.append(incomingString + "\n");
incomingString = inFile.readLine();
}

Categories

Resources