Writing file when closing window - java

I'm writing a Restaurant Program.
When the user confirms his order, the order gets stored in an array of type order. Why? because when the user chooses to close the program, all orders get saved in a file with item's names and information about each item.
Also, every order object has an array of type item inside it!
Could you help me on how to write that file?
I know it'll be in the method processWindowEvent.
This is my try, i know that i should remove textArea.getText() but i don't know how to print all items, neither.
protected void processWindowEvent(WindowEvent e){
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
JOptionPane.showMessageDialog(this,"All operation have been saved ");
try{
outFile=new File("Orderslist.txt");
out=new FileOutputStream(outFile);
ob=new PrintWriter(out);}
catch(IOException M){M.getMessage(); }
for(int i=0;i<o2.length;i++){
if(o2[i]!=null){
if(o2[i].getCount()<=4)
ob.println(o2[i].toString()+"\n--------------\n"+textArea.getText()+"--------------\n"+"\nTotal: "+o2[i].getTotalPrice());
else if(o2[i].getCount()>4)
ob.println(o2[i].toString()+"\n--------------\n"+textArea.getText()+"--------------\n"+"\nTotal Price#: "+o2[i].getTotalPrice()+"\n\nDiscount 20%\n\n--------------\nTotal price#: "+(o2[i].getTotalPrice()-(o2[i].getTotalPrice()*0.2)));
}
}

In the constructor of your Widnow add this:
public Window() {
this.addWindowListener(new WindowAdapter(){
#Override
public void windowClosing(WindowEvent arg0) {
writeFile(textArea.getText()); //Call your method
System.exit(0);
}
});
...
}
For writing the file:
File file = new File("myFile.txt");
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write("Texto to write");
bw.close();

After ob.println() do ob.close(); or ob.flush();.
If you dont close the stream or flush the stream , nothing will be printed in your file.

Really this isn't the best design, you should write changes to the file immediately as they are made. The reason for this is that if the application closes for any other reason (power cut, task manager kill, crash, etc) then you don't want to lose the user's data. It would also be worth automatically backing up that file (for example copying it after startup) so if you corrupt the current session somehow you can revert.
To actually implement the saving you want to use a FileOutputStream of some sort but the exact implementation will vary a lot depending on the format that you want the data inside the stream. For example XML, JSON, plan text, binary serialization etc are all fairly easy but you need to pick one :)

Related

Best way to ensure streams that are opened inside a method call get closed

I'm calling a method to write some data to a CSV file in java. Inside that method, I'm using a FileWriter that throws an IOException. I'm wondering what the correct way to handle this exception is if I want to handle it in the outer method while also ensuring that the FileWriter gets closed.
I am thinking of two solutions:
Just handle the exception inside the method that opens the FileWriter.
Figure out a way to pass the FileWriter back to the calling method so that it may be closed.
Here's an example of what I'm talking about:
public static void outerFunc() {
// get some sort of data
try {
innerFunc(data);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
// can I close the FileWriter here somehow?
}
}
private static void innerFunc(Data data) throws IOException {
FileWriter csv = new FileWriter("result.csv")
// Write the data to the file
csv.flush();
csv.close();
}
Let me know what you guys think. I'm very open to the fact that I may be completely off base here and should be doing this a different way. Thank you in advance for any input!
The method that opens the resource should close it, and I would use the try-with-resources Statement. Like,
try (FileWriter csv = new FileWriter("result.csv")) {
// ...
}

How To Read and Load an Array?

I have provided the background info:
So we have are working on a project of creating Facebook Lite. And in it we have this array profiles[idx]; idx is the index number, nop is the number of profiles. There is a switch case for choosing options from the menu; the professor wants us that, when the user exits the program, it should save their profiles (profile consists of first name, last name, friends, age) and when the program loads, the code should be able to load all the profiles. It's complicated.
Here's my read/write code which doesn't seem to work. First, it just makes a file which has stuff like "Profile#21bcffb5" this written. Instead of First Name:, Last Name: etc (elements inside the array). Also it doesn't load the profiles and my program gets stuck in an endless loop.
public void write()
{
try{
PrintStream writer = new PrintStream( new File("ProfileData.txt"));
for (int i=0; i<nop; i++){
writer.println(profiles[idx]);
}
writer.close();
}
catch(IOException e){
System.out.println(e);
}
}
public void read()
{
try {
Scanner s = new Scanner ( new File("ProfileData.txt"));
while(nop>0){
System.out.println(profiles[idx]);
}
}
catch(IOException e){
System.out.println(e);
}
}
It is printing the memory location at which Profile object is stored accessed by profiles[idx]. You should implement toString() method in Profile class which will print all the properties of the object

