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();
}
Related
I have a method that writes data from a list to a file, a method that reads data from a file into a list and a method that writes data from a list in a file to the specified number of times. I'm trying to extract data from a file after I use the first method writeFile () everything works fine. I read the data from the file into the list by readFile () method. After that I use my method which writes to the file the number of times I need, everything is fine, it writes multyWrite (). But after that I can not read the data from the file in the readFile () method since I get `
Exception stack trace:
Exception in thread "main" java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1599)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
at ProductService.readFile(ProductService.java:47)
at Main.main(Main.java:21)
I know that I should use objectOutputStream.reset (), but where would it be better to use it?
private String fileName;
private ProductInterface<FlyingMachine> productService = new ProductInterfaceImpl();
private ObjectOutputStream objectOutputStream;
private FileOutputStream fileOutputStream;
public ProductService(String fileName) throws IOException {
this.fileName = fileName;
fileOutputStream = new FileOutputStream(fileName);
this.objectOutputStream = new ObjectOutputStream(fileOutputStream);
}
public void writeFile() throws IOException {
try {
for (FlyingMachine f : productService.getProductContainer()) {
objectOutputStream.writeObject(f);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (objectOutputStream != null) {
objectOutputStream.flush();
objectOutputStream.close();
fileOutputStream.close();
}
}
}`
public void readFile() throws IOException {
ObjectInputStream objectInputStream = null;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(fileName);
objectInputStream = new ObjectInputStream(fileInputStream);
while (fileInputStream.available() > 0) {
FlyingMachine flyingMachine = (FlyingMachine) objectInputStream.readObject();
productService.getProductContainer().add(flyingMachine);
}
} catch (ClassNotFoundException | EOFException e) {
e.printStackTrace();
} finally {
if (objectInputStream != null) {
objectInputStream.close();
fileInputStream.close();
}
}
}
public void multyWrite(int number) throws IOException {
for (int i = 0; i < number; i++) {
try {
fileOutputStream = new FileOutputStream(fileName, true);
objectOutputStream = new ObjectOutputStream(fileOutputStream);
for (FlyingMachine f : productService.getProductContainer()) {
objectOutputStream.writeObject(f);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (objectOutputStream != null) {
objectOutputStream.flush();
objectOutputStream.close();
}
}
}
}
You create a new ObjectOutputStream in the constructor. In writeFile you use that OOS instance and close it. But in multyWrite you don't use it and instead create new instances.
Now when you call multyWrite without having called writeFile first, that first OOS will still be open, but the OOS you create in multyWrite doesn't know that - thus causing your file to have two OOS headers after another.
And then when you try to read such a file, the ObjectInputStream will find the first header (all is fine) and then unexpectedly find the second header, while it expected a type code. That header starts with 0xAC, hence throwing the exception message "invalid type code: AC".
To fix this, either have multyWrite use the OOS constructed in your constructor, the same way writeFile does, or make sure that that OOS is closed before you create a new one.
It's generally not a good idea to open a stream (of any kind) in a constructor and then rely on external code calling a specific method to close it. Better create streams when you need them and close them directly.
I'm basically making a journal app where each individual journal entry needs to persist, and I would like to keep all entries in a single file.
I've seen tons of tutorials on serializing a single object and so I came up with this solution, (which doesn't work) but even if I manage to fix it, it feels like a sloppy solution.
(Here I'm trying to serialize an arraylist, and each time I save an entry, i de-serialize the list and add the new entry to the list before serializing again)
To clarify, my question is: s this a good way to save objects to the same file, on multiple occasions?
Or does anyone have some tips about something else I should try, links to videos or documentation regarding this is also appreciated.
public class Serializer
{
//Calls readFile and adds the returned entries to an ArrayList
//Add the target object to the list and write to the file
public static void writeToFile(Object target)
{
ArrayList entries = new ArrayList();
entries = readFile();
entries.add(target);
String filename = "entries.bin";
FileOutputStream fileOut = null;
ObjectOutputStream objOut = null;
try
{
fileOut = new FileOutputStream(filename);
objOut = new ObjectOutputStream(fileOut);
objOut.writeObject(entries);
objOut.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
//Reads the file and returns all entries in a list
public static ArrayList readFile ()
{
ArrayList persistedEntries = new ArrayList<>();
String filename = "entries.bin";
FileInputStream fileIn = null;
ObjectInputStream objIn= null;
try
{
fileIn = new FileInputStream(filename);
objIn = new ObjectInputStream(fileIn);
persistedEntries = (ArrayList) objIn.readObject();
objIn.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
return persistedEntries;
}
}
Is this a good way to save objects to the same file, on multiple occasions?
I would argue no. This is because your method writeToFile or more accurately appendToFile can introduce strange behaviour in edge cases (such as entries.bin having an unexpected object). I would argue for this:
Use writeToFile(ArrayList<Object> target) to overwrite the file with the specified array. Then add a method appendToFile(Object target) that handles the process of reading from entries.bin from the disk, appending target then writing the array to the disk. This has the advantage of separating any logic related to 'merging' the new object target with the file on disk, and the actual logic of writing to the entries.bin file.
If just a learning exercise I would go with the above. Potential resource
Adding a reformatted version:
public class Serializer
{
private String filename;
// pass in "entries.bin"
public Serializer(String filename) {
this.filename = filename;
}
public void append(Object target) {
// readfile will return at least empty arraylist
ArrayList entries = readFile();
entries.add(target);
serialize(entries);
}
public void serialize(ArrayList entries)
{
FileOutputStream fileOut = null;
ObjectOutputStream objOut = null;
try
{
fileOut = new FileOutputStream(filename);
objOut = new ObjectOutputStream(fileOut);
objOut.writeObject(entries);
objOut.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
//Reads the file and returns all entries in a list
public ArrayList deserialize ()
{
ArrayList persistedEntries = new ArrayList<>();
FileInputStream fileIn = null;
ObjectInputStream objIn = null;
try
{
fileIn = new FileInputStream(filename);
objIn = new ObjectInputStream(fileIn);
Object result = objIn.readObject();
if (!(result instanceof ArrayList)) {
// read object is not an arraylist
}
persistedEntries = (ArrayList) objIn.readObject();
objIn.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
return persistedEntries;
}
}
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);
I have an object that has a List each ObjectA has a few data members (strings and a byte[]). Along with a FileInputStream used to read a file into the byte array. I have initialized all data members in the global scope of the object so that I can recycle them to reduce the amount of object creation per function call. When I serialize the object my FileInputStream is null, as I store the file in the byte array. so I expect that the FileInputStream being null would be skipped by the serialization process. both the main object and the objects that are put in the list of the main object are implementing serializable
I'm able to serialize the object that holds the list of objects and deserialize it as long as the list is empty. When the list has at least one object in it. It's still able to serialize but when i attempt to deserialize it I get the following error.
IOException: writing aborted; java.io.NotSerializableException: java.io.FileInputStream
The variables in my object's is as followed:
public class MainObject implements Serializable{
private String name;
private List<ObjectA> obj;
}
public class ObjectA implements Serializable{
private String id;
private String name;
private File fileStream;
byte []data;
}
To trouble shoot this I saved the serialized object to a file and looked at it and I can see the MainObject is being saved. If I include objects into the list the objects are also being saved.
Here is the code I made for reading the files and adding them to the object.
File[] files = new File(filePath).listFiles();
for (File file : files) {
if (file.isFile()) {
System.out.println(file.getName());
try {
fin = new FileInputStream(filePath+file.getName());
ois = new ObjectInputStream(fin);
mainObjectList.add((MainObject) ois.readObject());
ois.close();
fin.close();
} catch (FileNotFoundException e) {
System.err.println("FileNotFoundException: " + e.getMessage());
} catch (ClassNotFoundException e) {
System.err.println("ClassNotFoundException: " + e.getMessage());
} catch (IOException e) {
System.err.println("IOException: " + e.getMessage());
}
}
}
here is the setFile() that's in MainObject
public void setFile(String filePath) {
try {
File file=null;
fileStream = new FileInputStream(file=new File(filePath));
data = new byte[(int)file.length()];
fileStream.read(data,0,data.length);
for (int X : data){
System.out.print((char)X);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
Read the exception message. Contrary to the code you posted, you have a FileInputStream member, which is not serializable. Make it transient, or remove it, and construct it when you need it from the File.
And contrary to your claim that 'When i serialize mainObject and save it to a file i can see its saving all the data including the list of audioClip objects', when you serialized this data you got an exception, which you have ignored.
NB Your newly posted code:
try {
File file=null;
fileStream = new FileInputStream(file=new File(filePath));
data = new byte[(int)file.length()];
fileStream.read(data,0,data.length);
for (int X : data){
System.out.print((char)X);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
is very poor quality. It should have been written like this:
try (FileInputStream fileStream = new FileInputStream(new File(filePath))) {
data = new byte[(int)file.length()];
int total = 0;
int count;
while ((count = fileStream.read(data, total, data.length-total)) > 0) {
total += count;
}
for (byte X : data) {
System.out.print((char)X);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
Note that you cannot assume either that a file fits into memory, that the size fits into an int, or that read() fills the buffer. You have to:
store the result of read() into a variable
test it for -1, indicating end of stream
otherwise use it as the read count, instead of the buffer size
repeat until end of stream.
Note also that you don't need the File file variable at all; that the FileInputStream should always have been a local variable; and that you weren't closing it: this code does, via the try-with-resources syntax.
I'm trying to read from a file I have saved using the following code:
public void saveOnFile() {
try {
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("object.txt"));
output.writeObject(mediaList);
output.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
public void readFromFile() {
try {
ObjectInputStream inStream = new ObjectInputStream(new FileInputStream("object.txt"));
this.mediaList.add( (Media) inStream.readObject());
inStream.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
However, I don't know if ObjectInputStream knows what objects are inputted. Objects in this case can either be a "Movie" or a "TVShow" but the are all subclasses to Media.
I get the following errors:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to project.Media
at project.MediaHandler.readFromFile(MediaHandler.java:66)
at project.Window.<init>(Window.java:73)
at project.Window.main(Window.java:199)
The Object that you wrote to the ObjectOutputStream is called mediaList, therefore I assume that this is an ArrayList<Media> rather than each individual Media object.
On the ObjectInputStream, you are reading an object and casting it to Media, but I think that you will find that it is an ArrayList<Media> (or however mediaList is defined when it is written to the ObjectOutputStream).