Save an arraylist to cache file and retrieve it - java

I want to create two methods. The one should store and arraylist to the cache and the other should retrieve the arraylist from the cache. The code that I've tried is the following:
public class ByteConverter<T> {
public byte[] write_to_byte_array(ArrayList<T> list,File file){
// write to byte array
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e1) {
Log.d("file not found", "file not found", e1);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
for (T element : list) {
try {
out.writeUTF((String) element);
} catch (IOException e) {
Log.d("Error converting List to byte array", "Error converting List to byte array", e);
}
}
byte[] bytes = baos.toByteArray();
int len1 = 0;
while (len1 < bytes.length) {
try {
fos.write(bytes, 0, len1);
len1++;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
public String read_to_byte_array(byte[] bytes) throws IOException{
// read from byte array
String element = null;
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
DataInputStream in = new DataInputStream(bais);
while (in.available() > 0) {
element = in.readUTF();
}
return element;
}
}
However the aforementioned methods doesn't write anything to the file. I don't know why. Can anyone help me? Also I'm taking a ClassCastException at this line:
out.writeUTF((String) element);

First, the ClassCastExcetion is the reason you are not getting any output. The exception is thrown before your code writes to the file ...
Second, the ClassCastException is happening because the element is not a String. In theory, you could call element.toString() to get a string representation, but the chances are that that representation will NOT be suitable for your purpose.
So what is the correct approach?
Well it depends on the types of the objects in list.
If they implement Serializable (or Externalizable) then you should be able to use Java serialization. Read this section of the Java tutorial for more details.
Another option might be to use something like JAXP or GSON which can serialize POJOs to XML and JSON respectively.
The final fallback is to code the serialization method (and a corresponding serialization method) by hand.
Finally, I should point out some other errors in your code:
1) This code is wrong:
int len1 = 0;
while (len1 < bytes.length) {
fos.write(bytes, 0, len1);
len1++;
}
This will write:
bytes[0]
bytes[0], bytes[1]
bytes[0], bytes[1], bytes[2]
and so on.
The correct way to write bytes is:
fos.write(bytes);
or
fos.write(bytes, 0 bytes.length);
2) Your exception handling logic is incorrect. In 3 or 4 places you catch an exception, print or log something ... and then continue as if nothing had gone wrong. What you should probably do is let the exceptions propagate, and handle them at a higher level.
3) If something goes wrong in the write_to_byte_array method it is likely to leak a file descriptor. Best practice is to either close resources in a finally block, or use the new Java 7 try-with-resource syntax.
4) The names of the read_to_byte_array and write_to_byte_array methods violate the accepted Java style guidelines. They should be readToByteArray (or better still readFromByteArray) and writeToByteArray.

Rergarding ClassCastException, if element of type T isn't a String you will get that exception since that object cannot be casted to String. Maybe you are looking for toString method of element.
Also take a look to the FileUtils class of Apache Commons and the method writeLines

use Serializable Object , because ArrayList implement Serializable , must be implement Serializable.
youself can custom data type ,for example:
length|value|length|value....
4bytes|bytes|4bytes|bytes....

Related

Java inputStream to String Hangs

I am developing a tool to get client information, send to a server, and receive the information again (a proxy). I'm also trying to dump the data being received from the server. I can read the Integer representation of the inputStream, but I am not able to read the String format. I've tried the below example, but it hangs and never connects to the server. Also, System.out.println(inputStream.nextLine()) displays only one line and hangs.
public void run() {
try {
int i;
while ((i = inputStream.read()) != -1){
System.out.println(IOUtils.toString(inputStream));
outputStream.write(i);
}
} catch (IOException e) {
System.out.println("Lost connection to the client.");
}
}
My guess at this is that you're reading from the input stream, and then using the IOUtils library to read from the stream too. My suspicion is that your application is reading the first byte from the input stream, then reading the remainder of the inputstream with the IOUtils library, and then printing out the initial byte that was read.
It doesn't make any sense to call IOUtils.toString(inputstream) from within a loop. That method call will put all the data from the inputstream into a string. Why have the loop at all in this case?
You might want to try not using the IOUtils library for this. Just read a byte of data, push it into a StringBuilder, and then print that byte. In this approach, the loop would be necessary, and you'll probably get what you're looking for.
Try something like this, but modify it as necessary to print the data at the same time to your output stream:
public static String inputStreamToString(final InputStream is, final int bufferSize)
{
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try {
final Reader in = new InputStreamReader(is, "UTF-8");
try {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
}
finally {
in.close();
}
}
catch (UnsupportedEncodingException ex) {
/* ... */
}
catch (IOException ex) {
/* ... */
}
return out.toString();
}
The code you posted doesn't attempt to connect to the server, but if any of it executes you must already have connected.
If your program is hanging in this code, either the server hasn't sent any data yet, or the IOUtils.toString() method probably tries to read to EOS, so if the peer doesn't close the connection you will block here forever.
If your program hangs at a readLine() call it means the peer hasn't sent a line to read.

