3
\$\begingroup\$

I have created the following class to read Serializable object from file and write to a file.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.channels.FileLock;

/**
 * Class FileSerializeStreamer is used to read and write Serialise object to
 * file.
 * 
 * @author TapasB
 */
public class FileSerializeStreamer {

    /**
     * Constructor FileSerializeStreamer
     * 
     * @author TapasB
     */
    public FileSerializeStreamer() {

    }

    /**
     * Method readSerializable reads the Serialised object from file and
     * returns. If the file is null or doesn't exist then it returns null
     * without throwing any error.
     * 
     * @author TapasB
     * @param file
     *            - the instance of the file to read from.
     * @param clazz
     *            - the class type of the object.
     * @return the instance of the object.
     */
    public <T extends Serializable> T readSerializable(File file, Class<T> clazz) {
        if (file == null || !file.exists()) {
            return null;
        }

        RandomAccessFile serFile = null;
        FileChannel fileChannel = null;
        byte[] bytes = null;

        try {
            serFile = new RandomAccessFile(file, "rw");
            fileChannel = serFile.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate((int) serFile.length());
            FileLock fileLock = fileChannel.lock();
            fileChannel.read(buffer);
            fileLock.release();
            bytes = buffer.array();
            buffer.clear();
        } catch (Exception cause) {
            cause.printStackTrace();
        } finally {
            closeStream(fileChannel);
            closeStream(serFile);
        }

        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;

        try {
            byteArrayInputStream = new ByteArrayInputStream(bytes);
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return clazz.cast(objectInputStream.readObject());
        } catch (Exception cause) {
            cause.printStackTrace();
        } finally {
            closeStream(objectInputStream);
            closeStream(byteArrayInputStream);
        }

        return null;
    }

    /**
     * Method writeSerializable writes the Serialised object to the given file.
     * If the file is null or doesn't exist then it returns without throwing any
     * error.
     * 
     * @author TapasB
     * @param file
     *            - the instance of the file to write to.
     * @param serialized
     *            - the instance to be written.
     */
    public <T extends Serializable> void writeSerializable(File file, T serialized) {
        if (file == null || !file.exists()) {
            return;
        }

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = null;

        try {
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(serialized);
        } catch (Exception cause) {
            cause.printStackTrace();
        } finally {
            closeStream(objectOutputStream);
        }

        RandomAccessFile serFile = null;
        FileChannel fileChannel = null;

        try {
            byte[] source = byteArrayOutputStream.toByteArray();
            serFile = new RandomAccessFile(file, "rw");
            fileChannel = serFile.getChannel();
            ByteBuffer buffer = fileChannel.map(MapMode.READ_WRITE, 0, source.length);
            FileLock fileLock = fileChannel.lock();
            buffer.put(source);
            fileLock.release();
            buffer.clear();
        } catch (Exception cause) {
            cause.printStackTrace();
        } finally {
            closeStream(byteArrayOutputStream);
            closeStream(fileChannel);
            closeStream(serFile);
        }
    }

    // Method closeStream
    private void closeStream(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (Exception cause) {
            cause.printStackTrace();
        }
    }
}

I would like to know

  • If there is any drawback present in the code?
  • Is the right way to do it?
  • What happens if the size of the data that I want to read or write exceeds the Integer.MAX_VALUE? How to handle that scenario?
\$\endgroup\$
3
\$\begingroup\$

Why? Why use NIO? You are reading the data in to a buffer, completely, then you are performing the deserialization from that. What advantages of NIO are you using?

Even using your system, though, you should be using try-with-resources, and you should use the FileChannel.open(...) mechanism for it...

try (FileChannel channel = FileChannel.open(file.getPath())) {
    ... do something with the channel
} catch (IOException ...) {
    ....
    return null;
}

But, given your use case, I would simply do:

try {
    byte[] data = Files.readAllBytes(file.getPath());
    try (ObjectINputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
        return clazz.cast(ois.readObject());
    } catch (....) {
        ... deserialization problem
    }
} catch (....) {
    ... IO Problem
}

If you really require the file locking, then do it all in one process anyway, and don't use the intermediate byte[] array:

try (FileChannel channel = FileChannel.open(file.getPath())) {
    FileLock lock = channel.lock();
    try (ObjectInputStream ois = new ObjectInputStream(Channels.newInputStream(channel))) {
         return clazz.cast(ois.readObject());
    } finally {
        lock.release();
    }
    try (ObjectINputStream
}

Note, all the comments on the reading side, also apply to the writing side too. You can convert your serialization to match the same concepts as well.

\$\endgroup\$
  • \$\begingroup\$ Thank you for reviewing my code. Since I am using JDK6 I don't have many of the methods that you have mentioned. But I understand the parts that you have mentioned. But still I am thinking if the file is a large one and cannot be converted to a byte array \$\endgroup\$ – Tapas Bose Jan 7 '15 at 12:05
  • 1
    \$\begingroup\$ Using the Channels.newInputStream will remove the need for the byte[] array entirely. That will remove the issue with large files entirely too (if the data was OK to serialize, then it will be OK to read too). \$\endgroup\$ – rolfl Jan 7 '15 at 12:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.