Append to a certain part of a text file in Java - 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.

Related

OutputStreamWriter only writing one item into file

I have used the following code to write elements from an arraylist into a file, to be retrieved later on using StringTokenizer. It works perfect for 3 other arraylists but somehow for this particular one, it throws an exception when reading with .nextToken() and further troubleshooting with .countTokens() shows that it only has 1 token in the file. The delimiters for both write and read are the same - "," as per the other arraylists as well.
I'm puzzled why it doesnt work the way it should as with the other arrays when I have not changed the code structure.
=================Writing to file==================
public static void copy_TimeZonestoFile(ArrayList<AL_TimeZone> timezones, Context context){
try {
FileOutputStream fileOutputStream = context.openFileOutput("TimeZones.dat",Context.MODE_PRIVATE);
OutputStreamWriter writerFile = new OutputStreamWriter(fileOutputStream);
int TZsize = timezones.size();
for (int i = 0; i < TZsize; i++) {
writerFile.write(
timezones.get(i).getRegion() + "," +
timezones.get(i).getOffset() + "\n"
);
}
writerFile.flush();
writerFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
==========Reading from file (nested in thread/runnable combo)===========
public void run() {
if (fileTimeZones.exists()){
System.out.println("Timezone file exists. Loading.. File size is : " + fileTimeZones.length());
try{
savedTimeZoneList.clear();
BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("TimeZones.dat")));
String lineFromTZfile = reader.readLine();
while (lineFromTZfile != null ){
StringTokenizer token = new StringTokenizer(lineFromTZfile,",");
AL_TimeZone timeZone = new AL_TimeZone(token.nextToken(),
token.nextToken());
savedTimeZoneList.add(timeZone);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
}
===================Trace======================
I/System.out: Timezone file exists. Loading.. File size is : 12373
W/System.err: java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
at com.cryptotrac.trackerService$1R_loadTimeZones.run(trackerService.java:215)
W/System.err: at java.lang.Thread.run(Thread.java:764)
It appears that this line of your code is causing the java.util.NoSuchElementException to be thrown.
AL_TimeZone timeZone = new AL_TimeZone(token.nextToken(), token.nextToken());
That probably means that at least one of the lines in file TimeZones.dat does not contain precisely two strings separated by a single comma.
This can be easily checked by making sure that the line that you read from the file is a valid line before you try to parse it.
Using method split, of class java.lang.String, is preferable to using StringTokenizer. Indeed the javadoc of class StringTokenizer states the following.
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
Try the following.
String lineFromTZfile = reader.readLine();
while (lineFromTZfile != null ){
String[] tokens = lineFromTZfile.split(",");
if (tokens.length == 2) {
// valid line, proceed to handle it
}
else {
// optionally handle an invalid line - maybe write it to the app log
}
lineFromTZfile = reader.readLine(); // Read next line in file.
}
There are probably multiple things wrong, because I'd actually expect you to run into an infinite loop, because you are only reading the first line of the file and then repeatedly parse it.
You should check following things:
Make sure that you are writing the file correctly. What does the written file exactly contain? Are there new lines at the end of each line?
Make sure that the data written (in this case, "region" and "offset") never contain a comma, otherwise parsing will break. I expect that there is a very good chance that "region" contains a comma.
When reading files you always need to assume that the file (format) is broken. For example, assume that readLine will return an empty line or something that contains more or less than one comma.

Loading data from an RPG game

So I'm working on a simple RPG game. I want to add an option to load progress through the game, but I guess I'm not that familiar with Java to do it without issues. The idea is to save the game on checkpoints, and load a saved data when the game continues. I'm getting an error with a loadGame method, and I guess it's related to the fact that the data I'm trying to load are all different data types. health and level are integers, while equippedItem is a string.
Here are just two methods, saveGame, and loadGame, because the code is a bit too long to simply paste it in the whole. I'll put additional code if needed of course.
public static void saveGame() {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("savedGame.txt"));
bw.write("Your health is " + player.getHealth());
bw.newLine();
bw.write("Your level is " + player.getLevel());
bw.newLine();
bw.write("" + player.equippedItem);
bw.close();
}
catch (Exception e) {
System.out.println("There's an error.");
}
}
The saveGame() doing its work well, it stores the data in the file. The issue is with the loadGame() method.
public void loadGame() {
try {
BufferedReader br = new BufferedReader(new FileReader("savedGame.txt"));
player.getHealth();
player.getLevel();
player.equippedItem;
br.close();
} catch (Exception e) {
System.out.println("There's an error.");
}
}
The result of player.getHealth() and player.getLevel() is ignored, and it's probably the data type issue I've mentioned.
What you're doing is creating a text file in saveGame(), 'opening' that save file in loadGame() but not accessing the data inside.
You have correctly created a BufferedReader, but you're using it incorrectly. You will need to use br.readLine() to read the text file which will return a string like "Your health is 123".
To update the state of the player with this data, you could add something like this inside loadGame():
player.setHp(parseHp(br.readLine()));
player.setLevel(parseLevel(br.readLine()));
... // and so on
The parse methods would take a String input like "Your health is 123" and return int 123.

Java - Delete file after reading from it

I am trying to figure out why my inputFile.delete() will not delete the file. After looking at numerous topics it looks like something is still using the file and hence it won't delete. But I can't figure it out. What am I missing??
File inputFile = new File("data/Accounts.txt");
File tempFile = new File("data/tmp.txt");
try {
tempFile.createNewFile();
BufferedReader reader = new BufferedReader(new FileReader(inputFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
String line;
int i = 0;
for (User u : data) {
String toRemove = getIDByUsername(username);
while ((line = reader.readLine()) != null) {
if (line.contains(toRemove + " ")) {
line = (i + " " + username + " " + getStatusByUsername(username) + " " + password);
}
writer.write(line + "\n");
i++;
}
}
reader.close();
writer.close();
} catch (FileNotFoundException e) {
ex.FileNotFound();
} catch (IOException ee) {
ex.IOException();
} finally {
inputFile.delete();
tempFile.renameTo(inputFile);
}
You can have that much shorter and easier by using java.nio:
public static void main(String[] args) {
// provide the path to your file, (might have to be an absolute path!)
Path filePath = Paths.get("data/Accounts.txt");
// lines go here, initialize it as empty list
List<String> lines = new ArrayList<>();
try {
// read all lines (alternatively, you can stream them by Files.lines(...)
lines = Files.readAllLines(filePath);
// do your logic here, this is just a very simple output of the content
System.out.println(String.join(" ", lines));
// delete the file
Files.delete(filePath);
} catch (FileNotFoundException fnfe) {
// handle the situation of a non existing file (wrong path or similar)
System.err.println("The file at " + filePath.toAbsolutePath().toString()
+ " could not be found." + System.lineSeparator()
+ fnfe.toString());
} catch (FileSystemException fse) {
// handle the situation of an inaccessible file
System.err.println("The file at " + filePath.toAbsolutePath().toString()
+ " could not be accessed:" + System.lineSeparator()
+ fse.toString());
} catch (IOException ioe) {
// catch unexpected IOExceptions that might be thrown
System.err.println("An unexpected IOException was thrown:" + System.lineSeparator()
+ ioe.toString());
}
}
This prints the content of the file and deletes it afterwards.
You will want to do something different instead of just printing the content, but that will be possible, too ;-) Try it...
I am trying to figure out why my inputFile.delete() will not delete the file.
That's because the old file API is crappy specifically in this way: It has no ability to tell you why something is not succeeding. All it can do, is return 'false', which it will.
See the other answer, by #deHaar which shows how to do this with the newer API. Aside from being cleaner code and the newer API giving you more options, the newer API also fixes this problem where various methods, such as File.delete(), cannot tell you the reason for why it cannot do what you ask.
There are many, many issues with your code, which is why I strongly suggest you go with deHaar's attempt. To wit:
You aren't properly closing your resources; if an exception happens, your file handlers will remain open.
Both reading and writing here is done with 'platform default encoding', whatever that might be. Basically, never use those FileReader and FileWriter constructors. Fortunately, the new API defaults to UTF_8 if you fail to specify an encoding, which is more sensible.
your exception handling is not great (you're throwing away any useful messages, whatever ex.FileNotFound() might be doing here) - and you still try to delete-and-replace even if exceptions occur, which then fail, as your file handles are still open.
The method should be called getIdByUsername
Your toRemove string is the same every time, or at least, the username variable does not appear to be updated as you loop through. If indeed it never updates, move that line out of your loop.

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

Java Exception Handling and File I/O

[ I am out of ideas I need a to write a code that writes and reads text files within theprocessfiles method and a code that counts and print the total number of borrowers As part of my home I need to write a class that writes and reads text files.
public void
processFiles()throws FileNotFoundException
{
[ I am struggling to write a code that actually reads and writes a text file to a windows explorer folder ]
try
{
System.out.println("Enter your Firstname");
Scanner sc=new Scanner(System.in);
String firstName=sc.nextLine();
System.out.println("Enter your lastname");
String lastName=sc.nextLine();
System.out.println("Enter your library number");
String libraryNumber=sc.nextLine();
System.out.println("Enter the number of books on loan");
int numberOfBooks=sc.nextInt();
System.out.println(firstName +" "+ lastName +" "+ libraryNumber +" "+ numberOfBooks);
int count// I am struggling to to write a code that counts the borrowers and diplay it on the windows page.
int total// I am struggling to to write a code that displays the total number of borrowers to the windows page.
input.close();
output.close();
}
catch (InputMismatchException e) [This is the catch method]
{
System.out.println("Invalid");
}
catch (Exception e) this is the catch method
{
[ this is catch statement ] System.out.println("Wrong exception");
}
input.close();[ this is the input close]
output.close(); [and output close statements]
}
}
[I would be much appreciated if anyone could help me with this.]
Nobody can write the full code for you. However, here are a few tips:
Keep that link open at all times.
Separate the scanning process from the I/O process; keep the try blocks as small as possible.
Second, to get a path to a file, use Paths.get():
final Path path = Paths.get(someString);
To check whether a file exists, use:
Files.exists(path);
To open a reader to read a file as text (NOT binary), use:
Files.newBufferedReader(path, StandardCharsets.UTF_8);
To open a writer to write a file as text (NOT binary), use:
Files.newBufferedWriter(path, StandardCharsets.UTF_8);
Use the try-with-resources statement:
try (
// open I/O resources here
) {
// operate with said resources
} catch (FileSystemException e) {
// fs error: permission denied, file does not exist, others
} catch (IOException e) {
// Other I/O error
}
Java closes your resources for you right after the try block (ie, after the first pair of curly brackets).

Categories

Resources