'Trouble with replacing a variable in a txt file with user input - using java in eclipse
I am trying to replace one word in a txt file with a new one from user input (Using Java in Eclipse IDE). For example:
My txt file is as follows:
Jacket 12 59.95
DesignerJeans 40 34.95
Shirt 20 24.95
After entering in "Shirt" to be replaced with "Dress", my expected output is as follows:
Jacket 12 59.95
DesignerJeans 40 34.95
Dress 20 24.95
But my actual output with my current code is:
Dress 20 24.95
I got it to replace the desired word, however it also deleted the rest of my txt file. I'm posting the part of my code this occurs in below. Any insight on where my problem lies would be greatly appreciated. I'm still fairly new with java and I've been working on this for a while now.
public static void changeDescriptionOfAnItem(RetailItem[] tempVal) throws IOException {
System.out.print("Retail Item Description to change: ");
Scanner keyboard = new Scanner(System.in);
String userInput;
String newDescription;
userInput = keyboard.nextLine();
System.out.println("Enter NEW Retail Item Description: ");
newDescription = keyboard.nextLine();
File file = new File("RetailItemDatabase.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
String oldtext = userInput;
for (String line; (line = reader.readLine()) != null;) {
line = line.replace(oldtext, newDescription);
FileWriter writer = new FileWriter("RetailItemDatabase.txt");
writer.write(line);
writer.close();
}
reader.close();
}
Solution 1:[1]
There are a number of ways to do this but to carry on with the way you are attempting it then it could be something like this this (read all the comments in code):
/****************************************************
* BEFORE RUNNING THIS CODE, *
* MAKE A BACKUP OF YOUR ORIGINAL DATA FILE *
****************************************************/
public static void changeDescriptionOfAnItem() throws java.io.IOException {
String errMSG = "Invalid Entry! You must supply an item description" + LS
+ "of at least 3 characters in length or 'c' to cancel!" + LS;
String cancelMSG = "Item Description Change - CANCELED!" + LS;
String oldDescription = "";
String newDescription = "";
while (oldDescription.isEmpty()) {
System.out.print("Retail Item Description to change (c to cancel): ");
oldDescription = keyboard.nextLine().trim();
if (oldDescription.equalsIgnoreCase("c")) {
System.out.println(cancelMSG);
return;
}
// Validation...
if (oldDescription.isEmpty() || oldDescription.length() < 3) {
System.out.println(errMSG);
oldDescription = "";
}
}
while (newDescription.isEmpty()) {
System.out.print("Enter NEW Retail Item Description (c to cancel): ");
newDescription = keyboard.nextLine().trim();
if (newDescription.equalsIgnoreCase("c")) {
System.out.println(cancelMSG);
return;
}
// Validation...
if (newDescription.isEmpty() || newDescription.length() < 3) {
System.out.println(errMSG);
newDescription = "";
}
}
// ALL USER INPUT HAS BEEN RECEIVED
// The original Data file
File file = new File("RetailItemDatabase.txt");
// A temp data file where the changes will be stored.
File tmpFile = new File("RetailItemDatabase_tmp.txt");
/* 'Try With Resouces' used here for both reader and writer
so as to automatically close them and free resources. */
try (java.io.FileWriter writer = new java.io.FileWriter(tmpFile);
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.FileReader(file))) {
String oldtext = oldDescription;
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
/* To speed things up we make sure the line actually
contains the item we're looking for. */
if (line.toLowerCase().contains(oldtext.toLowerCase())) {
/* Seemed to have found a line where our item is located
but there is no quarantee it's not just part of another
item like "DressJacket" instead of just "Dress", so we
break the line up into its individual data components as
a String[] Array and then just compare the first one part
of the string. We're ignoreing letter case so that the
User doesn't have to be overly accurate. */
String[] lineParts = line.split("\\s+");
if (lineParts[0].equalsIgnoreCase(oldtext)) {
// Yup...this seems to be the line alright.
// Let's rebuild the new line...
line = newDescription;
for (int i = 1; i < lineParts.length; i++) {
line += " " + lineParts[i];
}
/* Note: You can not break out of the loop at this point
just because you found the item and made the line change.
You have to let this process carry through the entire
data file so that ALL original data is writen to the temp
data file. */
}
}
// Write the line to the tmp file ("RetailItemDatabase_tmp.txt")
writer.write(line + System.lineSeparator());
writer.flush(); // Write immediately.
}
}
// FILE READING/WRITING HAS COMPLETED!
/* Delete Original File ("RetailItemDatabase.txt") AND
Rename the Temp file ("RetailItemDatabase_tmp.txt") to what
the Original file name was named ("RetailItemDatabase.txt").
Because both the File#delete() and File#renameTo() methods
return boolean true if they are successful, we can use them
within the `if` statement as we do below. */
if (file.delete() && tmpFile.renameTo(file)) {
System.out.println("Item changed from '" + oldDescription + "' to "
+ "'" + newDescription + "' - SUCCESSFULLY!");
}
else {
System.out.println("Item change from '" + oldDescription + "' to "
+ "'" + newDescription + "' - FAILED!");
}
}
I had gotten rid of the RetailItem[] tempVal parameter from your method's signature since there is no indication as to what it might be for. One of the major problems you had was you were closing the writer within the for loop. This would happen upon the very first iteration, so, yes, only one write. You only close the reader and writer after you have actually carried out all the necessary reading and writing.
You should make your Scanner object a static class member so that it can be easily accessed by all methods that may be in your class. No need to open one for every method you want to use it in:
public class MyClassName {
/* The line separator (newLine) used for the
specific system running this application. */
private final static String LS = System.lineSeparator();
/* Declare as class member so that is can be used
anywhere in class. */
private final static Scanner keyboard = new Scanner(System.in);
public static void main(String args[]) {
// ----------- The rest of the class code ------------
}
I have also added validation to the User prompts within the changeDescriptionOfAnItem() method. This always helps to reduce possible errors or other nuisances. This also gives the User the opportunity to enter valid data. It simply provides a cleaner User experience...well in my opinion.
If you remove all the comments within the method, it really isn't all that much code. Keep in mind...this is only one way of doing things but it is effective.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | DevilsHnd |
