I used to save items in Android using Android Studio with Java. But now I want to read in exactly that data in my rewritten app in Flutter SDK (Dart language). But it seems that the files that are written are very Java specific. This is the save and load method in Java.
public void save(Item item)
{
String json = gson.toJson(item);
FileOutputStream fos = null;
try {
fos = context.openFileOutput("item_"+ item.getUid(), Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(json);
os.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private Item loadItem(String fileName)
{
FileInputStream fis = null;
try {
fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
Object object = is.readObject();
Item item = null;
String json = (String)object;
item = gson.fromJson(json, Item.class);
is.close();
fis.close();
return item;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
And now for reading it in Dart
Uint8List bytes = f.readAsBytesSync();
var data = bytes.buffer.asByteData();
// HOW TO DETECT JAVA
if (?SOMETHING?) { }
The length of bytes is quite large. It is an array of length = 3 245 500.
The length of the json string should be between 740 and 840 bytes long (i.e. a relatively short json).
How could I read in only the json part and not the entire Java 'overhead'/'java serialization format'
What you are currently doing is:
Serialize to JSON
Serialize the Java String with JSON data using Java serialization
Instead, change your code to:
Serialize to JSON (directly to file, or first to string, then to file using OutputStreamWriter wrapping a FileOutputStream).
Trying to reimplement Java serialization in another language is extremely painful, and your current usage of Java serialization makes little sense, and it is unnecessary overhead and only makes your life harder. Remove it from the mix and write the JSON directly to file.
It will simplify your code, and removes the need to implement Java serialization in Dart.
To be able to handle current files written in this combination of Java serialization wrapping JSON data, I would recommend using some extra code in your Java application to detect if a file is Java serialization and if so do a one-off conversion to store the JSON directly.
Alternatively, you can read up on the Java serialization protocol in Java Object Serialization Specification.
Related
I am writing a small program that inserts customer details in ArrayList and write it in file.
The problem is with ObjectOutputStream I was able to append data in file with turning FileOutputStream("",true). But when I try to read data with ObjectInputStream it only reads data that was inserted at first instance. But data is being added to file.
Here is the code -
public void insertCustomer() throws IOException
{
Customer1=new customerDetails("1", "Moeen4", "654654", "asdf", "coding", "student", "65464", "3210");
Customer3=new customerDetails("3", "Moeen5", "888888", "asdf", "coding", "student2", "65464", "321022");
Customer4=new customerDetails("4", "Moeen6", "654654", "asdf", "coding", "student", "65464", "7890");
_list=new ArrayList<customerDetails>();
_list.add(Customer1);
_list.add(Customer3);
_list.add(Customer4);
customersList cl=new customersList();
cl.WriteObjectToFile(files._customers, _list);
ArrayList<customerDetails>li=new ArrayList<customerDetails>();
li= (ArrayList) cl.ReadObjectFromFile(files._customers);
for(int i=0;i<li.size();i++)
{ System.out.println(li.size());
System.out.println(li.get(i).Id);
System.out.println(li.get(i).name);
System.out.println(li.get(i).annual_Salary);
System.out.println(li.get(i).Company);
System.out.println(li.get(i).dateOfBirth);
System.out.println(li.get(i).phone_Number);
}
}
public void WriteObjectToFile(String filepath,Object serObj) {
try {
FileOutputStream fileOut = new FileOutputStream(filepath,true);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serObj);
objectOut.close();
System.out.println("The Object was succesfully written to a file");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public Object ReadObjectFromFile(String filepath) {
try {
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
Object obj = objectIn.readObject();
objectIn.close();
System.out.println("The Object has been read from the file");
return obj;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
The real problem here is this:
FileOutputStream fileOut = new FileOutputStream(filepath, true);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serObj);
You cannot append to an existing serialization like this. If you do get an exception when attempting to read any objects appended to a pre-existing (non-empty) file.
There is a trick / hack that allows you to append objects though; see Appending to an ObjectOutputStream. (The trick involves suppressing the writing of the object stream header. It is most easily done by overriding the method that does this.)
The other approach is to keep the ObjectOutputStream open between writeObject calls. However there are use-cases where that won't be possible.
Note that there is a semantic difference between these two approaches. The best way to explain it is that the first one behaves as if you called reset() each time you write an object; see the javadoc.
Another thing to note about your example is that your reader code only reads one object. If you want to read multiple objects, you need to call readObject in a loop. And that will only work if you have used the trick / hack above to avoid writing a spurious header.
As suggested the code is only reading the first object and you would need to use a loop to read all the objects from multiple writes.
However -
If you change the above code i.e. ReadObjectFromFile to use a loop this will lead to an StreamCorruptedException: invalid type code: AC. The ObjectOutputStream constructor writes a serialization stream header to the OutputStream i.e. the file, when it is closed and reopend using new ObjectOutputStream and new FileOutputStream(filepath, true) a new header will be written at the append point so you will get an exception as the header is only expected once at the beginning of the file
This will need to be handled e.g.
Use the same ObjectOutputStream for the duration
Override java.io.ObjectOutputStream.writeStreamHeader() to account for append to a file
Change the approach and use List<List<Object>> which you could read, add, write to as a whole.
Loop example would throw exception unless ObjectOutputStream approach is changed
public Object ReadObjectFromFile(String filepath) {
List<List<Object>> objects = new ArrayList<>();
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
try {
while (true) {
List<Object> obj = (List<Object>) objectIn.readObject();
// This will throw StreamCorruptedException: invalid type code: AC
objects.add(obj);
System.out.println("The Object has been read from the file");
}
} catch (EOFException ex) {
// ENDS WHEN ALL READ
} finally {
fileIn.close();
objectIn.close();
}
return objects;
}
Sudo code List<List<Object>> approach -
public void readAndWrite() {
List<Object> customer = List.of(new CustomerDetails(...),
new CustomerDetails(...),
new CustomerDetails(...));
List<List<Object>> objects = readFromFile("existing-customer-file.txt");
objects.addAll(customer);
writeObjectToFile(objects);
}
How to read the multiple objects in a text file. I am trying to read the text file. I am always get only the first object of the file. How to get the all objects from text file...
List<Processedfile> processfiles = new ArrayList<Processedfile>();
Processedfile processfile = new Processedfile();
processfile.setFilename(filename);
processfile.setCountrow(uploadedFileCount);
processfile.setDate(dateformat);
processfiles.add(processfile);
writeReportTextFile(processfiles);
Write the processedfile object in the text file...
Write the file
public void writeReportTextFile(List<Processedfile> processfiles) {
String processedfilereport = "D:\\PaymentGatewayFiles\\MSSConsolidate\\processedfilereport.txt";
try {
File file = new File(processedfilereport);
FileOutputStream f = new FileOutputStream(file.getAbsoluteFile(), true);
// System.out.println(file);
ObjectOutputStream s = new ObjectOutputStream(f);
// System.out.println("the write"+reportfile);
s.writeObject(processfiles);
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Read the file..
public List<Processedfile> processreportfileread() {
List<Processedfile> a1 = new ArrayList();
String processedfilereport = "D:\\PaymentGatewayFiles\\MSSConsolidate\\processedfilereport.txt";
try {
File file = new File(processedfilereport);
FileInputStream r = new FileInputStream(file);
ObjectInputStream sp = new ObjectInputStream(r);
a1 = (List) sp.readObject();
System.out.println("the list is" +a1);
Iterator i = a1.iterator();
while(i.hasNext()) {
System.out.println("the iterator report is ===="+i.next());
}
}
catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return a1;
}
The object serialization protocol / APIs can cope with a stream containing single object or a sequence of objects. But it cannot cope with a concatenation of streams1 ... which is what your application appears to be creating by opening the output file in "append" mode)
The solution is to NOT write them like that. This:
FileOutputStream f = new FileOutputStream(file.getAbsoluteFile(), true);
is fundamentally wrong. It results in multiple object streams being concatenated. That can't be read.
The correct approach is to either:
assemble all of the Processedfile objects into a single list, and write the list ... with one writeObject call, or
use a sequence of writeObject calls to write the Processedfile objects to a single ObjectOutputStream, or
write the objects to multiple output files, and send the files as a ZIP archive or similar.
1 - To understand why, you need to read the Object Serialization specification, and in particular you need to understand the serialization protocol / format.
I might be trying to do this the hard way so let me know if there is a better solution.
I am making a simple text game in Java which you select your actions by a GUI. I have a couple of classes I am trying to serialize one being the player and another being an NPC. Is there an easy way to serialize more then one object (player and NPC) into the same file? I can serialize one object and load it back into the game.
Am I going about this the wrong way? Is there a simpler way of trying to save the game state?
If I have a class that creates multiple objects and I serialize that class, will the objects it created be serialized as well?
Thanks
An alternate approach to writing objects sequentially is to store them in a collection (e.g. a HashMap), since collections can be serialized. This may make it a little easier to manage upon retrieval, especially if you have many objects to serialize/deserialize. The following code demonstrates this:
String first = "first";
String second = "second";
HashMap<String, Object> saved = new HashMap<String, Object>();
saved.put("A", first);
saved.put("B", second);
try {
FileOutputStream fos = new FileOutputStream("test.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(saved);
oos.flush();
oos.close();
fos.close();
FileInputStream fis = new FileInputStream("test.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
HashMap<String,Object> retreived = (HashMap<String,Object>)ois.readObject();
fis.close();
System.out.println(retreived.get("A"));
System.out.println(retreived.get("B"));
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Running this should result in:
first
second
Just call writeObject() as many times with as many different objects as you need, and conversely call readObject() ditto.
Hard to believe you haven't already tried it.
I am building a basic bank application, although the usage of the java language is intermediate level.
There I am using file input and output a lots. Along the way some questions has popped up in my mind about the file-i/o in java.
1) What if I create two different text file for writing and reading objects? Does it make any difference?
2) How about the specifying path (or giving file name), what if I use // instead of \\?
3) Do I necessarily need to create a new file object like this: File file=new File("C://Users//Documents//NetBeansProjects//BankFile_assignment.txt"); in my specific case?
Last but not least if you may wonder about my file-i/o class:
public class ReaderWriter {
public void writeToFile(List<BankAccount> accounts) {
try {
File file = new File("C://Users//Documents//NetBeansProjects//BankFile_assignment.txt");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(accounts);//take the arrayList
oos.flush();
oos.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public List<BankAccount> readFromFile() {
List<BankAccount> readData = null;
try {
File file = new File("C://Users//Documents//NetBeansProjects//BankFile_assignment.txt");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
readData = (List<BankAccount>) ois.readObject();
ois.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
return readData;
}
}
1) Better way is to use databases (mySQL, SQLite,...) to access easily to all your datas without I/O worries.
2) If your application might work on different Operating Systems, a safe way to avoid any trouble with the specific symbol of system ( \ on Windows, / on Unix, Mac) is to use File.separator for example. More about this subject .
3) It must work on Windows, but fails on Unix. You can use (with adaptation for path) this instead of: File file = new File(System.getProperty("user.home")+ File.separator + BankFile_assignment.txt); See this .
Well, I am creating dumped objects using a ByteArrayOutputStream. And then will write them to MongoDB as an attribute in my documents. When I read it back how can I convert it to a byte array or a Binary without using a toString in the middle?
This is the way I do it now, and I dont think it is safe:
BasicBSONObject temp = (BasicBSONObject) models.get("0");
model = null;
if (temp != null) {
// TODO fix this serialization!
try {
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(temp.toString().getBytes()));
} catch (IOException e) {
L.error("unable to read model from string!");
L.error(e.getStackTrace().toString());
}
}