I have a client application program that has 10+ classes each with 100+ components that need to be kept track of. When the program is run the user inputs numbers, selects items, toogles checkboxes, etc. I need to come up with a way to save all of the data input when the program is closed and have the capability of when the program is run again grab all the data from a previous time being run.
I have looked into Serialization but some of the things I need saved are not serializable so that didn't work. I have also looked into SingleFrameApplication and session storage but only in vain.
Writing to a file would cause the need for hours of tedious coding and would probably be inefficient. Does anyone have any ideas of how else I could tackle this hairy beast of a problem?
Update:
Doing what #home suggest I did the following:
public Main() throws FileNotFoundException {
initComponents();
//read the file
Read();
//...
}
private void formWindowClosing(java.awt.event.WindowEvent evt) {
try {
//write to the file, the program is closing
Write();
} catch (FileNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void Read() throws FileNotFoundException {
try{
XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("test.xml")));
//set the JTabbedPane to what is in the file
tab = (JTabbedPane) decoder.readObject();
decoder.close();
}catch(Exception e){
//there was no test.xml file so create one
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("test.xml")));
encoder.writeObject(null);
encoder.close();
}
}
private void Write() throws FileNotFoundException {
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("test.xml")));
//clear all previous things in the file
encoder.flush();
//write the JTabbedPane into the file
encoder.writeObject(tab);
encoder.close();
}
After these changes all that pops up when I run the program is a blank JTabbedPane. Can anyone explain why this is the case?
If you simply want to serialize an object compatible with JavaBeans specification, look at XML Encoder and Decoder: http://download.oracle.com/javase/6/docs/api/java/beans/XMLEncoder.html, http://download.oracle.com/javase/6/docs/api/java/beans/XMLDecoder.html
EDIT: Tutorial here: http://java.sun.com/products/jfc/tsc/articles/persistence4/
Related
I wanted to write to a property file. But it silently never worked. Just from the code behavior I could not notice it. I always had to open the properties file and look if the value changed. But it never did. So actually I would expect to get an exception . The problem seemed to be that I did not close the InputStream before opening the OutputStream. But I never got to know that. It cost me 3 days because I would expect either OutputStream or store function to give me some feedback. Have a look at the code.
File file = ResourceUtils.getFile("classpath:First.properties");
FileInputStream in = new FileInputStream(file);
Properties props = new Properties();
props.load(in);
System.out.println(props.getProperty("country"));
in.close(); // This I always forgot
FileOutputStream out = new FileOutputStream(file);
props.setProperty("country", "germany");
props.store(out, null);
System.out.println(props.getProperty("country"));
out.close();
As for the actual question "why does it not throw an exception", it's because there are cases you want the Stream to remain open.
class FileWriteSample implements Closeable {
FileOutputStream writeTo;
public FileWriteSample(String filename) throws IOException {
writeTo = new FileOutputStream(filename);
// should we expect an Exception here because we don't close the Stream?
// we're planning to use it later on
}
public void write(String s) {
// write to stream
}
public void close() throws IOException {
writeTo.close();
}
}
A forgotten close() statement cannot cause an exception. From the perspective of your stream everything is okay. It just didn't wrote to its destination yet. Why should it? Even when the whole program terminates there is no guaranty that the stream closes and writes its internal buffers out.[1]
You always have to call flush() or close() actively. The underlying implementation will then perform the actual write operation.
This mistake is so common that there is an extra Java-Feature to handle it. It is called try-with-resources and prevents programmers from the evil consequences of missing close() statements.
Example:
//use try-with-resources on out
private void saveProperties(Properties properties, String path) {
try(PrintStream out = new PrintStream(new FileOutputStream(path))) {
printProperties(properties,out);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// you can pass System.out as well to print to console
private void printProperties(Properties properties, PrintStream out) {
try {
properties.store(out, null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//properties.load leaves the stream open, so you have to use try-with-resources
private Properties readProperties(String path) {
try (FileInputStream in = new FileInputStream(path)) {
Properties properties = new Properties();
properties.load(in);
return properties;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Related posts on Java Properties:
Read properties from outside of a jar: https://stackoverflow.com/a/54766296/1485527
Sorted print of properties: https://stackoverflow.com/a/54781548/1485527
Related posts on Java Streams:
Closing Streams in Java
[1] See: Josh Bloch, Effective Java,(2nd ed.), Page 27.
Avoid finalizers.[...] It is entirely possible, even likely, that a program terminates without executing finalizers on some objects that are no longer reachable.
This is my saveTable button which saves one row of my table and than puts it into my Auto.auto file,but i can only save one object(row) of Auto type. Every time i save another line(row) it replaces the old one whith the new one so at the end i have only one object(row of table) in my file after clicking save button for like 5 times while my program is running. How can I solve this?
saveTable.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int row = Integer.parseInt(textField.getText());
getText.getAuto(row);
File tabel = new File("C:\\Users\\Jovan\\Desktop\\Auto.auto");
try {
if (!(tabel.exists())) {
tabel.createNewFile();
}
FileOutputStream fos = new FileOutputStream(tabel);
ObjectOutputStream oos1 = new ObjectOutputStream(fos);
oos1.writeObject(getText.getAuto(row));
oos1.close();
ObjectOutputStream os2 = new ObjectOutputStream(new FileOutputStream(tabel, true)) {
protected void writeStreamHeader() throws IOException {
reset();
}
};
os2.writeObject(getText.getAuto(row));
os2.close();
} catch (IOException error) {
error.printStackTrace();
}
}
});
new FileOutputStream(tabel, true)
The second parameter means that you will append to that file instead of overwriting it
public FileOutputStream(File file,
boolean append)
throws FileNotFoundException
Creates a file output stream to write to the file represented by the specified File object.
If the second argument is true, then bytes will be written to the end
of the file rather than the beginning. A new FileDescriptor object is
created to represent this file connection. First, if there is a
security manager, its checkWrite method is called with the path
represented by the file argument as its argument.
If the file exists but is a directory rather than a regular file, does
not exist but cannot be created, or cannot be opened for any other
reason then a FileNotFoundException is thrown.
Reference here
I have a a problem I have been dealing with for quite some time now. When attempting to de-serialize my custom "Sound" objects in a folder I continue to get 3 exceptions. IOException, NullPointerException, and StreamCorruptedException. Please take a look:
Method for reading sounds:
public static Sound readSound(String loc){
try{
FileInputStream fis = new FileInputStream(loc);
ObjectInputStream ois = new ObjectInputStream(fis);
fis.close();
ois.close();
return (Sound)ois.readObject();
}catch(Exception e){
System.out.println("Failed to read a serialized object.");
e.printStackTrace();
return null;
}
}
Exceptions/Errors Received: http://gyazo.com/b53faa9590adf6448bf14db11f275325
(Too much to paste here and it pastes incorrectly)
Loading the sounds:
(add sound just adds the sound to an ArrayList as well as a JComboBox)
private static File saveDirFile = new File("/Users/francisj12/Desktop/ACData/");
private static File saveDirFileSounds = new File(saveDirFile.getPath()+"/sounds/");
public static void loadAllSounds(){
if(!saveDirFile.exists()){
saveDirFile.mkdir();
}
if(!saveDirFileSounds.exists()){
saveDirFileSounds.mkdir();
}
for(int x=0; x<saveDirFileSounds.list().length; x++){
try{
File sndFl = new File(saveDirFileSounds.listFiles()[x].getPath());
Sound newSound = Serialize.readSound(sndFl.getPath());
addSound(newSound);
}catch(Exception e){
e.printStackTrace();
continue;
}
}
}
Here it what the .ser files look like: (Once I started using transient on variables so I could serialize my custom Sound object which I dont understand transient yet, it started making the .ser look as follows instead of a ton of weird characters its just one line of weird characters now)
¨ÌsrAlarms.SoundË.®ŸÓÓxp
Hope this is all the information you guys will need thanks so much for your help!
I am using nu.xom.* for my project, link found at http://www.xom.nu/. My question is about the following part of my code:
private void open() {
builder = new Builder();
try {
document = builder.build(file);
} catch (ParsingException | IOException ex) {
Logger.getLogger(InvoiceData.class.getName()).log(Level.SEVERE, null, ex);
}
}
I have some unwanted file locks in my program and am practically checking all places where I open a file. Now it struck me here that builder.build(File file) does implement Closeable, so I myself am not sure here whether it closes the file properly or not.
Can anyone shed some light on this?
Regards.
Fortunately the XOM library is open source, so you can take a look at the source code of nu.xom.Builder.build(File):
public Document build(File in)
throws ParsingException, ValidityException, IOException {
InputStream fin = new FileInputStream(in);
// [...]
String base = url.toString();
try {
Document doc = build(fin, base);
return doc;
}
finally {
fin.close();
}
}
So you pass a File instance to the build() method and inside this method a FileInputStream is opened and closed at the end.
There is a part after new FileInputStream(in) which is not enclosed by a try block. If this code throws an unchecked exception it is possible that the input stream isn't closed. But if you don't catch an exception then you can be sure, that the input stream is closed properly.
I'm trying to write an Android game and I would like to be able to pause the game even if the user wants to return to the main menu or the activity gets killed off by the system. onSaveInstanceState doesn't seem to give me a whole lot of control as to when I can read the bundle back, plus from what I can tell, the bundle is only good for short periods of time. So I want to serialize a few ArrayLists that I have, then read them back. I don't get any compile errors nor does the program crash. But, the data either never gets written or never gets read. I'm not sure which one. My serializeData method is called in onDestroy and the deserializeData is called from onCreate. Here's my code for writing and reading the data:
public void serializeData(String filename, ArrayList<String>arrayList) {
FileOutputStream fos;
try {
fos = openFileOutput(filename, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(arrayList);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
#SuppressWarnings("unchecked")
private void deserializeData(String filename, ArrayList<String>arrayList){
try{
FileInputStream fis = openFileInput(filename);
ObjectInputStream ois = new ObjectInputStream(fis);
arrayList = (ArrayList<String>)ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
Any help would be greatly appreciated! Thanks in advance!
Let me tell you one thing: never use the onDestroy() method to save your data. Use onPause() or onStop() instead. You should never count on the onDestroy() method to save data or call some functions.
Use onDestroy to close connections and finish using resources and the like. If you want to read more about this you should take a look here.
Other than that your code seems fine. Just add one more thing: put a oos.flush() just above oos.close().
And don't forget to close the objectInputStream object.
I cannot see an obvious problem with that code.
I'd try adding some code after closing the ObjectOutputStream and before opening the ObjectInputStream to print out the absolute name and size of the file.
While serializing you can write to ByteArrayOutputStream and then decode the bytes into string using platform's default character set. Store this string into SharedPreferences. While deserializing, just get the bytes from string and create a ByteArrayInputStream using this and feed it to ObjectInputStream.Are you sure your activity is being killed? It might be the case that your activity is oscillating between onPasue/onResume.