How do I save the state of my program? [duplicate]

This question already has answers here:
How can I save the state of my program and then load it?
(2 answers)
Closed 6 years ago.
For my program I have two buttons, "Add" and "Save". When I click "Add" a button is added to the JPanel. My question is, how do I save the current state of my program with all the buttons the user added? Do I use serialization?
Here is a snippet of my code:
public class saveButton
{
//JFrame and JPanels have been declared earlier
class ClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String str = JOptionPane.showInputDialog("Name of button");
JButton b = new JButton(str);
frame.add(b);
}
}
ActionListener addButtonClicked = new ClickListener();
b.addActionListener(addButtonClicked);
class ClickListenerTwo implements ActionListener
{
public void actionPerformed(ActionEvent f)
{
//save all of the program
}
}
}
You can only serialize (meaning straight Java serialization) if your object and every non-transient member within the class supports serialization. This is not always possible.
However, you could define your own configuration object that contains the necessary state information and save it whenever (could be just before closing app, could be every time the state changes, it's up to you) and serialization might be a way to do it
It depends on how you save it. You can write the state onto a file and then recover it from there by reading it. The number of buttons and the order etc. You have to decide on the format on how you want to save it too. For example you may want to store in one line
Save,JButton,imageSrc,xpos,ypos
So when you read that line and split on ',' you know that Save is the text, JButton is the class, etc.
Hope this helps
I would write my own file format rather than deal with the overhead of Java's serialization. This has the benefit of being more easily readable in other languages and of slightly better performance. Furthermore, as #MadProgrammer pointed out the Serialization of Swing object is not currently supported and will not be compatible with future releases:
Warning: Serialized objects of this class will not be compatible with
future Swing releases. The current serialization support is
appropriate for short term storage or RMI between applications running
the same version of Swing. As of 1.4, support for long term storage of
all JavaBeans™ has been added to the java.beans package. Please see
XMLEncoder.
(link)
Here is an example:
public void saveState(){
File stateFile = new File("./stateFile");
FileOutputStream fos = new FileOutputStream(stateFile);
DataOutputStream dos = new DataOutputStream(fis);
for(JButton button : jButtons){ //store the buttons in an arraylist when they are created (you could also iterate over the added components and use instanceof)
dos.writeUTF(button.getText());
}
dos.writeUTF("end"); //have some sort of end marker
dos.flush();
dos.close();
fos.flush();
fos.close()
}
public void loadState(){
File stateFile = new File("./stateFile");
FileInputStream fis = new FileInputStream(stateFile);
DataInputStream dis = new DataInputStream(fis);
String name;
while(!(name = dis.readUTF()).equals("end")){
add(new JButton(name));
}
fis.close();
}

Java writes writes line multiple times?

static void goOut(String in) {
//instance variables
String fileCopy = currentLine + in;
try {
FileWriter writer = new FileWriter(output,true);
writer.write(line1 + System.getProperty("line.separator", "\r\n"));
writer.write(fileCopy + System.getProperty("line.separator", "\r\n"));
} catch(IOException ex) {
ex.printStackTrace();
}
}
Edited code to the correct standard as pointed out by other users.
of course because thats what you r telling it to do. every time is called it writes both x and the number. a quick fix: you can keep a flag if it is the first run set it flag = true. and check within ur method, sth like this:
public class YourClass{
private boolean didRun = false;
static void goOut(String in) {
...... init ur file and writer
if(!didRun)
writer.write(Y);
writer.write(in);
writer.close();
didRun = true;
}
}
I dont know the rest of the code but i think thats what u need
I believe you want to separate the jobs the "goOut" is responsible for.
You should make "goOut" only write the numbers (in your example).
The writing of the y's (in your example) should not be apart of the method and called once, at the start of writing to the file.
Also, #Jon Skeet is right about the multiple FileWriters. Use one, since its the same file.
Agree, sounds like a disaster.
When you use multiple writers to access the file, I would expect to get unpredictable results.
I dont think there is any guarantee that FileWriter1 would complete the task before FileWriter2.
In addition, the method is not synchronized.

Getting an InputStream to read more than once, regardless of markSupported()

I need to be able to re-use a java.io.InputStream multiple times, and I figured the following code would work, but it only works the first time.
Code
public class Clazz
{
private java.io.InputStream dbInputStream, firstDBInputStream;
private ArrayTable db;
public Clazz(java.io.InputStream defDB)
{
this.firstDBInputStream = defDB;
this.dbInputStream = defDB;
if (db == null)
throw new java.io.FileNotFoundException("Could not find the database at " + db);
if (dbInputStream.markSupported())
dbInputStream.mark(Integer.MAX_VALUE);
loadDatabaseToArrayTable();
}
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
this.dbInputStream = firstDBInputStream;
if (dbInputStream.markSupported())
dbInputStream.reset();
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
String CSV = "";
for (int i = 0; fileScanner.hasNextLine(); i++)
CSV += fileScanner.nextLine() + "\n";
db = ArrayTable.createArrayTableFromCSV(CSV);
}
public void reloadDatabase()//A method called by the UI
{
try
{
loadDatabaseToArrayTable();
}
catch (Throwable t)
{
//Alert the user that an error has occurred
}
}
}
Note that ArrayTable is a class of mine, which uses arrays to give an interface for working with tables.
Question
In this program, the database is shown directly to the user immediately after the reloadDatabase() method is called, and so any solution involving saving the initial read to an object in memory is useless, as that will NOT refresh the data (think of it like a browser; when you press "Refresh", you want it to fetch the information again, not just display the information it fetched the first time). How can I read a java.io.InputStream more than once?
You can't necessarily read an InputStream more than once. Some implementations support it, some don't. What you are doing is checking the markSupported method, which is indeed an indicator if you can read the same stream twice, but then you are ignoring the result. You have to call that method to see if you can read the stream twice, and if you can't, make other arrangements.
Edit (in response to comment): When I wrote my answer, my "other arrangements" was to get a fresh InputStream. However, when I read in your comments to your question about what you want to do, I'm not sure it is possible. For the basics of the operation, you probably want RandomAccessFile (at least that would be my first guess, and if it worked, that would be the easiest) - however you will have file access issues. You have an application actively writing to a file, and another reading that file, you will have problems - exactly which problems will depend on the OS, so whatever solution would require more testing. I suggest a separate question on SO that hits on that point, and someone who has tried that out can perhaps give you more insight.
you never mark the stream to be reset
public Clazz(java.io.InputStream defDB)
{
firstDBInputStream = defDB.markSupported()?defDB:new BufferedInputStream(defDB);
//BufferedInputStream supports marking
firstDBInputStream.mark(500000);//avoid IOException on first reset
}
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
this.dbInputStream = firstDBInputStream;
dbInputStream.reset();
dbInputStream.mark(500000);//or however long the data is
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
StringBuilder CSV = "";//StringBuilder is more efficient in a loop
while(fileScanner.hasNextLine())
CSV.append(fileScanner.nextLine()).append("\n");
db = ArrayTable.createArrayTableFromCSV(CSV.toString());
}
however you could instead keep a copy of the original ArrayTable and copy that when you need to (or even the created string to rebuild it)
this code creates the string and caches it so you can safely discard the inputstreams and just use readCSV to build the ArrayTable
private String readCSV=null;
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
if(readCSV==null){
this.dbInputStream = firstDBInputStream;
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
StringBuilder CSV = "";//StringBuilder is more efficient in a loop
while(fileScanner.hasNextLine())
CSV.append(fileScanner.nextLine()).append("\n");
readCSV=CSV.toString();
fileScanner.close();
}
db = ArrayTable.createArrayTableFromCSV(readCSV);
}
however if you want new information you'll need to create a new stream to read from again

Categories

Resources