EOFException on opening a buffered object stream - java

I'm testing the ObjectInputStream and ObjectOutputStream classes
tried to warp both in buffered stream object ..
File file = new File("file.lel"); //Assuming the file exist and has data stored in it.
//will truncate file
try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file))) //Bad Practice!
) {
SomeObject writeMe = new SomeObject(1, 2, 3, 50.5, 'k'); //Object with 3 ints, a double and a char
final double D = 30.3; //for testing
out.writeDouble(D);
out.writeObject(writeMe);
out.flush();
double DAgain = in.readDouble();
SomeObject readMe = (SomeObject)in.readObject();
readMe.printInfo();
}
//Some catch blocks...
But i'm getting EOFException on line 3 in the code above
Exception in thread "main" java.io.EOFException //header loaded first .. ?!
at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
When i removed the buffer stream objects, code worked .. i.e.
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))
) { ... }
Why this behavior? any idea?

Firstly, don't do this. Don't try to initialize the input stream until you've got data in the file.
As for why it's working when you don't buffer, I believe the problem is with the buffering of the output stream... in the buffered version, you're creating the FileOutputStream which will truncate the file, then wrapping that in a BufferedOutputStream, then wrapping that in an ObjectOutputStream. The last of these will write the preamble data to the stream - but it only gets as far as the BufferedOutputStream which buffers the data. When you try to create an ObjectInputStream reading from the file, it's trying to read the preamble... but there's nothing to read.
You can demonstrate this easily:
import java.io.*;
class Test {
public static void main(String[] args) throws IOException {
// Not disposing of any resources just for simplicity.
// You wouldn't actually use code like this!
FileOutputStream fos = new FileOutputStream("data");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
// Flush the preamble to disk
bos.flush();
FileInputStream fis = new FileInputStream("data");
ObjectInputStream ois = new ObjectInputStream(fis);
}
}
Without the flush() call, you get the the exception you've seen - with it, there's no exception.
As I say though, you simply shouldn't do this in the first place, IMO.

Related

BufferedWriter is not writing to ByteArrayOutputStream

I want to convert an input stream to byte array. I know I can use IOUtils from commons-io. But I am practicing some basics in java io. I read an xml file using BufferedReader and tried writing it to a ByteArrayOutputStream using BufferedWriter. But its not working.
When I write directly to the ByteArrayOutputStream its working. Whats wrong in my code?
try (InputStream inputStream = getClass().getResourceAsStream(
"/productInventory.xml");
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(arrayOutputStream));
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));) {
String line = "";
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
}
System.out.println(arrayOutputStream.size());
} catch (IOException e) {
e.printStackTrace();
}
When I include below line in the loop its working
arrayOutputStream.write(line.getBytes(), 0, line.getBytes().length);
What is wrong while using BufferedWriter?
Nothing's wrong - it's just buffering! :D
The BufferedWriter works by filtering everything you send into it into a buffer - when the buffer is full, or when the writer is closed, or flushed, (It's a Closeable, so you should absolutely close it), it sends along those buffered characters to the underlying writer.
If you want to see the underlying writer update you have to either:
1) Fill up the buffer (default size is 8k in Java)
2) Call .flush()
3) Call .close()
4) As mentioned in comments, you can do a try-with-resources to make the close implicit:
try (BufferedWriter writer = new BufferedWriter(underlyingWriter)) {
// doStuff
}

How can I store a data structure such as a Hashmap internally in Android?

