简体   繁体   中英

How to Read fixed number of bytes from a file in a loop in JAVA?

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.

Use aDataInput 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.

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;
}

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.

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.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM