簡體   English   中英

如何在JAVA循環中從文件中讀取固定數量的字節?

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

我必須閱讀一個文件,其中在每次迭代中我必須從文件中讀取 8 個字節。 例如,在第一次迭代中,我將讀取前 8 個字節,然后在第二次迭代中讀取下 8 個字節,依此類推。 這如何在 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;
}

我發現了這一點,但我認為這段代碼所做的完全是讀取文件並制作文件數據的字節數組。 但是我只需要准備一次迭代中需要的字節數。

使用DataInput進行此類處理:

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

我使用了RandomAccessFileDataInputStream是一種常見的替代方法。

您可以輕松地根據需要調整代碼:添加偏移量和計數,然后調用skip初始N個字節,如下所示 -

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

將代碼分成小塊,例如,要讀取一個字節塊(在您的情況下為 8 個字節),您需要了解 3 件事:

  1. 在哪個文件中讀取
  2. 從哪里開始閱讀
  3. 讀取多少字節/塊大小

把這看作一個步驟會讓你得到一個返回一個 byte[] 數組的方法,將上述 3 個點作為參數,例如:

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

下一步是打開文件並為文件中的每個字節塊調用此方法。 您從零位置開始讀取文件,調用該方法一次,對結果執行某些操作,然后在位置 = (previousPos) + blockSize 處重新調用它。 這段代碼可以放在另一個方法中,例如:

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

這將返回一個 byte[][] 數組,其中第一個索引為 byteBlockNumber(前 8 個字節,第二個 8 個字節,第三個 8 個字節,...)和每個單獨字節的第二個索引:

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

在上面的示例代碼中,byte[][] 數組初始化如下:

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

因此,塊數是文件中的總字節數除以字節塊的大小(在您的示例中為 8)。 假設文件有 9 個字節,塊大小為 8,這將導致 1,sth 並四舍五入為 1,所以最后一個字節將沒有空間,這就是為什么 Math.ceil() 用於四舍五入到任何師給。 Math.ceil(9 / 8) -> 2,這 2 個足以容納第一個 8 個字節的塊,以及第二個塊中的最后一個字節。

您可以使用以下代碼讀取具有起始偏移量和大小的內存塊:

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

甚至更好的性能,使用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);
    }
}

可以使用其array()方法從ByteBuffer訪問字節數組。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM