Java - Saving to txt file duplicates first entry - java

I have been working on a small library application which allows manuals to be stored. So far I have implemented code to allow my application to save to an existing text file, I would like the same file to be updated each time the user saves, and not overwritten.
Currently if I enter 1 manual and save the library, the text file is updated. But if I add a second manual to the library then save, the first manual is duplicated in the text file
Here is an example of the text file after a second manual is added:
Here is the code I am using to save:
//Choice 7: Save Library:
if(Menu.menuChoice == 7 && Library.ManualList.isEmpty()){
System.out.println(Messages.addManualFirst);
Menu.displayMenu();
}
else if(Menu.menuChoice == 7){
Library.displayManualList();
boolean saveYesNo = Console.readYesNo("\nThe ManualKeeper® app is able to save your current library to a '.txt' \nfile in your workspace directory.\n\nWould you like to save the current library? (Y/N):\n");
if(saveYesNo){
try {
FileWriter fw = new FileWriter("Library.txt", true);
PrintWriter pw = new PrintWriter(fw);
for (int i = 0; i < Library.ManualList.size(); i++){
pw.println("-------------------- Index Number: " + i + " --------------------");
pw.println(Library.ManualList.get(i).displayManual());
pw.println("---------------------------------------------------------\n");
}
pw.close();
} catch (IOException e) {
System.out.println("Error! Library unable to save.");
}
System.out.println("\n\n--------------------------------------------------------------------------");
System.out.println("\n Library saved!\n");
System.out.println("--------------------------------------------------------------------------\n");
}
else if(saveYesNo){
System.out.println("\n");
}
Menu.displayMenu();
}
If anyone knows how I might be able to get the first manual to stop duplicating, please let me know :)

I'm a little confused, you're saying you don't want to overwrite the file, you want to append to it... And that's exactly what's happening.
The PrintWriter will append to the existing file. So I'm assuming what happens is that on your first run, it creates the initial 'index 0' block. On your subsequent run it just appends to the file, duplicating the first entry.
To avoid this you could just create your file object from scratch every time, eg:
File file = new File("Library.txt");
file.delete();
file.createNewFile();
FileWriter fw = new FileWriter(file, true);
But as your question is described, it seems like the problem you're encountering is exactly what you want..?

Related

Java swing Save and Save as functions with JFileChooser

I am writing a little app and would like to add the same handler for two buttons: Save and Save As. For save if the file exists it should not open the JFileChooser,just save the content, but with my current code it always opens the dialog. How do I do this? Here's my code
public void actionPerformed(ActionEvent e) {
JComponent source = (JComponent)e.getSource();
if (pathToFile.length()>0){
File file = new File(pathToFile);
if (file.exists()){
try(FileWriter fw = new FileWriter(file.getName() + ".txt", true)){
fw.write(area.getText());
}
catch(Exception ex){
System.out.println(ex.toString());
}
}
}
else{
if (fchoser.showSaveDialog(source.getParent())== JFileChooser.APPROVE_OPTION){
try(FileWriter fw = new FileWriter(fchoser.getSelectedFile()+".txt")){
fw.write(area.getText());
f.setTitle(fchoser.getSelectedFile().getPath());
pathToFile = fchoser.getSelectedFile().getPath();
}
catch(Exception ex){
}
}
}
UPDATE Added code to check if file exsists. It does and there is no exception but the additional text does not write.
Not related to your question but:
fw.write(area.getText());
Don't use the write method of a FileWriter. This will always write the text to the file using a "\n" as the line separator which may or may not be correct for the OS your code is running on.
Instead you can use the write(...) method of the JTextArea:
area.write(fw);
Then the proper line separator will be used.

Saving to new txt file each time library saved by user

How would it be possible to enable my application to save to a new .txt file each time the user wishes to save, as opposed to overwriting the existing one?
I have this code which functions and saves information to a text file:
if(Menu.menuChoice == 1 && Library.ManualList.size() > 0){
Library.displayManualList();
boolean saveYesNo = Console.readYesNo("The ManualKeeper® app is able to save your current library to a '.txt' \nfile in your workspace directory.\n\nWould you like to save the current library? (Y/N):\n");
if(saveYesNo){
try {
FileWriter fw = new FileWriter("Library.txt");
PrintWriter pw = new PrintWriter(fw);
for (int i1 = 0; i1 < Library.ManualList.size(); i1++){
pw.println("-------------------- Index Number: " + i1 + " --------------------");
pw.println(Library.ManualList.get(i1).displayManual());
pw.println("---------------------------------------------------------\n");
}
pw.close();
} catch (IOException e) {
System.out.println("Error! Library unable to save.");
}
System.out.println("\n\n--------------------------------------------------------------------------");
System.out.println("\n Library saved!\n");
System.out.println("--------------------------------------------------------------------------\n");
}
else if(saveYesNo){
System.out.println("\n");
}
Ideally I would like the files to be saved in a numbered fashion, so the user could easily select which .txt file to view, at a later date.
To save it to a new file each time, the file name has to be unique.
You can achieve this in mulitple ways. Some ideas:
Date+Time in file name
Add the current date+time to the file name, this will also be informative as when it was created/saved, and when listing files, newer files will be at the end of the list naturally.
String name = "Library-"
+ new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date()) + ".txt";
As an alternative, you could simply append System.currentTimeMillis() which will preserve natural creation order but will not be as nice looking/informative:
String name = "Library-" + System.currentTimeMillis() + ".txt";
Random String in file name
This might not be as nice looking, but for example:
String name = "Library-" + UUID.randomUUID() + ".txt";
Counter in the file name
The idea is to use a counter in the file name, so the first should be "Library.txt", the next should be "Library (2).txt", the third should be "Library (3).txt" etc.
For this to implement, we have to check existing files to determine the next value of the counter. Here is an example how to do it. This is not optimal, but does the job:
public static Path uniqueFile() {
Path file = Paths.get("Library.txt").toAbsolutePath();
if (!Files.exists(file))
return file;
Path folder = file.getParent();
for (int counter = 2; true; counter++) {
file = folder.resolve(String.format("Library (%d).txt", counter));
if (!Files.exists(file))
return file;
}
}
And using it:
String name = uniqueFile().getFileName().toString();
If the application is made with a GUI, a fileDialog would be best (save if he wants to override the file, save as if he wants to save it to a new file, like a lot of applications have).
In your case you should use a counter and add it to the end of the file like Library1.txt.
If rerun the application, of course this counter variable is reset resp. it is not stored. I would suggest to store this variable (and other attributes like that) in another file, e.g. config.txt
This config.txt file you can read (and parse it like I showed you in a previous answer). So everytime you start your application you read the config.txt file, set the counter. Before exiting the application of course you have to save the counter to the config.txt file.
Just pseudocode:
//load at start of application
counter = loaded from config.txt
//save to a new file
FileWriter fw = new FileWriter("Library" + counter++ + ".txt");
//save counter to config.txt file

Android Can't Remember My Files

I am writing a notepad app and I'm making a create a password screen pop up until you've created one, and then a log in screen will pop up from then on.
Here is some sample code:
File myFile = new File(getFilesDir() + "pass.txt");
if (!myFile.exists()) // if "pass.txt" DOESN'T exist, make them create a password
{
try {
// this writes the password to the "pass.txt" file
// which is the one that is checked to exist.
// after it is written to, it should always exist.
FileOutputStream fos = openFileOutput("pass.txt", Context.MODE_PRIVATE);
fos.write(pass.getBytes());
// this writes the security question to a different file.
fos = openFileOutput("securityQ.txt", Context.MODE_PRIVATE);
fos.write(secQ.getBytes());
// this writes the security answer to a different file.
fos = openFileOutput("securityAnswer.txt", Context.MODE_PRIVATE);
fos.write(secAns.getBytes());
fos.close();
} catch(Exception e) {}
^ That is in one method. Then, in another I do this:
try { // input the right password to the String data
char[] inputBuffer = new char[1024];
fIn = openFileInput("pass.txt");
isr = new InputStreamReader(fIn);
isr.read(inputBuffer);
data = new String(inputBuffer);
isr.close();
fIn.close();
}catch(IOException e){}
if (password.getText().toString().equals(data)) // if password is right, log in.
{
loggedin();
}
else // if the password entered is wrong, display the right one.
{
TextView scr = (TextView)findViewById(R.id.display);
scr.setText("." + data + "."+'\n'+"." + password.getText().toString() + ".");
}
The problem is that the user can't log in even though the password is entered correctly and the display proves that.
The other problem is that whenever I run the app again, it goes to the create screen, which means that it is recognizes the file to NOT exist (even though I just wrote to it).
I've dealt with files this whole project and it can keep track of entered text so that when you press a button, it reads the file back to you. Even if you close it, it keeps track of what you input. For some reason though, the password thing doesn't work.
Here is an image of what happens (the first .k. is the data read from the "pass.txt" file and the second .k. is the user inputted String from the EditText):
SOLUTION to the logging in problem:
String values look the same but don't ".equals()" each other
Had to simply use the .trim() method on the password user input.
I'll pass on commenting about saving passwords in a file called "pass.txt", and just focus on the technical part.
File myFile = new File(getFilesDir() + "pass.txt");
myFile will never be a valid file. You don't have a separator / between the path and the file name. Since that will never be vaild, the next line will say it doesn't exist and go through the whole block.
You can easily fix this one of two ways:
File myFile = new File(getFilesDir() + "/pass.txt");
That simply adds the separator to the file name.
File myFile = new File(getFilesDir(), "pass.txt");
This is probably the better option, since it uses the explicit path, file constructor. Either one is fine, though.
You can also just use context.openFileInput("pass.txt"); and catch if FileNotFoundException occurs, at which point you can "assume" the file actually doesn't exist.

java file.renameTo() fails in unix

I have a java application that processes the contents of a file, and then I need to move it to another location.
This is how I read the file:
String filePath = new String("foo.bar");
String fileContents = new String("");
char[] myBuffer = new char[chunkSize];
int bytesRead = 0;
BufferedReader in;
try {
FileReader fr = new FileReader(filePath);
in = new BufferedReader(fr);
try {
while ((bytesRead = in.read(myBuffer,0,chunkSize)) != -1)
{
//System.out.println("Read " + bytesRead + " bytes. They were: " + new String(myBuffer));
fileContents+= new String(myBuffer).substring(0, bytesRead);
}
// close the stream as I don't need it anymore. (If I don't close it, then java would hold the file open thus preventing the subsequent move of the file)
in.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
the file should be closed as I close both input stream and file reader.
Then after this I try to move the file to another directory using File.renameTo(newFileName); but this fails (under unix!, under windows it works fine)
Right after the move fails, I test whether I can create a file called newFileName and whether I can delete the original file. The new file gets to be created, while the original file fails to delete.
Interestingly enough I can delete the original file from command line while the application is running (right after the failure).
Any idea why is that or any alternative?
More details: I am working under unix and I'm bound to use java 1.6 for legacy reasons (thus I can not revert to Files.move() which is supported starting from java 1.7).
I found what was the problem in my java application.
Basically I extract a list of files from a directory using a custom FileFilter. This gives me an array File[] foundFiles.
What I do afterwards is reading each file in a while loop using the snippet of code in the question.
Right after the file is read for some reason I created a new File object using the i-th file from the array as parameter for the constructor
File file = new File(foundFiles[i].getName()); // File to be moved
and then I tried to rename this one.
Now for some reason this works under windows while it doesn't under unix (the file is somehow locked I think by the foundFiles[i] object).
In fact if I print the results of these lines
System.out.println("I can read foundFiles[i]: " +foundFiles[i].canRead());// DEBUG
System.out.println("I can write foundFiles[i]: " +foundFiles[i].canWrite());// DEBUG
System.out.println("I can read file : " +file.canRead());// DEBUG
System.out.println("I can write file : " +file.canWrite());// DEBUG
I get
I can read foundFiles[i]: True
I can write foundFiles[i]: True
I can read file: False
I can write file: False
It was simply enough to use renameTo() directly on the foundFiles[i] objects to make it work fine.
Hope this helps, but I don't know why the first version would work under windows and not under unix.
Let's analyze the above observation...
I can read foundFiles[i]: True
I can write foundFiles[i]: True
I can read file: False
I can write file: False
The result is normal, because the file object has been produced via new File(foundFiles[i].getName()) but the method getName provides only the name of the file, WITHOUT its filepath !
By creating the file via new File(foundFiles[i].getParent() + File.separator + foundFiles[i].getName()), the results would then be :
I can read foundFiles[i]: True
I can write foundFiles[i]: True
I can read file: True
I can write file: True

Opening and Writing to file Java

I'm currently stuck on a spot in my code. I need to write data to a text file, I have sorts going and they are taking the time that each sort takes to complete and then puts them into a txt file that I can then use to create graphs. Problem is that I just get one line after I run the program. I can't get it to keep each result.
public static void resultsToFile(String sort, double seconds, File file)
{
try (PrintWriter out = new PrintWriter(new FileWriter(file)))
{
out.write(sort + "\t");
out.write(seconds + " seconds\n");
out.flush();
out.close();
}catch (IOException e)
{
e.printStackTrace();
}
}
This is what I have so far for my writing to files method. Any help would be greatly appreciated!
You're creating a new PrintWriter object each time you write a line of results to the file and thus over-writing any previously existing File that held the previous line of data. Why not create your PrintWriter once in the class, and then close it when you're done writing all of the data to file?
As HovercraftFullOfEals mentioned, you open the file for each line, and this is a big performance overhead.
Yet the problem you see is because you don't open the file to append to it, but to write to it from the beginning. To append to the file, open it using the constructor FileWriter(File,boolean):
try (PrintWriter out = new PrintWriter(new FileWriter(file, true)))

Categories