8

I have to read a fie where in every iteration I have to read 8 bytes form the file. For example in first iteration I'll read first 8 bytes and in second iteration next 8 and so on. How can this be done in Java?

public static byte[] toByteArray(File file) {
    long length = file.length();
    byte[] array = new byte[length];
    InputStream in = new FileInputStream(file);
    long offset = 0;
    while (offset < length) {
        int count = in.read(array, offset, (length - offset));
        offset += length;
    }
    in.close();
    return array;
}

I have found this, but I think what this code is doing is completely reading a file and making a byte array of file data. But I need to ready only that many bytes that I need in one iteration.

1
  • Why not just use Files.readAllBytes? Commented Nov 18, 2019 at 2:05

5 Answers 5

3

Use a DataInput for this type of processing:

  private void process(File file) throws IOException {
    try (RandomAccessFile data = new RandomAccessFile(file, "r")) {
      byte[] eight = new byte[8];
      for (long i = 0, len = data.length() / 8; i < len; i++) {
        data.readFully(eight);
        // do something with the 8 bytes
      }
    }
  }

I've use a RandomAccessFile but a DataInputStream is a common alternative.

Sign up to request clarification or add additional context in comments.

Comments

2

You can easily adapt the code to your needs: add an offset and the count, and call skip to get past the initial N bytes, like this -

public static byte[] toByteArray(File file, long start, long count) {
      long length = file.length();
      if (start >= length) return new byte[0];
      count = Math.min(count, length - start);
      byte[] array = new byte[count];
      InputStream in = new FileInputStream(file);
      in.skip(start);
      long offset = 0;
      while (offset < count) {
          int tmp = in.read(array, offset, (length - offset));
          offset += tmp;
      }
      in.close();
      return array;
}

2 Comments

Thank you. And to convert that byte array to string with: String str=new String(array);
Converting bytes to string without knowing the encoding would be an extremely bad idea.
1
public static void main(String[] args) {
   File dir = new File("C:\\");
   int fixedNumber = n;
   if (dir.isDirectory()) {
      for (String file : dir.list()) {
         int sum = sumByteArray(new File(dir.getAbsoluteFile() + "\\" + file),fixedNumber);
      }
   }
}

private static int sumByteArray(File file, int fixedNumber) {
   FileInputStream fileInputStream = null;
   byte[] bFile = new byte[fixedNumber];
   int sum = 0;
   try {
      fileInputStream = new FileInputStream(file);
      fileInputStream.read(bFile);
      fileInputStream.close();
      for (Byte b : bFile) {
         sum += (int) b;
      }
   } 
   catch (Exception e) {
      e.printStackTrace();
   }
   return sum;
}

1 Comment

can you explain your answer rather than just putting code snippets
0

Divide the code into small chunks, for example, to read a byte block (in your case 8 bytes) you need to know 3 things:

  1. In which file to read
  2. Where to start reading
  3. How many bytes to read / size of the block

Seeing this as one step would leave you with a method that returns a byte[] array, taking the above 3 points as parameters, for example:

private byte[] readByteBlock(InputStream in, int offset, int noBytes) throws IOException {
    byte[] result = new byte[noBytes];
    in.read(result, offset, noBytes);
    return result;
}

The next step would be, to open the file and call this method for every byte block in the file. You start reading the file at position zero, call that method once, do something with the result, and call it all over at position = (previousPos) + blockSize. This chunk of code could be put in another method, for example:

public byte[][] toByteArray(File file, int byteBlockSize) throws IOException {

    InputStream in = new FileInputStream(file);
    long noOfBlocks = (long) Math.ceil((double)file.length() / (double)byteBlockSize);
    byte[][] result = new byte[(int)noOfBlocks][byteBlockSize];
    int offset = 0;
    for(int i = 0; i < result.length; i++) {
        result[i] = readByteBlock(in, offset, byteBlockSize);
    }
    return result;
}

This returns a byte[][] array with the first index as the byteBlockNumber (first 8 bytes, second 8 bytes, third 8 bytes, ...) and the second index each individual byte:

byte[0][0]: the first byte block's first byte
byte[0][7]: the first byte block's second byte
byte[1][2]: the second byte block, third byte
etc..

In the example code above the byte[][] array is initialized like:

long noOfBlocks = (long) Math.ceil((double)file.length() / (double)byteBlockSize);
byte[][] result = new byte[noOfBlocks][byteBlockSize];

So the number of blocks is the number of overall bytes in the file divided by the size of the byte blocks (8 in your example). Assuming the file has 9 bytes and the block size is 8, this would result 1,sth and rounded to 1, so you won't have space for the last byte, that's why Math.ceil() is used to round up to whatever the division gives. Math.ceil(9 / 8) -> 2, and those 2 are enough to hold the first block of 8 bytes, and the last byte in a second block.

2 Comments

It is a defect to fail to check the return value of the read. You cannot assume it always fills the buffer. See the doc: An attempt is made to read as many as len bytes, but a smaller number may be read.
If you use public int read(byte[] b,int off,int len) on less then 'len' bytes available, the elements in b after the last byte read just stay unaffected (0). Since the overall length is known, the last byte to be read can be calculated and further bytes ignored. The code was not intended for copy & paste as an final perfect solution ;) So, yes, if, if you have a file with 9 bytes, read blocks of 8, the second byte[] will have 8 elements with the last 7 not representing the file content.
0

You can use the following code to read a memory chunk with a start offset and size:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileReadingUtilities
{
    public static byte[] readBytes(String file, int start, int size) throws IOException
    {
        Path filePath = Paths.get(file);
        long fileSize = Files.size(filePath);

        if(start < 0)
        {
            throw new IllegalArgumentException("The start may not be negative!");
        }

        if(size < 0)
        {
            throw new IllegalArgumentException("The size may not be negative!");
        }

        if (start + size > fileSize)
        {
            throw new IllegalArgumentException("Interval exceeds file size!");
        }

        byte[] readBytes = new byte[size];

        try (InputStream inputStream = new FileInputStream(filePath.toFile()))
        {
            long actuallySkipped = inputStream.skip(start);

            if (start != actuallySkipped)
            {
                throw new IllegalStateException("Error while skipping bytes ahead!");
            }

            int bytesReadCount = inputStream.read(readBytes, 0, size);
            if (bytesReadCount != size)
            {
                throw new IllegalStateException("Not enough bytes have been read!");
            }
        }

        return readBytes;
    }
}

Even better performance-wise, use a MappedByteBuffer:

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileReadingUtilities
{
    public static ByteBuffer getByteBuffer(String filePath, int start, int size) throws IOException
    {
        File binaryFile = new File(filePath);
        FileChannel binaryFileChannel = new RandomAccessFile(binaryFile, "r").getChannel();

        return binaryFileChannel.map(FileChannel.MapMode.READ_ONLY, start, size);
    }
}

The byte array can be accessed from the ByteBuffer using its array() method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.