Java, need a while loop to reach eof. i.e.while !eof, keep parsing

I currently have a working parser. It parses a file once(not what I want it to do) and then outputs parsed data into a file. I need it to keep parsing and appending to the same output file until the end of the input file. Looks something like this.
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Everything is done except the while loop. It only parses once when I need it to keep parsing. I'm looking for a while loop function to reach eof.
I'm also using a DataInputStream. Is there some sort of DataInputStream.hasNext function?
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
i.e. dis.read();
.
//Need a while !eof while loop
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Warning: This answer is incorrect. See the comments for explanation.
Instead of looping until an EOFException is thrown, you could take a much cleaner approach, and use available().
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
while (dis.available() > 0) {
// read and use data
}
Alternatively, if you choose to take the EOF approach, you would want to set a boolean upon the exception being caught, and use that boolean in your loop, but I do not recommend it:
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
boolean eof = false;
while (!eof) {
try {
// read and use data
} catch (EOFException e) {
eof = true;
}
}
DataInputStream has a lot of readXXX() methods that do throw EOFException but the method that you're using DataInputStream.read() does not throw EOFException.
To correctly identify the EOF while using read() implement your while loop as follows
int read = 0;
byte[] b = new byte[1024];
while ((read = dis.read(b)) != -1) { // returns numOfBytesRead or -1 at EOF
// parse, or write to output stream as
dos.write(b, 0, read); // (byte[], offset, numOfBytesToWrite)
}
If you are using FileInputStream, here's an EOF method for a class that has a FileInputStream member called fis.
public boolean isEOF()
{
try { return fis.getChannel().position() >= fis.getChannel().size()-1; }
catch (IOException e) { return true; }
}

Reading from a binary file object

I have to read a series of object from a binary file.
I use:
ObjectOutputStream obj = new ObjectOutputStream(new FileInputStream(fame));
obj.readObject(p);
where p is a reference to an object I had created. How can I read the entire file until the end?
I can use:
while(p!=null){}
?
readObject() returns null if and only if you wrote a null. The correct technique is to catch EOFException and when you get it close the stream and exit the reading loop.
Let's assume you meant ObjectInputStream and p = obj.readObject().
I would do something like this: (this is wrong, see EDIT below)
FileInputStream fstream = new FileInputStream(fileName);
try {
ObjectInputStream ostream = new ObjectInputStream(fstream);
while (ostream.available() > 0) {
Object obj = ostream.readObject();
// do something with obj
}
} finally {
fstream.close();
}
EDIT
I take it back! EJP rightly points out that the use of available() is incorrect here. I think the fixed code might be:
FileInputStream fstream = new FileInputStream(fileName);
try {
ObjectInputStream ostream = new ObjectInputStream(fstream);
while (true) {
Object obj;
try {
obj = ostream.readObject();
} catch (EOFException e) {
break;
}
// do something with obj
}
} finally {
fstream.close();
}
Although the documentation for readObject() doesn't explicitly say that EOFException is thrown at the end of the stream, it seems to be implied and may be the only way to detect the end of the stream.
Another option if you control the code that wrote the stream would be to write an object count at the beginning, or a flag after each object indicating whether the previous object was the final one.
If you want to read object into your program, then you have to use ObjectInputStream, not ObjectOutputStream.
And if you will store a bunch of objects, then use an appropriate Collection for writing to file and reading from it. The API documentation for readObject does not state that it will return null or throw an exception if EOF is reached. So to be on the safe side, use Collections.
You may also want to read API docs on ObjectInputStream and ObjectOutputStream.
Boolean i = true;
while(i) {
try {
System.out.println(reader.readObject());
} catch(Exception e) {
i = false;
System.out.println("Dead end");
}
}
Guava's Files.toByteArray does what you want so if fame in your code is a File, then
import com.google.common.io.Files;
...
byte[] fameBytes = Files.toByteArray(fame);

How to count number of objects stored in a *.ser file

