Serialization Writing/Reading to File - java

I have a strange bug when executing my code. The first time I save the level, the code properly writes to the file. Upon running the game, the level is properly loaded. However, the second time I try saving on a level that was previously loaded, the save file's arraylists become null. The code DOES NOT throw an error, I noticed only the ArrayList filled with entities, not the level itself, became null, hence does not properly load the game the second time around.
Here is my code:
public void save() {
try (ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream(fileName, false))) {
out.writeObject(object);
} catch (IOException e) {
System.out.println("There was a problem saving " + object);
System.out.println(e.getMessage());
}
}
public Object load() {
try (ObjectInputStream in = new ObjectInputStream(
new FileInputStream(fileName))) {
return in.readObject();
} catch (IOException | ClassNotFoundException e) {
System.out.println("There was a problem loading " + object);
System.out.println(e.getMessage());
}
return null;
}
The following methods are called when expected:
public static void saveGame() {
level.save();
System.out.println("SAVED");
System.out.println(level.load());
}
public static void load() {
if (level.load() != null) {
Level.level1 = (Level) level.load();
System.out.println(Level.level1);
System.out.println("LOADED");
}
}
The levels themselves are static, I'm not sure if that has any special rules. Here is the snippet of the Level instance data if that is needed:
protected List<Mob> mobs = new CopyOnWriteArrayList<Mob>();
protected List<Player> players = new CopyOnWriteArrayList<Player>();
private String imagePath;
private transient BufferedImage image;
public static Level level1 = new LordHillsboroughsDomain();
I have a feeling it has something to do with a new instance of the level overwriting the saved level, but I just can't seem to figure it out. Any help is greatly appreciated!

Related

Why is this Class' object not serialized properly in different processes?

