Deleting a specific line from a text file in Java - java

I am setting up a rank system where each member has a username and a rank. The program reads the username and rank from a text file and assigns it to the user.
One username and rank per line, such as:
user1 1
user2 2
user3 3
I have set up a program to add usernames and ranks to the text file, however I cannot seem to figure out how to delete a specific user from the list, such as if I wanted to only delete user 2 and his/her rank and leave the other two, however it is important that afterwards there isn't a blank line left behind.
Just for reference here is the code for how I write it to the file in the first place:
try {
BufferedWriter out = new BufferedWriter(new FileWriter("stafflist.txt", true));
for (int i = 0; i < 1; i++) {
out.newLine();
out.write(target.getUsername() + " " + target.getRights());
}
out.close();
SerializableFilesManager.savePlayer(target);
if (loggedIn) {
target.getPackets().sendGameMessage(modString + Utils.formatPlayerNameForDisplay(member.getUsername()) + "!", true);}
member.getPackets().sendGameMessage(successString + Utils.formatMemberNameForDisplay(target.getUsername()) + " to a Moderator.",true);
loggedIn = false;
} catch (IOException e) {
System.out.println("GiveMod - Can't find stafflist.txt");
}
return true;

You cannot delete data from the middle of a file (without leaving nulls). You need to rewrite at least what underneath it. A Simple solution would be loading everything in memory, remove that line and dump the collection again.
An alternative solution would be to:
Open a FileChannel from a RandomAccessFile
read the file line by line and keep the file-pointer of the line head. fileChannel.position();file.readLine(); load what comes after that into a collection. truncate the file from that position file.setLength(linePosition); and then dump the collection at the end of the file.
If your data doesn't fit in memory then you can use a temp file instead of a collection. Create a temp-file File.createTempFile(...), read the remaining data line by line and write to temp, truncate the original file ,read temp line by and write to original.
OR, guess what, use a database.

There seems to be an issue in your for loop. It is looping between 0 and 1, so I think the output you posted is incorrect. Anyway, if you want to only print out certain lines you can filter it as follows:
for (int i = 0; i < 1; i++) {
if(!target.getUsername().equals("user2")){
out.newLine();
out.write(target.getUsername() + " " + target.getRights());
}
}

Read the file into some Collection, remove desired users and rewrite the file using the modified Collection.

Related

How to update txt file in java