I'm trying to read all the objects stored in a *.ser file and store them in a array of objects. How can I get the number of objects stored in that file(So that I can declare the array to be number_of_objects long)?
I've checked the API and was unable to find a Desirable function.
-edit-
A Part of the code:
Ser[] objTest2 = new Ser[number_of_objects];
for(int i=0; i<=number_of_objects, i++) {
objTest2[i] = (Ser)testOS2.readObject();
objTest2[i].printIt();
}
What you want to look at is the ArrayList class.
It is basically a dynamically growing Array.
You can add items to it like so:
ArrayList list = new ArrayList();
list.add(someObject);
list.add(anotherBoject);
The list will grow as you add new items to it. So you don't have to know the size ahead of time.
If you need to get an array out if the List at the end you can use the toArray() method of List.
Object[] arr = list.toArray(new Object[list.size()]);
Edit:
Here is a general implementation of what you need:
List<Ser> objTest2 = new ArrayList<Ser>();
while (testOS2.available > 0) {
Ser toAdd = ((Ser)testOS2.readObject());
toAdd.printIt();
objTest2.add(toAdd);
}
*I don't think available() is a reliable test for whether or not there are more bytes to read.
Year's later this post is still relevant. I was looking for a way to loop through a .ser file while de-serializing each file, and to some extent, Rohit Singh's post helped. This is my version of the same though:
ArrayList<Profile> availableProfiles = new ArrayList<Profile>();
try {
FileInputStream fileStream = new FileInputStream("profiles.ser");
ObjectInputStream os = new ObjectInputStream(fileStream);
Object profileObject = null;
while((profileObject = os.readObject()) != null) {
Profile castObject = (Profile) profileObject;
availableProfiles.add(castObject);
}
os.close();
} catch(Exception ex) {
if(ex instanceof EOFException) {
out.println("End of file reached!");
out.println("Total profiles found is: " + availableProfiles.size());
} else if(ex instanceof FileNotFoundException) {
out.println("File not found! \n Answer the following to create your profile");
createProfile();
}
}
The most important part is the position of the while-loop. In my version, that loop does not create a new FileInputStream or ObjectInputStream like Singh's does. That will make the ObjectInputStream read the .ser file afresh each time those two are created, and as a result, you only add() one Profile object to the ArrayList- the first one to be serialized- each time the loop restarts.
Instead, we only loop the with the readObject() method until it produces a null signifying no other object was found in the file, and it triggers the EOFException.
while(true)
{
try
{
Employee e=(Employee) ois.readObject();
System.out.println("successfully deserialized.........showing details of object.");
e.display();
}
catch(Exception e)
{
if(e instanceof java.io.EOFException)
{
System.out.println("All objects read and displayed");
break;
}
else
{
System.out.println("Some Exception Occured.");
e.printStackTrace();
}
}
}
Just keep reading objects until you get EOFException. That's what it's for. And use a List instead of an array so you don't need the count in advance.

Java Applet - Image Export Performance Issues

I have a Java Applet that I'm making some edits to and am running into performance issues. More specifically, the applet generates an image which I need to export to the client's machine.
This is really at the proof-of-concept stage so bear with me. For right now, the image is exported to the clients machine at a pre-defined location (This will be replaced with a save-dialog or something in the future). However, the process takes nearly 15 seconds for a 32kb file.
I've done some 'shoot-by-the-hip' profiling where I have printed messages to the console at logical intervals throughout the method in question. I've found, to my surprise, that the bottleneck appears to be with the actual data stream writing process, not the jpeg encoding.
KEEP IN MIND THAT I ONLY HAVE A BASIC KNOWLEDGE OF JAVA AND ITS METHODS
So go slow :p - I'm mainly looking for suggestions to solve the problem rather the solution itself.
Here is the block of code where the magic happens:
ByteArrayOutputStream jpegOutput = new ByteArrayOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(jpegOutput);
encoder.encode(biFullView);
byte[] imageData = jpegOutput.toByteArray();
String myFile="C:" + File.separator + "tmpfile.jpg";
File f = new File(myFile);
try {
dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(myFile),512));
dos.writeBytes(byteToString(imageData));
dos.flush();
dos.close();
}
catch (SecurityException ee) {
System.out.println("writeFile: caught security exception");
}
catch (IOException ioe) {
System.out.println("writeFile: caught i/o exception");
}
Like I mentioned, using system.out.println() I've narrowed the performance bottleneck to the DataOutputStream block. Using a variety of machines with varying hardware stats seems to have little effect on the overall performance.
Any pointers/suggestions/direction would be much appreciated.
EDIT:
As requested, byteToString():
public String byteToString(byte[] data){
String text = new String();
for ( int i = 0; i < data.length; i++ ){
text += (char) ( data[i] & 0x00FF );
}
return text;
}
You might want to take a look at ImageIO.
And I think the reason for the performance problem is the looping in byteToString. You never want to do a concatenation in a loop. You could use the String(byte[]) constructor instead, but you don't really need to be turning the bytes into a string anyway.
If you don't need the image data byte array you can encode directly to the file:
String myFile="C:" + File.separator + "tmpfile.jpg";
File f = new File(myFile);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(
new BufferedOutputStream(fos));
encoder.encode(biFullView);
}
catch (SecurityException ee) {
System.out.println("writeFile: caught security exception");
}
catch (IOException ioe) {
System.out.println("writeFile: caught i/o exception");
}finally{
if(fos != null) fos.close();
}
If you need the byte array to perform other operations it's better to write it directly to the FileOutputStream:
//...
fos = new FileOutputStream(myFile));
fos.write(imageData, 0, imageData.length);
//...
You could also use the standard ImageIO API (classes in the com.sun.image.codec.jpeg package are not part of the core Java APIs).
String myFile="C:" + File.separator + "tmpfile.jpg";
File f = new File(myFile);
ImageIO.write(biFullView, "jpeg", f);

Categories