public class Inventory implements Serializable {
ArrayList<Product> productlist;
File file;
public Inventory(){
productlist = new ArrayList<Product>();
file = new File("build/classes/inventory/inv.ser");
if(!file.exists()){
try {
file.getParentFile().mkdirs();
file.createNewFile();
} catch (IOException ex) {
Logger.getLogger(Inventory.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(file.length() !=0){
loadFile(file);
}
}
public void addProduct(Product product){
productlist.add(product);
saveFile(this.file);
}
public void saveFile(File file){
try{
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(productlist);
out.close();
fos.close();
} catch(FileNotFoundException ex){System.out.println("FileNotFoundException");}
catch(IOException ex){System.out.println("InputException");}
}
public void loadFile(File file){
try{
FileInputStream fis = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fis);
productlist=(ArrayList<Product>)in.readObject();
in.close();
fis.close();
} catch(FileNotFoundException ex){ System.out.println("FileNotFoundException"); }
catch(IOException ex){System.out.println("OutputException");}
catch(ClassNotFoundException ex){System.out.println("ClassNotFoundException");}
}
}
Does writeObject() overwrite the content of the existing file or append the objects to the existing file?
And is it a good idea to serialize an ArrayList of Objects like what i did inside the saveFile method?
Does writeObject() overwrite the content of the existing file or append the objects to the existing file?
Neither. It writes the object to the underlying stream. The underlying stream is a serial byte stream that can only be appended to. In this case the underlying stream is backed by an underlying file, which has or has not already been overwritten, depending on how you constructed the FileOutputStream. It has nothing to do with writeObject(). In any case you can't successfully append to a file of serialized objects without taking special measures.
And is it a good idea to serialize an ArrayList of Objects like what i did inside the saveFile method?
Compared to what?
N.B.
When you get an exception, print it. Not just some message of your own devising.
Creating a file just so you can test it for zero length doesn't make sense.
The directory build/classes/inventory won't be there at runtime once you stop using the IDE. This is no place to put a file.
You could try FileUtils function to write list of object into plane text file.
Please find below URL for reference -
http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FileUtils.html#writeLines-java.io.File-java.util.Collection-java.lang.String-boolean-
e.g.
FileUtils.writeLines(new File(fileToAttach), list);
Related
I'm new serialization (and programming in general) so i don't really know what happens under the hood. I'm making an email client program and the class
FileHandlerObject is used to write and read email messages that i send. I maintain an ArrayList and it is read, updated with new email and then written again. I don't understand why it throws an InvalidClassException because the file contains an ArrayList so the casting should be no problem.
I'm maintaining an ArrayList because the writeObject() truncates the file every time it writes.(Let me know if im wrong here)
class FileHandlerObject implements MyFileHandler<EmailMessage>{
public void write(EmailMessage input){
try
{
FileInputStream fileInputStream=new FileInputStream("emails.ser");
ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
#SuppressWarnings("unchecked")
ArrayList<EmailMessage> messagelist= (ArrayList<EmailMessage>) objectInputStream.readObject();
objectInputStream.close();
messagelist.add(input);
FileOutputStream fileOutputStream = new FileOutputStream("emails.ser");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(messagelist);
objectOutputStream.flush();
objectOutputStream.close();
}
catch(FileNotFoundException f)
{
try{
FileOutputStream fileOutputStream = new FileOutputStream("emails.ser");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
ArrayList<EmailMessage> messagelist=new ArrayList<EmailMessage>();
messagelist.add(input);
objectOutputStream.writeObject(messagelist);
objectOutputStream.flush();
objectOutputStream.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
catch(IOException e){
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}
public ArrayList<EmailMessage> read(){
try{
FileInputStream fileInputStream=new FileInputStream("emails.ser");
ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
#SuppressWarnings("unchecked")
ArrayList<EmailMessage> messagelist= (ArrayList<EmailMessage>) objectInputStream.readObject();
objectInputStream.close();
return messagelist;
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException c)
{
c.printStackTrace();
}
catch(ClassCastException c)
{
c.printStackTrace();
}
return null;
}
As the docs explain, this means one of a few things. The code you pasted does not give any insights about which of these mistakes you've made.
You saved some emails. Then, you edited the EmailMessage class, for example by adding a method or changing the name of a field, and then you ran the code again which ends up reading that file that was 'saved' with an old version of EmailMessage and which you are now trying to read with a new version. The java serialization mechanism can theoretically deal with versioning schemes but in practice it's a disaster. Ditch serialization, write your own protocol instead.
The EmailMessage class does not implement Serializable and does not have a no-args constructor. Give it a no-args constructor, and add implements Serializable to it.
Your classpath is incomplete; EmailMessage contains fields or methods that refer to some other class you wrote and it is not available on the classpath right now. Fix your classpath.
For my android studio project I need to serialize a User object. The idea is to save and load this object, so when the application is closes (gets destroyed) the objects and it's attributes are saved and stored in a file. My problem is that I'm getting an error with loading the object. It's says there is no such file or directory named 'save.bin', although I tried to create it. Here is my code:
public class SaveAndLoadManager{
public void save(Object object){
Log.d("Save", "saving object");
try{
File userInfo = new File("save.bin");
FileOutputStream fileOutputStream = new FileOutputStream(userInfo);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.close();
Log.d("Save", "object saved");
}catch(FileNotFoundException e){
Log.e("Save", e.getMessage());
}catch(IOException e){
Log.e("Save", e.getMessage());
}
}
public Object load(){
Log.d("Load", "loading object");
Object object = null;
try{
FileInputStream fileInputStream = new FileInputStream("save.bin");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
object = objectInputStream.readObject();
objectInputStream.close();
Log.d("Load", "object loaded");
}catch(FileNotFoundException e){
Log.e("Load", e.getMessage());
}catch(StreamCorruptedException e){
Log.e("Load", e.getMessage());
}catch(Exception e){
Log.e("Load", e.getMessage());
}
return object;
}
}
How do I properly create a directory?
Assuming that User is implementing Serialazible
File userInfo = new File("save.bin");
you can think about the above line, like a file object, called "save.bin", stored in the root, (/) on the the filesystem. This location is not writable by your application. Your application has the permission two write locations, one stored under /data/data/yourapp, and the other stored on /sdcard/Android/data/yourapp. Both should be access through the public api. E.g. you can use the pair openFileOutput/openFileInput to retrieve the FileOutputStream/FileInputStream
FileOutputStream fileOutputStream = openFileOutput("save.bin", Context.MODE_PRIVATE)
FileInputStream fileInputStream = openFileInput("save.bin");
As mentioned by #androidLerner in his comment,
you can find more info here,
I have admin account which should be able to add many users to a .dat file. Then I want to retrieve all the objects from the .dat file into a list for further programming.
public class User implements Serializable { //get and set methods }
This is hwo I am writing each object to the .dat file
public void addNewUser() throws Exception {
User newUser=new User();
newUser.name="test";
newUser.position="admin";
FileOutputStream outStream = new FileOutputStream("Users.dat", true);
ObjectOutputStream objectOutputFile = new ObjectOutputStream(outStream);
// Write the object to the file.
objectOutputFile.writeObject(newUser);
// Close the file.
objectOutputFile.close();
}
How can retrieve all the objects from the .dat file into ArrayList??
public class displayUsers { **//what to do??** }
You can either write the list object and read it as list. But since you're writing user objects individually, you can do something like this -
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Users.dat"));
Object object = null;
while ((object = ois.readObject()) != null) {
if (object instanceof User) {
User user = (User) object;
list.add(user);
}
}
Of course, you would need to take care of exceptions (like EOFException).
Generally it is bad practice to concatenate individual ObjectOutputStreams in a file without adding any lengths or delimiters. So better write all objects in one pass (and use ObjectOutputStream.reset in case your process is long-running and you fear memory leaks (otherwise ObjectOutputStream will keep a reference to every object it serialized before) or add them to a List and write it.
If you have to write it in multiple passes, I'd suggest to write the individual objects to a ByteArrayOutputStream first, and then use DataOutputStream to write the array prefixed by its length. That way, you can use DataInputStream to get out the individual byte arrays and use ByteArrayInputStream to deserialize them.
In case this does not work, you can try this solution (depending on the lookahead used by ObjectInputStream, this might not work for more complex objects with custom serialization formats, though, so use at your own risk):
public static void displayUsers() throws Exception {
FileInputStream fiis = new FileInputStream("Users.dat");
InputStream fis = new FilterInputStream(fiis) {
#Override
public void close() throws IOException {
// ignore
}
};
try {
while (true) {
ObjectInputStream in = new ObjectInputStream(fis);
User user = (User) in.readObject();
in.close();
System.out.println(user.name + "/" + user.position);
}
} catch (EOFException ex) {
// done
}
fiis.close();
}
List<User> listOfUser = new ArrayList<User>();
ObjectInputStream input = null;
try {
while (true) {
input = new ObjectInputStream(new FileInputStream("Users.dat"));
listOfUser.add(input.readObject());
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
input.close();
}
I have a java application that needs to write a lot of data into individual lines in a text file. I wrote the code below to do this, but for some reason, it is not writing anything to the text file. It does create the text file, but the text file remains empty after the program is done running. Can anyone show me how to fix the code below so that it actually fills the output file with as many lines of output as it is called upon to do?
public class MyMainClass{
PrintWriter output;
MyMainClass(){
try {output = new PrintWriter("somefile.txt");}
catch (FileNotFoundException e1) {e1.printStackTrace();}
anotherMethod();
}
void anotherMethod(){
output.println("print some variables");
MyOtherClass other = new MyOtherClass();
other.someMethod(this);
}
}
public class MyOtherClass(){
void someMethod(MyMainClass mmc){
mmc.output.println("print some other variables")
}
}
How you are going about doing this seems very strange to me. Why don't you write one method that takes in a string and then writes it to your file? Something like this should work fine
public static void writeToLog(String inString)
{
File f = new File("yourFile.txt");
boolean existsFlag = f.exists();
if(!existsFlag)
{
try {
f.createNewFile();
} catch (IOException e) {
System.out.println("could not create new log file");
e.printStackTrace();
}
}
FileWriter fstream;
try {
fstream = new FileWriter(f, true);
BufferedWriter out = new BufferedWriter(fstream);
out.write(inString+"\n");
out.newLine();
out.close();
} catch (IOException e) {
System.out.println("could not write to the file");
e.printStackTrace();
}
return;
}
Use the other constructor:
output = new PrintWriter(new FileWriter("somefile.txt"), true);
According to JavaDoc:
public PrintWriter(Writer out, boolean autoFlush)
Creates a new PrintWriter.
Parameters:
out - A character-output stream
autoFlush - A boolean; if true, the println, printf, or format methods will flush the output buffer
Use other constructor new PrintWriter(new PrintWriter("fileName"), true) for auto-flushing data or
Use flush() and close() when you're done writing
I have this serializable class, wich i use to store on a binary file an ArrayList of Strings.
public class SaveState implements Serializable{
public static ArrayList <String> favoriteBusStopNumbers = new ArrayList<String>();
public static SaveState instance=new SaveState();
}
I'm using this method to store the instance with the arrayList of strings once this array is full with the data i must store:
public static void saveData(){
ObjectOutput out;
try {
//primero comprobamos si existe el directorio, y si no, lo creamos.
File folder = new File(Environment.getExternalStorageDirectory() + DIRECTORY_NAME);
if(!folder.exists())
folder.mkdirs();
File outFile = new File(Environment.getExternalStorageDirectory(), DIRECTORY_NAME+"appSaveState.data");
out = new ObjectOutputStream(new FileOutputStream(outFile));
out.writeObject(SaveState.instance);
out.close();
} catch (Exception e) {e.printStackTrace();}
}
And finally, i use this method on the init of my app to load the file and fill my SaveState.instance variable with the previously stored data:
public static void loadData(){
ObjectInput in;
try {
File inFile = new File(Environment.getExternalStorageDirectory(), DIRECTORY_NAME+"appSaveState.data");
in = new ObjectInputStream(new FileInputStream(inFile));
SaveState.instance=(SaveState) in.readObject();
in.close();
} catch (Exception e) {e.printStackTrace();}
}
When i save the data, the file is being created correctly with the object fill of data, i know it because the file has more than 0KB of disc space. But something is going wrong here because when i start my app and load the data, my SaveState.instance variable gets an empty ArrayList of strings....... then ¿what is wrong in the code?
Thanks
Your arraylist is static. Static variables are associated with the class and not with the object. So they dont get serialized.
If you do want to serialize static variables, you have to override readObject and writeObject.
Here is some additional info -- http://java.sun.com/developer/technicalArticles/Programming/serialization/
Best solution here is to reconsider your data structure and make the arraylist non-static if its saving the state of an object.
EDIT: Alternatively, you could serialize just the arraylist ( as #Ted suggests below )
The problem is that variables marked as static will not be serialized except you implement
private void readObject(ObjectInputStream ois){}
and
private void writeObject(ObjectOutputStream oos){}
ObjectOutputStream - JavaDoc:
The default serialization mechanism for an object writes the class of
the object, the class signature, and the values of all non-transient
and non-static fields.
Since the only data kept in SaveState is a static array, you'll have more success just serializing and deserializing the array:
public static void saveData(){
ObjectOutput out;
try {
//primero comprobamos si existe el directorio, y si no, lo creamos.
File folder = new File(Environment.getExternalStorageDirectory() + DIRECTORY_NAME);
if(!folder.exists())
folder.mkdirs();
File outFile = new File(Environment.getExternalStorageDirectory(), DIRECTORY_NAME+"appSaveState.data");
out = new ObjectOutputStream(new FileOutputStream(outFile));
out.writeObject(SaveState.favoriteBusStopNumbers);
out.close();
} catch (Exception e) {e.printStackTrace();}
}
#SuppressWarnings("unchecked")
public static void loadData(){
ObjectInput in;
try {
File inFile = new File(Environment.getExternalStorageDirectory(), DIRECTORY_NAME+"appSaveState.data");
in = new ObjectInputStream(new FileInputStream(inFile));
SaveState.favoriteBusStopNumbers=(ArrayList<String>) in.readObject();
in.close();
} catch (Exception e) {e.printStackTrace();}
}
(You need to suppress the warning about casting to a generic type.)
You don't really need the SaveState.instance field at all.