I have JTable where I show data from text file:
Now, for deleting I have method like this:
private void delete(ActionEvent evt) {
DefaultTableModel model = (DefaultTableModel) tblRooms.getModel();
// get selected row index
try {
int SelectedRowIndex = tblRooms.getSelectedRow();
model.removeRow(SelectedRowIndex);
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex);
}
}
And action listener:
btnDelete.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
delete(e);
}
});
It will delete row in JTable and thats okey, but my text file have 7 splits, where last spit is for logical deleting. So, if false - room isn't deleted.
13|family room|name apartman|4|true|true|true|false
14|superior room|super room|2|true|false|false|false
15|room|room for one|1|false|false|true|false
0|MisteryRoom|Mistery|0|true|true|free|false
How to delete certain room from JTable on correct way, and change from false to true?
For example if I click on super room, how to delete exactly that room.
This sort of thing is best handled using a database rather than a text file for a great number of reasons, never the less since you are utilizing a text file as your data storage I will demonstrate one way to replace a value (substring) in a specific data text file line.
Now, the following method can be used to modify any piece of field data on any file data line...even the room number so keep that in mind. You will need to ensure that you only modify when it's best to do so:
/**
* Updates the supplied Room Number data within a data text file. Even the
* Room Number can be modified.
*
* #param filePath (String) The full path and file name of the Data File.
*
* #param roomNumber (Integer - int) The room number to modify data for.
*
* #param fieldToModify (Integer - int) The field number in the data line to
* apply a new value to. The value supplied here is to be considered 0 based
* meaning that 0 actually means column 1 (room number) within the file data
* line. A value of 7 would be considered column 8 (the deleted flag).
*
* #param newFieldValue (String) Since the file is string based any new field
* value should be supplied as String. So to apply a boolean true you will need
* to supply "true" (in quotation marks) and to supply a new room number that
* room number must be supplied a String (ie: "666").
*
* #return (Boolean) True if successful and false if not.
*/
public boolean updateRoomDataInFile(String filePath, int roomNumber,
int fieldToModify, String newFieldValue) {
// Try with resources so as to auto close the BufferedReader.
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
// Add the data file contents to a List interface...
List<String> dataList = new ArrayList<>();
while ((line = reader.readLine()) != null) {
dataList.add(line);
}
for (int i = 0; i < dataList.size(); i++) {
line = dataList.get(i).trim(); // Trim off any leading or trailing whitespaces (if any).
// Skip Blank lines (if any) and skip Comment lines (if any).
// In this example file comment lines start with a semicolon.
if (line.equals("") || line.startsWith(";")) {
continue;
}
//Split each read line so as to collect the desired room number
// since everything will always be based from this unique ID number.
// Split is done baesed on the Pipe (|) character since this is
// what is implied with your data example.
String[] roomData = line.split("\\|");
// Get the current file data line room number.
// Make sure the first piece of data is indeed a valid integer room
// number. We use the String.matches() method for this along with a
// regular expression.
if (!roomData[0].trim().matches("\\d+")) {
// If not then inform User and move on.
JOptionPane.showMessageDialog(null, "Invalid room number detected on file line: "
+ (i + 1), "Invalid Room Number", JOptionPane.WARNING_MESSAGE);
continue;
}
// Convert the current data line room number to Integer
int roomNum = Integer.parseInt(roomData[0]);
// Does the current data line room number equal the supplied
// room number?
if (roomNum != roomNumber) {
// If not then move on...
continue;
}
// If we reach this point then we know that we are currently on
// the the data line we need and want to make changes to.
String strg = ""; // Use for building a modified data line.
// Iterate through the current data line fields
for (int j = 0; j < roomData.length; j++) {
// If we reach the supplied field number to modify
// then we apply that modification to the field.
if (j == fieldToModify) {
roomData[j] = newFieldValue;
}
// Build the new data line. We use a Ternary Operator, it is
// basicaly the same as using a IF/ELSE.
strg += strg.equals("") ? roomData[j] : "|" + roomData[j];
}
// Replace the current List element with the modified data.
dataList.set(i, strg);
}
// Rewrite the Data File.
// Try with resources so as to auto close the FileWriter.
try (FileWriter writer = new FileWriter(filePath)) {
// Iterate through the List and write it to the data file.
// This ultimately overwrites the data file.
for (int i = 0; i < dataList.size(); i++) {
writer.write(dataList.get(i) + System.lineSeparator());
}
}
// Since no exceptions have been caught at this point return true
// for success.
return true;
}
catch (FileNotFoundException ex) {
Logger.getLogger("updateFileRoomStatus()").log(Level.SEVERE, null, ex);
}
catch (IOException ex) {
Logger.getLogger("updateFileRoomStatus()").log(Level.SEVERE, null, ex);
}
// We must of hit an exception if we got
// here so return false for failure.
return false;
}
To use this method you might want to do it this way:
private void delete() {
DefaultTableModel model = (DefaultTableModel) tblRooms.getModel();
try {
// get selected row index
int SelectedRowIndex = tblRooms.getSelectedRow();
// Get out if nothing was selected but the button was.
if (SelectedRowIndex == -1) { return; }
int roomNumber = Integer.parseInt(model.getValueAt(SelectedRowIndex, 0).toString());
updateRoomDataInFile("HotelRoomsData.txt", roomNumber, 7, "true");
model.removeRow(SelectedRowIndex);
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex);
}
In the code above a data file name of "HotelRoomsData.txt" was supplied. This of course assumes the the data file contains that name and that is is located within the root folder (directory) of your particular project. If the file is named differently and it is located in some completely different location then you will need to change this to the full path and file name of the data file, for example:
"C:/Users/Documents/MyDataFile.txt"
The code really isn't that long, it's just that there are a lot of comments accompanying it so as to explain things. Of course these comments can be deleted from the code.

How can I update contents of a text file

My assignment requires me to make a simple mathGame that generates random math problems. The program has to record the amount correct and the amount incorrect in a text file. It also has to update the statistics of an existing file instead of overwrite them.
This is how I am creating each file:
try {
writer = new FileWriter(userName + " Stats.txt", true);
outputfile = new PrintWriter (writer);
} catch (IOException e) {
}
Here is what is being written to the file:
public static void saveStats () {
outputfile.println();
outputfile.println("Correct Answers:"+ correct);
outputfile.println("Incorrect Answers:" + incorrect);
if (money > 0) {
outputfile.printf("Earnings: $%.2f", money);
outputfile.println();
}
else {
float moneyNegative = Math.abs(money);
outputfile.printf("Earnings: -$%.2f", moneyNegative);
outputfile.println();
}
outputfile.flush();
}
Here is a sample output of the text file after quitting the program:
Correct Answers:0
Incorrect Answers:1
Earnings: -$0.03
correct, incorrect, and money are all global variables and are initialized to 0. If I restart the program, my file will still exist but the values of Correct Answers, Incorrect Answers, and Earnings will be overwritten or a new entry to the file will be added. I just want to update it.
Here is all of my code: https://pastebin.com/1Cmg5Rt8
Have you tried getting the original text first, then writing it before you start writing what you need to?
Basically, you take the input from the file you have at the beginning
Scanner s = new Scanner(new File("FileName.txt"));
Then, you can loop through it and write to the file.
while(s.hasNextLine())
{
outputfile.println(s.nextLine());
}
After you have all of your previous file rewritten into the text, you can run the rest of your code and not have the information overwritten.
Also, instead of try-catch you can just throw IOException

