I'm trying to write couple of object using ObjectOutputStream to a file. After that, I read the file with ObjectInputStream. The problem is, I can only read first object in the file. When I opened the file with notepad++, I can see the entries for other objects.
Here writer part
public class FileProcess {
private ObjectOutputStream output;
private Accounts account;
public FileProcess() {}
public void WriteObject(Accounts account) {
this.account = account;
openFile();
addRecords();
closeFile();
}
private void openFile() {
try {
output = new ObjectOutputStream(Files.newOutputStream(Paths.get("record_files.txt"),CREATE,APPEND));
}catch (Exception e) {
System.out.println("\nError opening file");
}
}
private void addRecords() {
try {
output.writeObject(account);
}
catch (Exception e) {
System.out.printf("Error writing file %s",e);
}
}
private void closeFile() {
try {
if(output != null)
output.close();
} catch (Exception e) {
System.out.println("\nError closing file");
}
}
}
And Reader part
abstract class User {
private String userID;
private int password;
private String position;
private ObjectInputStream input;
public User(String userID, int password, String position) {
this.userID = userID;
this.password = password;
this.position = position;
}
boolean signIn() {
boolean found_check = false;
openFile();
found_check = checkRecords();
closeFile();
return found_check;
}
private void closeFile() {
try {
if(input != null)
input.close();
} catch (Exception e) {
System.out.println("Error closing file");
}
}
private boolean checkRecords() {
try {
while(true) {
Accounts account = (Accounts) input.readObject();
System.out.printf("%s %d %s",account.getUserID(),account.getPassword(),account.getPosition());
}
}
catch (Exception e) {
System.out.println("\nError reading file");
return false;
}
return false;
}
private void openFile() {
try {
input = new ObjectInputStream(Files.newInputStream(Paths.get("record_files.txt")));
}catch (Exception e) {
System.out.println("Error opening file");
}
}
}
Accounts class implements Serializable
public class Accounts implements Serializable {
private String userID;
private int password;
private String position;
public Accounts(String userID, int password, String position) {
try {
this.userID = userID;
this.password = password;
this.position = position;
}
catch (Exception e) {
System.out.printf(e.toString());
}
}
}
Your code is throwing the following exception: java.io.StreamCorruptedException: invalid type code: AC.
There's a good question and answer here
This was discovered by adding e.printStackTrace(); to the exception handler in User.checkRecords.
Related
The streams used to work, but suddenly just stopped two days ago, and I can't get it fixed.
The client creates and successfully sends a User object and a Message object (serialize by the client and deserialize by the server). When the clients receives any of the two classes (serialized by the server and deserialized by the client), I get exceptions, mainly:
java.io.UTFDataFormatException
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(ObjectInputStream.java:3704)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3658)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:3458)
at java.base/java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1239)
at java.base/java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:804)
at java.base/java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:988)
at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2032)
at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1907)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2209)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
at Model.MessageClient$1.run(MessageClient.java:69)
at java.base/java.lang.Thread.run(Thread.java:833)
Every so often, I get:
java.io.InvalidClassException: Model.Message; class invalid for deserialization
at java.base/java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:174)
at java.base/java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:921)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2210)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
Client side - streams
public MessageClient(String ip, int port, String usernameStr, ImageIcon icon, Controller controller) {
this.user = new User(usernameStr, icon);
this.controller = controller;
this.port = port;
this.ip = ip;
this.messageBuffer = new Buffer<>();
this.contacts = new ArrayList<>(); //(ArrayList<Model.User>) readObjectFromFile("files/contacts");
setUpStreams();
setUpThreads();
}
public void setUpStreams(){
try {
s = new Socket(ip, port);
try {
ois = new ObjectInputStream(s.getInputStream());
oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(user);
oos.flush();
users = new ArrayList<>();
setUpThreads();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void setUpThreads(){
t1 = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
try {
Object o = ois.readObject();
if (o.getClass().isAssignableFrom(Message.class)) {
receiveMessage((Message) o);
}
if (o.getClass().isAssignableFrom(ArrayList.class)) {
updateUsers((ArrayList<Model.User>) o);
}
} catch(EOFException e){
System.out.println("stopped");
t2.stop();
t1.stop();
} catch(IOException | ClassNotFoundException e){
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
});
t2 = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
try {
Message currMessage = messageBuffer.get();
oos.writeObject(currMessage);
oos.flush();
} catch(IOException | InterruptedException e){
e.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
Server-side streams
#Override
public synchronized void run() {
while (socket.isConnected() && !socket.isClosed()) {
try {
Object o = ois.readObject();
ih.addToBuffer((Model.Message) o);
} catch (EOFException e) {
try {
socket.close();
t2.stop();
t1.stop();
} catch (IOException ex) {
ex.printStackTrace();
}
} catch (IOException | ClassNotFoundException e) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
chm.put(user, null);
clients.remove(this);
sendAll(new Message(user.getUsername() + " has disconnected", null));
}
private class InputHandler implements Runnable{
private Buffer<Model.Message> inputBuffer;
public InputHandler(){
inputBuffer = new Buffer<>();
}
public void addToBuffer(Message msg){
inputBuffer.put(msg);
}
#Override
public synchronized void run() {
Object o = null;
while (!Thread.interrupted()) {
Message temp = null;
Message sendable = null;
try {
temp = inputBuffer.get();
sendable = new Message(temp.getText(), temp.getIcon(), temp.getRecipients(), temp.getSender());
sendable.setCurrID();
sendable.setUploaded(new Timestamp(System.currentTimeMillis()));
sendSelect(sendable ,sendable.getSender());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void sendSelect(Message msg, User selectedUser){
Client currClient;
if(!chm.containsKey(selectedUser)) {
try {
oos.writeObject(new Message(selectedUser.getUsername() + "not found", null));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
} else if ((currClient = chm.get(selectedUser)) != null) {
try {
currClient.oos.writeObject((Model.Message) msg);
currClient.oos.flush();
msg.setDownloaded(new Timestamp(System.currentTimeMillis()));
callback.downloadTimestamp(msg);
} catch (IOException e) {
e.printStackTrace();
}
} else {
addUnsent(selectedUser, msg);
}
}
The classes I serialized copy and pasted.
The classpath is the same, all fields are serializable and the have no-arg constructors. I also made sure both encoding on are set to UTF-8
Message
package Model;
import javax.swing.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.LinkedList;
public class Message implements Serializable{
#Serial
private static final long serialVersionUID = -3930131856060689940L;
private static int nextID = 0;
private int currID;
private final String text;
private final ImageIcon icon;
private Timestamp uploaded;
private Timestamp downloaded;
private final User sender;
private final LinkedList<User> recipients;
public Message(){
currID = nextID;
nextID++;
this.text = null;
this.icon = null;
sender = null;
recipients = null;
}
public Message(String text, User sender){
currID = nextID;
nextID++;
this.text = text;
this.icon = null;
this.sender = sender;
this.recipients = null;
}
public Message(String text, ImageIcon icon, User sender) {
currID = nextID;
nextID++;
this.text = text;
this.icon = icon;
this.sender = sender;
this.recipients = null;
}
public Message(String text, ImageIcon icon, LinkedList<User> recipients, User sender) {
currID = nextID;
nextID++;
this.text = text;
this.icon = icon;
this.sender = sender;
this.recipients = recipients;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof Message){
if( ((Message) obj).getCurrID() == this.currID ){
return true;
}
}
return false;
}
public String getText() {
return text;
}
public ImageIcon getIcon() {
return icon;
}
public Timestamp getUploaded() {
return uploaded;
}
public Timestamp getDownloaded() {
return downloaded;
}
public Model.User getSender(){return sender;}
public int getCurrID(){return currID;}
public void setCurrID(){currID = nextID; nextID++;}
public LinkedList<User> getRecipients(){
return recipients;
}
public void setUploaded(Timestamp uploaded) {
this.uploaded = uploaded;
}
public void setDownloaded(Timestamp downloaded) {
this.downloaded = downloaded;
}
}
User
package Model;
import javax.swing.*;
import java.io.Serial;
import java.io.Serializable;
public class User implements Serializable{
#Serial
private static final long serialVersionUID = -5886308724572898536L;
private String username;
private ImageIcon image;
public User(String username, ImageIcon image){
this.username = username;
this.image = image;
}
public int hashCode() {
return username.hashCode();
}
public boolean equals(Object obj) {
if(obj!=null && obj instanceof User)
return username.equals(((User)obj).getUsername());
return false;
}
public String getUsername() {
return username;
}
#Override
public String toString(){
return username;
}
}
The issue was I called setUpThread() twice, messing with the input stream. So if you get this kind of problem, make sure you don't initialize your threads (that are reading input stream from the sockets) more than once.
I have a music player that downloads a directory from the FTP server to the SD card. And the player downloads and accepts server settings (there are two versions of ME and CE), but it happens after downloading the application crashes. When I delete some folders after downloading it works normally in ME mode, but when I download it and it takes the CE mode all the time the application crashes.
public class FTPManager {
public static final String LOG_TAG = FTPManager.class.getName();
private static final String HOST = "*******";
private static final String LOGIN = "*******";
private static final String PASSWORD = "*******";
private static final int REPEAT_TIMEOUT_MILLIS = 5 * 1000;
private int mCommandAttempts;
private String host;
private String login;
private String password;
private FTPClient mFtpClient;
private FTPManager(String host, String login, String password) {
this.host = host;
this.login = login;
this.password = password;
mFtpClient = new FTPClient();
}
public FTPManager() {
this(HOST, LOGIN, PASSWORD);
}
public boolean connect() {
mCommandAttempts = 5;
return attemptConnect();
}
private boolean attemptConnect() {
try {
mFtpClient.connect(host);
mFtpClient.login(this.login, password);
mFtpClient.setPassive(true);
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return false;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptConnect();
}
}
return true;
}
public List<String> listFiles() {
return listFiles(FTPFile.TYPE_FILE);
}
public List<String> listDirectores() {
return listFiles(FTPFile.TYPE_DIRECTORY);
}
private List<String> listFiles(int type) {
mCommandAttempts = 5;
return attemptListFiles(type);
}
private List<String> attemptListFiles(int type) {
ArrayList<String> names = new ArrayList<>();
try {
FTPFile[] files = mFtpClient.list();
for (FTPFile file : files) {
if (file.getType() == type) {
names.add(file.getName());
}
}
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return names;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptListFiles(type);
}
}
return names;
}
public boolean downloadFile(OutputStream outputStream, String ftpName) {
mCommandAttempts = 5;
return attemptDownloadFile(outputStream, ftpName);
}
private boolean attemptDownloadFile(OutputStream outputStream, String ftpName) {
try {
mFtpClient.download(ftpName, outputStream, 0, null);
return true;
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return false;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptDownloadFile(outputStream, ftpName);
}
}
return false;
}
public boolean changeDirectory(String path) {
mCommandAttempts = 5;
return attemptChangeDirectory(path);
}
private boolean attemptChangeDirectory(String path) {
try {
mFtpClient.changeDirectory(path);
return true;
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return false;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptChangeDirectory(path);
}
}
return false;
}
public boolean release() {
if (mFtpClient != null) try {
mFtpClient.logout();
mFtpClient.disconnect(true);
mFtpClient = null;
return true;
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
return false;
}
return false;
}
}
And
public class FTPDirectory implements Parcelable {
private StringBuilder builder;
public FTPDirectory(String host) {
builder = new StringBuilder(host);
}
protected FTPDirectory(Parcel in) {
builder = new StringBuilder(in.readString());
}
public static final Creator<FTPDirectory> CREATOR = new Creator<FTPDirectory>() {
#Override
public FTPDirectory createFromParcel(Parcel in) {
return new FTPDirectory(in);
}
#Override
public FTPDirectory[] newArray(int size) {
return new FTPDirectory[size];
}
};
public FTPDirectory append(String path) {
builder.append("/").append(path);
return this;
}
public String getPath() {
return builder.toString();
}
public static FTPDirectory getImgDirectory() {
return new FTPDirectory("/img");
}
public static FTPDirectory getAdDirectory() {
return new FTPDirectory("/adv");
}
public static FTPDirectory getMusicDirectory() {
return new FTPDirectory("/music");
}
public static FTPDirectory getChannelDirectory(String channel, int index) {
return getChannelRootDirectory(channel)
.append(Integer.toString(index));
}
public static FTPDirectory getChannelRootDirectory(String channel) {
return getMusicDirectory()
.append(channel);
}
#Override
public String toString() {
return "FTPDirectory{" +
"Path=" + builder.toString() +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getPath());
}
}
I think somewhere here there may be a mistake. It turns out that one file reads and the other does not, but the format is the same. Please help to solve the problem.
On my serialized XML File is only one attribute of my Object saved, although four should be saved. I think this is due to y XStream Object registering only one converter, although he should register four.
My Converters are all functioning individually. I tested them one by one.
My XML File:
<object-stream>
<model.Product>13</model.Product>
</object-stream>
My Product class which should be saved:
public class Product implements Externalizable, Serializable {
private static final long serialVersionUID = -8437751114305532162L;
#XStreamConverter(converter.NameConverter.class)
private SimpleStringProperty name;
#XStreamConverter(converter.PriceConverter.class)
private SimpleDoubleProperty price;
#XStreamConverter(converter.CountConverter.class)
private SimpleIntegerProperty quantity;
#XStreamConverter(converter.IDConverter.class)
private long id;
public Product(String name, int quantity, double price, long id)
{
this.name=new SimpleStringProperty(name);
this.quantity=new SimpleIntegerProperty(quantity);
this.price=new SimpleDoubleProperty(price);
this.id=id;
//Getter and Setter and implentation of Externalizable
My XStream class
XStream xstream;
ObjectInputStream ois;
ObjectOutputStream oos;
#Override
public void close() throws IOException {
if (oos != null) {
oos.close();
}
if (ois != null) {
ois.close();
}
}
#Override
public void writeObject(Product obj) throws IOException {
try {
oos.writeObject(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
public void open(InputStream input, OutputStream output) throws IOException {
xstream = createXStream(model.Product.class);
converter.ConverterManager con=new ConverterManager();
con.registerAllConverters(xstream);
if (input != null) {
if (input.available() > 0) {
ois = xstream.createObjectInputStream(input);
}
}
if (output != null) {
oos = xstream.createObjectOutputStream(output);
}
}
}
My ConverterManager:
import com.thoughtworks.xstream.XStream;
public class ConverterManager {
public void registerAllConverters(XStream xstream)
{
xstream.aliasAttribute("Product Price", "price");
xstream.registerConverter(new PriceConverter());
xstream.aliasAttribute("Product ID", "id");
xstream.registerConverter(new IDConverter());
xstream.aliasAttribute("Product Name", "name");
xstream.registerConverter(new NameConverter());
xstream.aliasAttribute("Product quantity", "quantity");
xstream.registerConverter(new CountConverter());
}
}
My writeObject, open and close methods are called from this method from another class:
private void saveModel() {
XStreamStrategy s=new XStreamStrategy();
try {
s.open(getFilePath());
} catch (IOException e) {
e.printStackTrace();
}
for(fpt.com.Product p: model)
{
try {
s.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This is my first experience with serialization. I have my data in an arraylist. When I deserialize it, the arraylist is empty and I can't figure out why. The arraylist contains only two objects (but in the future could hold more) of class Account. The Account class is serializable as I beleive is the case with ArrayList objects. Here is my code:
public class BankDatabase implements Serializable
{
public ArrayList<Account> accounts;
private static ObjectOutputStream output;
private static ObjectInputStream input;
public BankDatabase()
{
accounts = new ArrayList();
File database = new File("database.ser");
if(!database.exists())
{
Account testAccount[] = new Account[2];
testAccount[0] = new Account(12345, 54321, 1000.0, 1200.0);
testAccount[1] = new Account(98765, 56789, 200.0, 200.0);
accounts.add(0, testAccount[0]);
accounts.add(1, testAccount[1]);
}
else
loadDatabase();
}
public static void openIn()
{
try
{
input = new ObjectInputStream(Files.newInputStream(Paths.get("database.ser")));
}
catch (IOException ioException)
{
System.err.println("Could not open file. Closing Program.");
System.exit(1);
}
}
public static void openOut()
{
try
{
output = new ObjectOutputStream(Files.newOutputStream(Paths.get("database.ser")));
}
catch (IOException ioException)
{
System.err.println("Could not open file. Closing Program.");
System.exit(1);
}
}
public void readData()
{
try
{
while(true)
{
accounts.add((Account) input.readObject());
}
}
catch (EOFException endOfFileException)
{
System.out.printf("No More Records%n");
}
catch (ClassNotFoundException classNotFoundException)
{
System.err.println("Invalid object type.");
}
catch (IOException ioException)
{
System.err.println("Could not read file.");
}
}
public void saveData()
{
try
{
for(Account currentAccount : accounts)
{
output.writeObject(currentAccount);
}
}
catch (IOException ioException)
{
System.err.println("Error writing to file. Terminating");
}
}
public void closeOut()
{
try
{
if (output != null)
output.close();
}
catch (IOException ioException)
{
System.err.println("Error closing file. Terminating.");
System.exit(1);
}
}
public void closeIn()
{
try
{
if (input != null)
input.close();
}
catch (IOException ioException)
{
System.err.println("Error closing file. Terminating.");
System.exit(1);
}
}
public void loadDatabase()
{
openIn();
readData();
closeIn();
}
public void updateDatabase()
{
openOut();
saveData();
closeOut();
}
}
public class Account implements Serializable
{
public int accountNumber;
public int pin;
public double availableBalance;
public double totalBalance;
public Account(int theAccountNumber, int thePIN,
double theAvailableBalance, double theTotalBalance)
{
accountNumber = theAccountNumber;
pin = thePIN;
availableBalance = theAvailableBalance;
totalBalance = theTotalBalance;
}
ArrayList is Serializable, do objectOuput.writeObject(list) to save it and List list = (List)objectInputStream.readObject() to read back
I try to read data from file "sinhvien.dat" then push into array of Student.
My code:
private Student[] docFile() {
Student[] std = null;
FileInputStream f = null;
ObjectInputStream inStream = null;
try {
f = new FileInputStream("student.dat");
inStream = new ObjectInputStream(f);
std = (Student[]) inStream.readObject();// this line throw error
} catch (ClassNotFoundException e) {
System.out.println("Class not found");
} catch (IOException e) {
System.out.println("Error Read file");
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (IOException ex) {
}
}
if (f != null) {
try {
f.close();
} catch (IOException ex) {
}
}
}
return std;
}
Class Student
public class Student implements Serializable { private String studName; Student(String name) { this.studName = name; } public Student() { } public String getStudName() { return studName; } public void setStudName(String studName) { this.studName = studName; } #Override public String toString() { return "Student Name :" + studName; } }
I don't know how to fix this error.
sorry for bad english :(
Exception in thread "Thread-3" java.lang.ClassCastException: btvn_l5.Student cannot be cast to [Lbtvn_l5.Student;
This means, that you cannot cast a single Student-obect into an array of Student-objects.
I think you serialize a Student and try to deserialize a Student[]. Th prefix [L indicates an array.
Take a look at you serializer.