Context
I made a Java application, and need to run two instances of that application, synchronizing some of their attributes via socket each time there's some change. To communicate those changes, Serializable objects are sent through a socket using ObjectStreams (input and output) using read/writeUTF() for an identifier, and read/writeObject() and flush(). The app is the exact same .jar, run twice with some changes like having different ports and ip (if necessary).
Problem
I noticed that objects of some of my classes (e.g. Notification) were sent and received without any troubles, but objects from another class (RegisteredUsers) weren't sent (or received) properly. So I ran some tests to send objects between the two apps and found that the object is being sent and isn't null, it's attribute (a HashMap<String,User>) is also being sent and isn't null, but is always empty.
So I decided to scale it down to what the problem was exactly: I'm trying to write an object through a Stream, and read it in a different process of the same .jar, and with most classes it seems to work, but it doesn't with one.
There seems to be something I'm missing or don't understand about this serialization process, if the object is written and read during the execution of the same process it works, but not if this object is read on another instance of the same app. I even added a HashMap to Notification with the same creation process, but it still works, I really don't get it, what am I missing?
Code
I have taken some code from the bigger app and trimmed it down to the basic problem if anyone wants to test it. To reproduce the errors, run Main1, which will create the two files with an object persisted in each one (one with a Notification object and the other with a RegisteredUsers object) and shows their information, then Main2, which reads them from the files and shows their information, and the problem should be printed. That being that reg3's HashMap is empty and thus neither of the Users are registered.
Main1
public class Main1 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg1 = new RegisteredUsers();
RegisteredUsers reg2 = new RegisteredUsers();
reg1.register("Name1", "127.0.0.1");
reg1.register("Name2", "127.0.0.1");
try {
pers.writeReg(reg1, regFile);
} catch (IOException e) {
System.out.println("Error writing registry.");
}
try {
reg2 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
System.out.println("Original registry: ");
System.out.println(reg1.isRegistered("Name1") + " " + reg1.isRegistered("Name2"));
System.out.println("Registry read from file: ");
System.out.println(reg2.isRegistered("Name1") + " " + reg2.isRegistered("Name2"));
Notification noti1 = new Notification("Name", "127.0.0.1");
Notification noti2 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
pers.writeNotif(noti1, notificationFile);
} catch (IOException e) {
System.out.println("Error writing notification.");
}
try {
noti2 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Original notification: ");
System.out.println(noti1.getAttributes().get(0) + " " + noti1.getAttributes().get(1));
System.out.println(noti1.getMap());
System.out.println("Notification read from file: ");
System.out.println(noti2.getAttributes().get(0) + " " + noti2.getAttributes().get(1));
System.out.println(noti2.getMap());
}
}
Main2
public class Main2 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg3 = new RegisteredUsers();
try {
reg3 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
if (reg3 == null) {
System.out.println("reg3 is null");
}
if (reg3.getMap() == null)
System.out.println("reg3 has a null map");
if (reg3.getMap().isEmpty())
System.out.println("reg3 has an empty map");
System.out.println("Registry read from file on another process: ");
System.out.println(reg3.isRegistered("Name1") + " " + reg3.isRegistered("Name2"));
Notification noti3 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
noti3 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Notification read from file on another process: ");
System.out.println(noti3.getAttributes().get(0) + " " + noti3.getAttributes().get(1));
System.out.println(noti3.getMap());
}
}
A Class to persist the objects in the files:
public class Persistence {
public void writeReg(RegisteredUsers regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public RegisteredUsers readReg(String file) throws IOException {
RegisteredUsers regus = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
regus = (RegisteredUsers) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return regus;
}
public void writeNotif(Notification regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public Notification readNotif(String file) throws IOException {
Notification notif = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
notif = (Notification) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return notif;
}
}
RegisteredUsers
public class RegisteredUsers implements Serializable {
private static HashMap<String, User> users;
public RegisteredUsers() {
users = new HashMap<String, User>();
}
public HashMap<String, User> getMap() {
return users;
}
public boolean isRegistered(String name) {
User us = users.get(name);
return us != null;
}
public void register(String name, String ip) {
users.put(name, new User(name, ip, false));
}
}
Notification
public class Notification implements Serializable {
private ArrayList<String> attributes;
private HashMap<String, User> map = new HashMap<>();
public Notification() {
}
public Notification(String name, String ip) {
attributes = new ArrayList<String>();
attributes.add(0, name);
attributes.add(1, ip);
map.put(ip, new User(name, ip, false));
}
public ArrayList<String> getAttributes() {
return attributes;
}
public HashMap<String, User> getMap() {
return map;
}
}
User
public class User implements Serializable {
private String name;
private String ip;
private boolean connection_state;
public User(String name, String ip, boolean connection_state) {
this.name = name;
this.ip = ip;
this.connection_state = connection_state;
}
}
In java static fields are implicitly transient, and transient fields are not serialized.
If you modify the RegisterdUsers to
public class RegisteredUsers implements Serializable {
private HashMap<String, User> users; // static modifier is removed
...
}
The serialization will work.

How to overwrite a file that is altering an arraylist

I'm writing a program in order to keep track of DVDs in my library. I'm having trouble altering the text file that saves an added or removed DVD object from the arraylist. Whenever I call my save method, which is the one that overwrites the existing text file holding all the information, it will not change it whatsoever. My add and remove methods work fine but it's just the save method which overwrites the file that I'm reading from that will not work. The following code is what I was attempting to use to save the arraylist to the file. My filename is DVDCollection.txt and the boolean variable flag is a static variable used to check whether or not the code which adds or removes an object from the arraylist was reached.
public void save() {
try{
if(flag=true){
FileWriter instream = new FileWriter("DVDCollection.txt",false);
instream.close();
}else{
return;
}
}catch(IOException e){
System.out.println("The file could not be written to!");
}
}
If you are using java 8 or above it's as simple as:
List<String> lines = Arrays.asList("first line", "second line");
try {
Files.write(Paths.get("my-file.txt"), lines);
} catch (IOException e) {
//handle exception
}
Make sure you provide the right path!
Not sure, why this method should save an array list, as the actual code that writes to this file is missing. Here is simple test, let's start here:
import java.io.*;
import java.util.*;
public class FileSaveTest {
public static void main(String[] args) {
FileSaveTest test = new FileSaveTest();
test.fill();
test.save();
}
public void fill() {
arrayList.add("My disc 1");
arrayList.add("My disc 2");
arrayList.add("Another disc");
}
public void save() {
try {
if(flag) { // you dont need ==true
FileWriter instream = new FileWriter("DVDCollection.txt",false);
for (String entry : arrayList) {
instream.write(entry + "\n");
}
instream.close();
} else {
return;
}
} catch(IOException e) {
System.out.println("The file could not be written to!");
}
}
private ArrayList<String> arrayList = new ArrayList<>();
private static boolean flag = true;
}
Next, it's not very good, to close the file in such manner. If an exception occurs while writing, the file will not be closed. instream.close() should be put into the "finally" block. This block will be executed in any case, regardless of whether an exception occurred or the return keyword met:
public void save() {
Writer instream = null;
try {
if(flag) { // you dont need ==true
instream = new FileWriter("DVDCollection.txt",false);
for (String entry : arrayList) {
instream.write(entry + "\n");
}
} else {
return;
}
} catch(IOException e) {
System.out.println("The file could not be written to!");
} finally {
try {
if (instream != null)
instream.close();
} catch (IOException e) {
System.err.println("Exception during close");
}
}
}
Or, if you are using java 7, you can use try-with-resources syntax:
public void save() {
if(flag) { // you dont need ==true
try (Writer instream = new FileWriter("DVDCollection.txt",false)) {
for (String entry : arrayList)
instream.write(entry + "\n");
} catch(IOException e) {
System.out.println("The file could not be written to!");
}
} // you dont need "return else { return; }" anymore
}

Unexpected output in concurrent file writing in java web

I wrote a very simple Java web application ,just included some basic function like register , sign in , changing the password and some others.
I don't use database. I just create a file in the app to record the users' information and do the database stuff.
I used JMeter to stressing the web application, especially the register interface.
The JMeter shows that the result of the 1000 thread is right
but when I look into the information.txt , which stores the users' information, it's wrong because it stores 700+ record :
but it should include 1000 record, it must be somewhere wrong
I use the singleton class to do the write/read stuff, and i add a synchronized word to the class, the insert() function which is used by register to record the register information is shown as below: (a part of it)
public class Database {
private static Database database = null;
private static File file = null;
public synchronized static Database getInstance() {
if (database == null) {
database = new Database();
}
return database;
}
private Database() {
String path = this.getClass().getClassLoader().getResource("/")
.getPath() + "information.txt";
file = new File(path);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public void insert(String account, String password, String username) {
RandomAccessFile infoFile = null;
try {
infoFile = new RandomAccessFile(file, "rw");
String record;
long offset = 0;
while ((record = infoFile.readLine()) != null ) {
offset += record.getBytes().length+2;
}
infoFile.seek(offset);
record = account+"|"+password+"|"+username+"\r\n";
infoFile.write(record.getBytes());
infoFile.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (infoFile != null) {
try {
infoFile.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
the question is why would this happened , the synchronized is thread safe, why i lost so many data and some blank line was inserted into it, what could I do the correct it !
You are synchronizing the getInstance() method, but not the insert() method. This makes the retrieval of the instance of Database thread-safe, but not the write operation.

How do I save states to a file and keep the file safe?

I'm trying to create save states for my game, not so much for where your game was left but something simple like score boards. The format would be something like this:
Wins: 5
Losses: 10
GamesPlayed: 15
I need to be able to access the file, and depending on whether the player won/lost it will append +1 to the value in the file.
What would be the best way to go about this? I've heard of a bunch of different ways to save data, for example XML, but aren't those overkill for the size of my data?
Also, I do want to keep this file safe from the users being able to go into the files and change the data. Would I have to do some sort of encryption? And, if the user removes the file and replaces it with an empty one can't they technically reset their values?
You can use plain serialization/deserialization for this. In order to serialize/deserialize a class, it must implement the Serializable interface. Here's a example to start with:
public class Score implements Serializable {
private int wins;
private int loses;
private int gamesPlayed;
//constructor, getter and setters...
}
public class ScoreDataHandler {
private static final String fileName = "score.dat";
public void saveScore(Score score) {
ObjectOutputStreamout = null;
try {
out = new ObjectOutputStream(new FileOutputStream(fileName));
out.writeObject(score);
} catch (Exception e) {
//handle your exceptions...
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
}
}
}
}
public Score loadScore() {
ObjectInputStreamin = null;
Score score = null;
try {
in = new ObjectInputStream(new FileInputStream(fileName));
score = (Score)in.readObject();
} catch (Exception e) {
//handle your exceptions...
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ioe) {
}
}
}
return score;
}
}

Error Reading and writing files (Java) [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
Hi guys i just implemented object files into my program and i am constantly getting the errors (error reading file and problem writing to file) these are 2 errors in my try catch block, when i try to read the file it does not load, saving doesn't work either.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
public class Stores implements Serializable
{
public static ArrayList<Student> stud1 = new ArrayList<Student>();
public static ArrayList<SubjectTeacher> sTeach1 = new ArrayList<SubjectTeacher>();
private static int iT = 0;
private static int iS = 0;
public static void savet (ArrayList<SubjectTeacher> teachIn, int count)
{
iT = count;
sTeach1 = teachIn;
saveTeachToFile();
}
public static void saves (ArrayList<Student> studIn, int count)
{
iS = count;
stud1 = studIn;
saveStudToFile();
}
public static ArrayList<Student> getStud ()
{
return stud1;
}
public static ArrayList<SubjectTeacher> getTeach ()
{
return sTeach1;
}
public static int getStudSize()
{
return stud1.size();
}
public static int getTeachSize()
{
return sTeach1.size();
}
private static void saveStudToFile()
{
try
{
// create a FileOutputStream object which will handles the writing of the sudent list of objects to the file.
FileOutputStream studentFile = new FileOutputStream("Students.obf");
// the OutputObjectStream object will allow us to write whole objects to and from files
ObjectOutputStream studentStream = new ObjectOutputStream(studentFile);
for(Student item: stud1) // enhanced for loop
// Loop through the list of studentsListIn and for each of these objects, wite them to the file
{
studentStream.writeObject(item);
}
//close the file so that it is no longer accessible to the program
studentStream.close();
}
catch(IOException e)
{
System.out.println("There was a problem writing the File");
}
}
private static void saveTeachToFile()
{
try
{
FileOutputStream teacherFile = new FileOutputStream("Teacher.obf");
ObjectOutputStream teacherStream = new ObjectOutputStream(teacherFile);
for(SubjectTeacher item1: sTeach1) // enhanced for loop
{
teacherStream.writeObject(item1);
}
//close the file so that it is no longer accessible to the program
teacherStream.close();
}
catch(IOException e)
{
System.out.println("There was a problem writing the File");
}
}
public static void loadStudentList()
{
boolean endOfFile = false;
Student tempStudent;
try
{
// create a FileInputStream object, studentFile
FileInputStream studentFile = new FileInputStream("Students.obf");
// create am ObjectImnputStream object to wrap around studentStream
ObjectInputStream studentStream = new ObjectInputStream(studentFile) ;
// read the first (whole) object with the readObject method
tempStudent = (Student) studentStream.readObject();
while (endOfFile != true)
{
try
{
stud1.add(tempStudent);
// read the next (whole) object
tempStudent = (Student) studentStream.readObject();
}
//use the fact that the readObject throws an EOFException to check whether the end of eth file has been reached
catch(EOFException e)
{
endOfFile = true;
}
studentStream.close();
}
}
catch(FileNotFoundException e)
{
System.out.println("File not found");
}
catch(ClassNotFoundException e) // thrown by readObject
/* which indicates that the object just read does not correspond to any class
known to the program */
{
System.out.println("Trying to read an object of an unkonown class");
}
catch(StreamCorruptedException e) //thrown by constructor
// which indicates that the input stream given to it was not produced by an ObjectOutputStream object {
{
System.out.println("Unreadable File Format");
}
catch(IOException e)
{
System.out.println("There was a problem reading the file");
}
}
public static void loadTeacherList()
{
boolean endOfFile = false;
SubjectTeacher tempTeacher;
try
{
FileInputStream teacherFile = new FileInputStream("Teacher.obf");
ObjectInputStream teacherStream = new ObjectInputStream(teacherFile) ;
tempTeacher = (SubjectTeacher) teacherStream.readObject();
while (endOfFile != true)
{
try
{
sTeach1.add(tempTeacher);
// read the next (whole) object
tempTeacher = (SubjectTeacher) teacherStream.readObject();
}
//use the fact that the readObject throws an EOFException to check whether the end of eth file has been reached
catch(EOFException e)
{
endOfFile = true;
}
teacherStream.close();
}
}
catch(FileNotFoundException e)
{
System.out.println("File not found");
}
catch(ClassNotFoundException e) // thrown by readObject
/* which indicates that the object just read does not correspond to any class
known to the program */
{
System.out.println("Trying to read an object of an unkonown class");
}
catch(StreamCorruptedException e) //thrown by constructor
// which indicates that the input stream given to it was not produced by an ObjectOutputStream object {
{
System.out.println("Unreadable File Format");
}
catch(IOException e)
{
System.out.println("There was a problem reading the file");
}
}
}
Well, for one thing, you should edit the question with the correct code so it doesn't get closed. Second, A couple of things could be happening.
The classes you're writing to file aren't serializable
The files are readonly or write protected somehow
Based on the code from your updated question, it looks like you may be confusing which classes need to implement Serializable. The classes that need to implement that are the ones you're actually writing to file (ie SubjectTeacher, etc.).
Check those two, and let me know what you find.
Also, I'd suggest stepping the code and seeing what the exceptions look like at runtime. You'll get a much better idea of what's going on.

Categories