Search code examples
javaperformanceiorandom-access

How to increase io performances of this piece of code


How can I make this piece of code extremely quick? It reads a raw image using RandomAccessFile (in) and write it in a file using DataOutputStream (out)

final int WORD_SIZE = 4;
byte[] singleValue = new byte[WORD_SIZE];
long position;

    for (int i=1; i<=100000; i++)
    {
             out.writeBytes(i + " ");

             for(int j=1; j<=17; j++)
             {
                  in.seek(position);
                  in.read(singleValue);                     
                  String str = Integer.toString(ByteBuffer.wrap(singleValue).order(ByteOrder.LITTLE_ENDIAN).getInt());
                  out.writeBytes(str + " ");
                  position+=WORD_SIZE;      
             }
             out.writeBytes("\n");
    }

The inner for creates a new line in the file every 17 elements

Thanks


Solution

  • I assume that the reason you are asking is because this code is running really slowly. If that is the case, then one reason is that each seek and read call is doing a system call. A RandomAccessFile has no buffering. (I'm guessing that singleValue is a byte[] of length 1.)

    So the way to make this go faster is to step back and think about what it is actually doing. If I understand it correctly, it is reading each 4th byte in the file, converting them to decimal numbers and outputting them as text, 17 to a line. You could easily do that using a BufferedInputStream like this:

        int b = bis.read();  // read a byte
        bis.skip(3);         // skip 3 bytes.
    

    (with a bit of error checking ....). If you use a BufferedInputStream like this, most of the read and skip calls will operate on data that has already been buffered, and the number of syscalls will reduce to 1 for every N bytes, where N is the buffer size.

    UPDATE - my guess was wrong. You are actually reading alternate words, so ...

        bis.read(singleValue);
        bis.skip(4);
    

    Every 100000 offsets I have to jump 200000 and then do it again till the end of the file.

    Use bis.skip(800000) to do that. It should do a big skip by moving the file position without actually reading any data. One syscall at most. (For a FileInputStream, at least.)


    You can also speed up the output side by a roughly equivalent amount by wrapping the DataOutputStream around a BufferedOutputStream.

    But System.out is already buffered.