In my Android application I'm trying to store a Map structure such as:Map<String, Map<String, String>>using internal storage. I've looked into using SharedPreferences, but as you know, this only works when storing primitive data types. I tried to use FileOutputStream, but it only lets me write in bytes...Would I need to somehow serialize the Hashmap and then write to file?
I've tried reading through http://developer.android.com/guide/topics/data/data-storage.html#filesInternal but I can't seem to find my solution.
Here's an example of what I'm trying to do:
private void storeEventParametersInternal(Context context, String eventId, Map<String, String> eventDetails){
Map<String,Map<String,String>> eventStorage = new HashMap<String,Map<String,String>>();
Map<String, String> eventData = new HashMap<String, String>();
String REQUEST_ID_KEY = randomString(16);
. //eventData.put...
. //eventData.put...
eventStorage.put(REQUEST_ID_KEY, eventData);
FileOutputStream fos = context.openFileOutput(EVENT_FILENAME, Context.MODE_PRIVATE);
fos.write(eventStorage) //This is wrong but I need to write to file for later access..
}
What is the best approach for storing this type of a data structure internally in an Android App? Sorry if this seems like a dumb question, I am very new to Android. Thanks in advance.
HashMap is serializable, so you could just use a FileInputStream and FileOutputStream in conjunction with ObjectInputStream and ObjectOutputStream.
To write your HashMap to a file:
FileOutputStream fileOutputStream = new FileOutputStream("myMap.whateverExtension");
ObjectOutputStream objectOutputStream= new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(myHashMap);
objectOutputStream.close();
To read the HashMap from a file:
FileInputStream fileInputStream = new FileInputStream("myMap.whateverExtension");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Map myNewlyReadInMap = (HashMap) objectInputStream.readObject();
objectInputStream.close();
+1 for Steve P's answer but it does not work directly and while reading I get a FileNotFoundException, I tried this and it works well.
To Write,
try
{
FileOutputStream fos = context.openFileOutput("YourInfomration.ser", Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(myHashMap);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
And to Read
try
{
FileInputStream fileInputStream = new FileInputStream(context.getFilesDir()+"/FenceInformation.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Map myHashMap = (Map)objectInputStream.readObject();
}
catch(ClassNotFoundException | IOException | ClassCastException e) {
e.printStackTrace();
}
Writing:
FileOutputStream fos = context.openFileOutput(EVENT_FILENAME, Context.MODE_PRIVATE);
ObjectOutputStream s = new ObjectOutputStream(fos);
s.writeObject(eventStorage);
s.close();
Reading is done in the inverse way and casting to your type in readObject

Java: Error with calling the WriteUTF method

I'm having problems with writing a 2d, user-inputted array to a text file. My code thus far (in the Saving method, at least) is:
`public static void Save(String[][] EntryList)
{
try {
String[][] content = EntryList;
File file = new File("CBB.dat");
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
InputStream instream;
OutputStream outstream;
instream = new DataInputStream( new BufferedInputStream(new FileInputStream(file))); // buffers the data stream
outstream = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(file)));
FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter writer = new BufferedWriter(fw);
for (int row = 0; row < EntryList.length; ++row)
{
outstream.writeUTF(EntryList[row][1]);
outstream.writeUTF(EntryList[row][2]);
outstream.writeUTF(EntryList[row][3]);
outstream.writeUTF(EntryList[row][4]);
outstream.writeUTF(EntryList[row][5]);
}
outstream.close();
}catch (IOException e) {
e.printStackTrace();
}
}`
However, when I try to compile, I get the error that Java "cannot find symbol - method WriteUTF(String)"
Apparently there is no writeUTF defined for java.io.OutputStream.
You should probably declare outstream as DataOutputStream reference:
DataOutputStream outstream;
as the method writeUTF is defined for DataOutputStream.

Reading two different objects from file

I am trying to read 2 arraylists using the following methods.
public static ArrayList<Contestant> readContestantsFromFile() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("minos.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<Contestant> contestants = (ArrayList<Contestant>) ois.readObject();
ois.close();
return contestants;
}
public static ArrayList<Times> readContestantsFromFile() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("minos.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<times> times = (ArrayList<Times>) ois.readObject();
ois.close();
return times;
}
Bit this doesn't work. It cannot cast to the the second arraylist type i've saved. So how can I access this? The exact error I got was this:
Exception in thread "main" java.lang.ClassCastException: com.deanchester.minos.model.Contestant cannot be cast to com.deanchester.minos.model.Times
at com.deanchester.minos.tests.testAddTime.main(testAddTime.java:31)
The line that this is referring to is:
ArrayList<times> times = (ArrayList<Times>) ois.readObject();
So how can I read 2 different arraylists from one file?
Use FileOutputStream fos = new FileOutputStream("minos.dat", true); when writing the second file. true is a value of argument "append". Otherwise you override the file content. This is the reason that you read the same collection twice.
When you are reading the second collection from the file you have to skip to the beginning of the second collection. To do this you can remember how many bytes have you read on first phase and then use method skip().
But better solution is to open file only once (I mean call new FileInputStream and new FileOutputStream) only once and then pass it to methods that read collections.
You can read two different objects from a file using a ObjectInputStream, but your problem comes from the fact that you reopen the stream so it starts at the beginning of the file where you have the ArrayList<Contestant> and then you ArrayList<Times>. Try doing everything at once and returning both lists:
public static ContestantsAndTimes readObjectsFromFile() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("minos.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<Contestant> contestants = (ArrayList<Contestant>) ois.readObject();
ArrayList<Times> times = (ArrayList<Times>) ois.readObject();
ois.close();
return new ContestantsAndTimes(contestants, times);
}

Is there a way to create FileInputStream with mark feature?

Is there any possible way to create FileInputStream with mark supported feature as true?
Wrap your Fileinputstream inside a BufferedInputStream.
The buffered streams support marks.
Wrap it in BufferedInputStream.
instead of
FileInputStream fis = new FileInputStream(...);
do this:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(...));
and use bis instead of fis; nothing else should have to change in your code.
BufferedInputStreams are not magic. They will only support marking for as large as their underlying buffers and these buffers are going to take up memory. So if you go down this route its important that you understand the usage case and potentially call the BufferedInputStream constructor with the appropriatedly sized buffer. If the underlying file starts to get large and you mark far enough back then this technique may not work for you.
Try something like this
public FileInputStream fstream;
public DataInputStream in;
public BufferedInputStream bs;
public String path;
public void myExample() throws IOException{
path = "yourPath";
try {
fstream = new FileInputStream(path);
in = new DataInputStream(fstream);
bs = new BufferedInputStream(new InputStreamReader(in));
//do something
br.close(); //when do something is completed
} catch (FileNotFoundException ex) {
JOptionPane.showMessageDialog(null, "File not found");
}
}

Categories