I'm having a logic issue to update a text file via user input.
I have a text file containing product information (ID;Name;Cost;Stock) :
001;Hand Soap;2.00;500
In order to add a product the user calls a function addProduct in order to either update a product if the product name already exists in the file or append to the text file if it does not yet exist. I'm unsure of two things : how to append only once (for the moment it's appending for every line it reads..) and how to deal with an empty text file.
This is how addProduct looks:
public void addProduct(Product product, int amountReceived) throws FileNotFoundException, IOException {
newProduct = product;
String productParams = newProduct.getProduct();
String productID = newProduct.getProductID();
int productStock = newProduct.getProductStock();
String productName = newProduct.getProductName();
String tempFileName = "tempFile.txt";
System.out.println("Attempting to Add Product : " + newProduct.getProduct());
BufferedReader br = null;
BufferedWriter bw = null;
try {
FileInputStream fstream = new FileInputStream(ProductMap.productFile);
br = new BufferedReader(new InputStreamReader(fstream));
String line;
StringBuilder fileContent = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println("Line : " + line);
String [] productInfo = line.split(";");
System.out.println("Added Product Info length : " + productInfo.length);
if (productInfo.length > 0) {
if (productInfo[1].equals(productName))
{
System.out.println("Adding existing product");
System.out.println("Product Info : " + String.valueOf(productInfo[3]));
//line = line.replace(String.valueOf(productInfo), String.valueOf(productStock - amountSold));
productInfo[3] = String.valueOf(Integer.parseInt(productInfo[3]) + amountReceived);
String newLine = productInfo[0] + ";" + productInfo[1] + ";" + productInfo[2] + ";" + productInfo[3];
fileContent.append(newLine);
fileContent.append("\n");
System.out.println("Updated Product Info : " + String.valueOf(Integer.parseInt(productInfo[3]) + amountReceived));
System.out.println("Line :" + newLine);
} else {
fileContent.append(line);
fileContent.append("\n");
fileContent.append(productParams);
fileContent.append("\n");
//fileContent.append(productParams + "\n");
//System.out.println("Product Name : " + productInfo[1]);
//System.out.println("The full product info : " +productParams);
}
}
br.readLine();
}
if (br.readLine() == null) {
fileContent.append(productParams);
}
System.out.println("Product Updated File Contents : " + fileContent);
FileWriter fstreamWrite = new FileWriter(ProductMap.productFile);
BufferedWriter out = new BufferedWriter(fstreamWrite);
System.out.println("File Content : " + fileContent);
out.write(fileContent.toString());
out.close();
in.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
At a high level, a simple text file may not be the best choice for this use. This implementation requires enough memory to hold the entire file.
If you only had additions and could just append to the file directly, things would be easier. A database would seem to be the best choice. Somewhere between a database and a simple text file, a RandomAccessFile could help if the data could be written with standard lengths for each field. Then you could overwrite a particular row rather than having to rewrite the whole file.
Given the constraints of the current setup, I can't think of a way around writing all the data each time the file is updated.
To get around the empty file problem, you could skip the else condition of the current loop So the new data would not be added to the fileContent StringBuffer. Then when writing the data back out, you could either write the new data before or after the other information from the file.
Also, the readLine at the bottom of the loop is not needed. Any row that is read at the bottom of the loop will be skipped over and not really processed when the read at the top of the loop gets the next line.
Related
I have a text file containing client data, ID, Name and Surname, Balance and Date,4 lines for one client in text file, then there is a space and another client data begins and so on.
ID:33
Client: Michael Reedus
Balance: 30000 Eur
Date: 32.03.2019
ID:34
Client: Michael Snow
Balance: 31900 Eur
Date: 32.03.2019
I need to create line replacement for specific client ID block, to avoid replacing same line for other person without using ID.
I tried realizing an idea, where when code finds ID which I need, it stops there, jumps, for example, a line lower and edits that line, but instead, I lose all other lines except line I am replacing.
private static void updateLine(String fails, String ID, String toUpdate, String updated) throws IOException {
BufferedReader file = new BufferedReader(new FileReader(fails));
String line;
String input = "";
while ((line = file.readLine()) != null) {
if (line.equals(ID)) {
line = file.readLine();
input += line + System.lineSeparator();
input = input.replace(toUpdate, updated);
}
}
FileOutputStream os = new FileOutputStream(fails);
os.write(input.getBytes());
file.close();
os.close();
}
I expect getting
ID:33
Client: Michael Jordan
Balance: 30000 Eur
Date: 32.03.2019
not
Client: Michael Jordan
There are a number of reasons why you were having difficulties, here are some:
if (line.equals(ID)) {
line = file.readLine();
input += line + System.lineSeparator();
As you can see in the above wee bit of code you are effectively taking the line you just read in and then applying directly to your String which will be written to file. There is no change in the data here. It should be:
if (line.equals(ID)) {
line = file.readLine();
input += updated + System.lineSeparator();
Which opens another can of worms. What if the Original Name supplied doesn't match the ID number supplied. Maybe an entry mistake was made. Before updating the particular item in file compare it to what is contained within the toUpdate parameter:
if (line.equals(ID)) {
line = file.readLine();
if (line.equals(toUpdate)) {
input += updated + System.lineSeparator();
}
This next line really puzzles me:
input = input.replace(toUpdate, updated);
You do realize that the input String variable will eventually hold ALL the data contained within your file. What if the item you want to update is in several locations under many different ID numbers? The line above will change all of them. Get rid of this scary line of code. If anything it should only be applied to the line variable (the file line currently read in).
Below I have posted a modified version of your updateLine() method. This version allows you to change any client field except the ID field, for example:
updateLine("clients.txt", "ID:33", "Date: 32.03.2019", "Date: 31.03.2019");
updateLine("clients.txt", "ID:34", "Client: Michael Snow", "Client: John Smith");
updateLine("clients.txt", "ID:34", "Balance: 31900", "Balance: 1253672");
Here is the code (most of it is comments):
private static void updateLine(String fails, String ID, String toUpdate, String updated) {
// Try With Resources is used to autoclose the BufferedReader
try (BufferedReader file = new BufferedReader(new FileReader(fails))) {
String line;
String input = "";
while ((line = file.readLine()) != null) {
if (line.equals(ID)) {
// Append the ID to String
input+= ID + System.lineSeparator();
/* Loop through this client's data and make
changes where necessary... */
while ((line = file.readLine()) != null) {
/* If we get to this point where we read an ID again
then we've gone too far. The item to update could
not be found under the supplied ID Number. */
if (line.startsWith("ID:")) {
// Append the original ID to String.
System.out.println("The item to update (" + toUpdate +
") could not be found under the ID of: " + ID);
// Add this line to string anyways.
input+= line + System.lineSeparator();
break; // Break out of this inner lop
}
// Does file line match the supplied toUpdate?
if (line.equals(toUpdate)) {
// Yes - Append the new item to String
input+= updated + System.lineSeparator();
break; // Get out of inner loop. Let main loop take over again.
}
else {
// Append the original item to String.
input+= line + System.lineSeparator();
}
}
}
else {
input+= line + System.lineSeparator();
}
}
// Re-Write File with new data
// Try With Resources is used to autoclose the Stream
try (FileOutputStream os = new FileOutputStream(fails)) {
os.write(input.getBytes());
os.flush();
}
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
Writing a program in java I'm trying to read the content of a file which is treated as a storage. I have a function to modify the amount of an object in the store, which is organized with one line per product, where the first word is the prodCode, and the second is the amount of it.
This is the function:
public static void modifyAmount(String prodCode, String newAmount){
try{
File magazzino = new File("Magazzino.txt");
BufferedReader fromFile = new BufferedReader(new FileReader("Magazzino.txt"));
FileWriter toFile = new FileWriter(magazzino);
String oldContent="";
String line;
String lineToReplace = prodCode + " " + amountRequest(prodCode);
String newLine = prodCode + " " + newAmount;
while((line = fromFile.readLine()) != null){
oldContent = oldContent + line + "\n";
System.out.println("leggendo " + line);
}
System.out.println(oldContent);
String newContent = oldContent.replaceAll(lineToReplace, newLine);
toFile.write(newContent);
toFile.close();
fromFile.close();
}catch(IOException e){
e.printStackTrace();
}
}
And the result of it is that it won't enter the while cycle because the first readLine result null, though the file is correctly formatted, the 'amountRequest' function works properly and the input is correct.
Magazzino.txt:
1 12
3 25
4 12
You're probably having trouble because you're trying to read and write the file at the same time, with different file handles. I'd suggest reading the file first, then closing the FileReader, then creating a FileWriter to write to it.
The issue is that before you have read the contents of the file, you are creating an instance of FileWriter which will clear the file.
FileWriter toFile = new FileWriter("Magazzino.txt"); will clear the file
The solution is to just create the instance of FileWriter after you are done reading the file.
public static void modifyAmount(String prodCode, String newAmount){
try{
File magazzino = new File("Magazzino.txt");
BufferedReader fromFile = new BufferedReader(new FileReader("Magazzino.txt"));
String oldContent="";
String line;
String lineToReplace = prodCode + " " + amountRequest(prodCode);
String newLine = prodCode + " " + newAmount;
while((line = fromFile.readLine()) != null){
oldContent = oldContent + line + "\n";
System.out.println("leggendo " + line);
}
fromFile.close();
System.out.println(oldContent);
String newContent = oldContent.replaceAll(lineToReplace, newLine);
FileWriter toFile = new FileWriter(magazzino);
toFile.write(newContent);
toFile.close();
}catch(IOException e){
e.printStackTrace();
}
}
You open a file twice, simultaneously for reading and writing.
As soon as you do this line,
FileWriter toFile = new FileWriter(magazzino);
your file is erased. Check it yourself.
Actually, with this line you are creating a new empty file for writing instead of the old one.
I'd suggest read file, then close, then write.
You can also try to pen file for append : new FileWriter("filename.txt", true);
This will not erase old file, allowing you to read it. But the new data will be appended to the end, though.
If you want to use you file as a state or storage, I'd suggest to look at sqlite: https://www.sqlite.org/index.html
I have written this program to compare 2 files. They are 500mb to 2.8gb in size and are created every 6 hours. I have 2 files from 2 sources (NMD and XMP). They are broken up into lines of text that have fields separated by the pipe(|) character. Each line is a single record and may be up to 65,000 characters long. The data is about TV shows and movies, showing times and descriptive content. I have determined that any particular show or movie has a minimum of 3 pieces of data that will uniquely identify that show or movie. IE: CallSign, ProgramId and StartLong. The two sources for this data are systems called NMD and XMP hence that acronym added to various variables. So my goal is to compare a file created by NMD and one created by XMP and confirm that everything that NMD produces is also produced by XMP and that the data in each matched record is the same.
What I am trying to accomplish here is this:
1. Read the NMD file record by record for the 3 unique data fields.
2. Read the XMP file record by record and look for a match for the current record in the NMD file.
3.The NMD file should iterate one record at a time. Each NMD record should then be searched for in the entire XMD file, record by record for that same record.
4. Write a log entry in one of 2 files indicating success or failure and what that data was.
What is happening is the first record in each file is read, but then no records after that get read. As a result, the end of neither file is ever reached and no matches are ever found. My success.log and failure.log file never show any data in them. In the outer do/while loop, System.out displays a single line of text. IE: The first record in the file. In the inner do/while loop System.out prints the same data over and over and over which is also from the first record in the file. Isn't this proof that the program isn't iterating record by record through the two source files?
So onto the actual code...
import java.io.*;
public class FileParse {
public static void main(String[] args) throws java.io.IOException {
String epgsRecordNMD = null;
String epgsRecordXMP = null;
BufferedWriter logSuccessWriter = null;
BufferedWriter logFailureWriter = null;
BufferedReader readXMP = null;
BufferedReader readNMD = null;
readNMD = new BufferedReader(new FileReader("d:testdataNMD.txt"));
do {
epgsRecordNMD = readNMD.readLine();
String[] epgsSplitNMD = epgsRecordNMD.split("\\|");
String epgsCallSignNMD = epgsSplitNMD[0];
String epgsProgramIdNMD = epgsSplitNMD[2];
String epgsStartLongNMD = epgsSplitNMD[9];
System.out.println("epgsCallsignNMD: " + epgsCallSignNMD + " epgsProgramIdNMD: " + epgsProgramIdNMD + " epgsStartLongNMD: " + epgsStartLongNMD );
do {
readXMP = new BufferedReader(new FileReader("d:testdataXMP.txt"));
epgsRecordXMP = readXMP.readLine();
String[] epgsSplitXMP = epgsRecordXMP.split("\\|");
String epgsCallSignXMP = epgsSplitXMP[0];
String epgsProgramIdXMP = epgsSplitXMP[2];
String epgsStartLongXMP = epgsSplitXMP[9];
System.out.println("epgsCallsignXMP: " + epgsCallSignXMP + " epgsProgramIdXMP: " + epgsProgramIdXMP + " epgsStartLongXMP: " + epgsStartLongXMP);
if (epgsCallSignXMP.equals(epgsCallSignNMD) && epgsProgramIdXMP.equals(epgsProgramIdNMD) && epgsStartLongXMP.equals(epgsStartLongNMD)) {
logSuccessWriter = new BufferedWriter (new FileWriter("d:success.log", true));
logSuccessWriter.write("NMD match found in XMP" + "epgsCallsignNMD: " + epgsCallSignNMD + " epgsProgramIdNMD: " + epgsProgramIdNMD + " epgsStartLongNMD: " + epgsStartLongNMD);
logSuccessWriter.write("\n");
logSuccessWriter.close();
System.out.println ("Match found");
}
} while (epgsRecordXMP != null);
logFailureWriter = new BufferedWriter (new FileWriter("d:failure.log", true));
logFailureWriter.write("NMD match not found in XMP" + "epgsCallsignNMD: " + epgsCallSignNMD + " epgsProgramIdNMD: " + epgsProgramIdNMD + " epgsStartLongNMD: " + epgsStartLongNMD);
logFailureWriter.write("\n");
logFailureWriter.close();
System.out.println ("Match NOT found");
} while (epgsRecordNMD != null);
readNMD.close();
readXMP.close();
}
}
do {
readXMP = new BufferedReader(new FileReader("d:testdataXMP.txt"));
You sure you want this in a loop? You are opening the same file over and over again.
Why not do something like this?
BufferedReader br = new BufferedReader(new FileReader("whateverfile.dat"));
BufferedReader br2 = new BufferedReader(new FileReader("whateverfile2.dat"));
String data;
String data2;
while(data = br.readLine() != null)
{
// do whatever you want, for example found 3 unique records
while(data2 = br2.readLine() != null)
{
// do whatever you want
}
}
Just like what OldProgrammer said, you're opening the file multiple times. You just need to ensure that the reader / streamer is open and iterate whatever you want then close it.
File outFile = new File("D:\\output.txt");
BufferedWriter wb = new BufferedWriter(new FileWriter(outFile));
while (resultSet.next()) {
int attr_id = resultSet.getInt("int_id");
String stringValue = resultSet.getString("StringValue");
String name = resultSet.getString("Name");
int index = stringValue.indexOf(".");
int valueLength = stringValue.length();
if(isNumeric(stringValue)) {
//if(index != -2 ) {
if(index != (valueLength - 2)) {
String string1 = Double.valueOf(stringValue).toString();
System.out.println("converted values : " +string1);
System.out.println("stringValue : " +stringValue);
System.out.println("intValue : " +int_id);
wb.write( stringValue + "," + int_id + "," + string1 );
wb.newLine();
}
}
}
Above is my part of the code, from resultset i'm writing the data into a file. However the code is not printing values in output.txt file but i could see the result in console.
if i remove the commented line and comment if(index != (valueLength - 2)) { this line, the java code is creating output.txt with values.
What's wrong?
probably need to just call flush and/or close on your BufferedWriter when you are done.
The reason why your code is not writing to the file is because you never push the data from the Writer to the actual file.
Think of BufferedWriters as an email you are sending to a coworker. When you use:
wb.write( stringValue + "," + int_id + "," + string1 );
it is like you are typing the email to your coworker, and defining the message to them. BUT, since you did not press "send email", your coworker will never see the message. The same concept can be applied here.
You are filling the writer with a bunch of data, but you are never sending the data to the file that you are trying to write to. There are two ways that you can do this, the first being to "flush" the writer (see documentation HERE). You can do this by calling
wb.flush();
This is the equivalent of pressing "send email", and will write the data to the file that you are editing. The second method would be to "close" the writer (see documenation HERE). The reason that this works is because the BufferedWriter's close method flushes the stream first, before closing the stream. This can be done by calling
wb.close();
Although, it would not be wise to do so until you are fully done editing the file, as it can no longer be accessed.
The following is your code edited to flush the stream after every record you are writing, and then close the stream after all records have been processed. Note the locations of wb.flush() and wb.close().
File outFile = new File("D:\\output.txt");
BufferedWriter wb = new BufferedWriter(new FileWriter(outFile));
while (resultSet.next()) {
int attr_id = resultSet.getInt("int_id");
String stringValue = resultSet.getString("StringValue");
String name = resultSet.getString("Name");
int index = stringValue.indexOf(".");
int valueLength = stringValue.length();
if(isNumeric(stringValue)) {
//if(index != -2 ) {
if(index != (valueLength - 2)) {
String string1 = Double.valueOf(stringValue).toString();
System.out.println("converted values : " +string1);
System.out.println("stringValue : " +stringValue);
System.out.println("intValue : " +int_id);
wb.write( stringValue + "," + int_id + "," + string1 );
wb.newLine();
wb.flush();
}
}
}
wb.close();
I have this code here that takes in 3 arguments, A Directory, a Filename, and a number. The program creates the filename in the directory and writes the number in it. So I can say...
>java D: myName.txt Clay 100
which will create a file named myName.txt in D: and says 100 in it.
If myName is taken up, it changes the name to myName(2), then myName(3) (if myName(2) taken up). The only problem is that when it changes the name to myName(2) and writes, it overwrites myName. I dont want it to overwrite myName, I want it to just create a new file with that name. Ive looked at similar questions and the common answer is the flush and close the writer which ive done And it still doesnt work.
Any help would be appreciated, here is my code so fart...
import java.io.*;
public class filetasktest{
public static void main(String[] args) throws IOException{
int i = 2;
String directory = args[0];
if (directory.substring(directory.length() - 1) != "/"){
directory += "/";
}
String contactName = args[1];
String contactNumber = args[2];
String finalDirectory = directory + contactName + ".contact";
File f = new File(finalDirectory);
while (f.exists()){
finalDirectory = directory + contactName + "(" + ("" + i) + ")" + ".contact";
f.renameTo(new File(finalDirectory));
i++;
}
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(finalDirectory), "utf-8"));
writer.write(contactNumber);
} catch (IOException ex){
System.out.println(ex.getMessage());
} finally {
try {
writer.close();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
}
You need to use append mode
new BufferedWriter(new FileWriter(yourFileName, true));
here, true means that the txt should be appended at the end of file.
Check the FileWriter javadoc for more information.
Your problem is here:
while (f.exists()){
finalDirectory = directory + contactName + "(" + ("" + i) + ")" + ".contact";
f.renameTo(new File(finalDirectory));
i++;
}
The renameTo method does not change the path of a File object; it renames a file on disk. The path of f stays the same throughout the loop: it starts out as D:/myName.txt and if a file by that name exists, the file is renamed as D:/myName(1).txt. The variable f still holds the path D:/myName.txt, which no longer names a file, and the content is written to D:/myName(1).txt, overwriting the previous content.
To fix this issue change the loop to:
while (new File(finalDirectory).exists()){
finalDirectory = directory + contactName + "(" + ("" + i) + ")" + ".contact";
i++;
}
Take a look at FileInputStream(String, boolean) which will allow you to flag if the file should be appended or overwritten