Append to a certain part of a text file in Java

I have an assignment where I have created a program to sell and order electronic devices and update two text files whenever a new sale/order has been made.
I found a way to update the text file instead of overwriting it so any old orders/sales are not lost and the new ones are added to the end of the file, but my assignment requires me to have the text file in the following form:
SALES
{
SALE
{
(Sale info here)
}
SALE
{
(Another sale info here)
}
}
The SALES { } needs to appear once in the whole file, and I need to update the file with each SALE { }. Can I make it so that
the writer writes only after SALES } (therefore in the 3rd line) and before } (so in the second to last line), even after restarting the application?
This is part of the code of my writer:
File file1= null;
BufferedWriter writer=null;
try {
file1=new File(path);
}
catch (NullPointerException e) {
System.err.println ("Not Found.");
}
try {
writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file1, true)));
}
catch (FileNotFoundException e) {
System.err.println("Error opening file for writing.");
}
try
{
writer.write("SALES " + "\n" + "{");
//Writer writes sale info here
writer.write("\n" + "}");
}
catch (IOException e) {
System.err.println("Write error!");
}
Basically as of now, it creates SALES{ } every time I run the program, which is something I don't want.
Another way I thought of doing this is basically start the file with the following:
SALES
{
}
and just overwrite the last line with every new order, and at the end of each execution I will add another } in the end which will close the upper SALES {. But I also do not know how to do that.
Sorry if this sounds very amateurish. Thank you for any answers beforehand.
One way you can give a try is by checking whether "SALES
{" string is present in your file. If present you may directly write sales info else write the entire file.
You can include following snippet in your code to scan the file line by line as follows:
Scanner scanner = new Scanner(file1);
while(scanner.hasNextLine()){
if("SALES{".equals(scanner.nextLine().trim())){
//Writer writes sale info here
break;
}else{
writer.write("SALES " + "\n" + "{");
//Writer writes sale info here
writer.write("\n" + "}");
}
}
First of all, use this as a line separator:
String lineSeparator = System.getProperty("line.separator");
Why? diferent systems use diferent ways to separate the lines ( \n < linux, \r\n < windows, \r < mac).
In your code you will change de +"\n"+ to + lineSeparator + .
The best way to write this is to use a collection (array) of Sale Objects and then you will interate through this collection, like:
for(Sale sale : sales){
sale.getters // Infos
//write +\t+ (tab) and save infos
}
and then finish with "+}+"
For me its better to always create a new file in this case.

How can I format output values?

This my output file. I'used standart "System.out.print()" for writing operation. There is a tab space between each value. But due to difference of word size, format looks bad. How can I fix the format of output?
This should print an element of your String by column every two tabs. If you need more tabs because the names are too long, you can increase the number of tabs in //here rememberingh that every tab have a length of 8 characters.
try{
FileOutputStream file = new FileOutputStream("filename.txt", true);
PrintStream out = new PrintStream(file);
String s=line;
String[] items = s.split("\t");
for(String item : items){
if(item.length()<8){ //here
out.print(item + "\t\t" ); //here
}else{
if(item.length()>16){ //here
out.print(item + "\t" );
}
}
}catch (IOException e){
System.out.println("Error: " + e);
System.exit(1);
}
}
You can write to a .csv file which can be opened in Excel and will give you data divided by column.
Use System.out.format, you can specify width to make things consistent.
Check out the Oracle Tutorial explanation.

Java program is creating extra columns in csv file

I am creating a csv file in a JDBC program that pulls data and then writes it to the csv file. The problem is that some of the data comes in like "Birmingham, AL" and when the program sees the "," it is creating a new column when really it should all be in one column. The first 15000 rows come in correctly with no commas, but then some commas start appearing and it is creating new columns where it shouldn't. I was wondering if there was a way to catch and avoid this or to workaround this issue. I hope I'm explaining this well enough. Feel free to ask for more information.
EDIT: Here is the snippet of code that does the work.
while (rs.next()) {
for (int i = 0; i < cols; i++) {
if (i > 0) {
Object value = rs.getObject(i);
if (value == null || rs.wasNull())
out.write("NULL" + ",");
else
out.write(value.toString() + ",");
}
}
out.newLine();
}
out.close();
writer.close();
instead of
out.write(value.toString() + ",");
try
out.write("\""+value.toString() + "\",");

Categories

Resources