Как я могу прочитать определенное количество байтов из объекта FileInputStream, используя буферы

У меня есть ряд объектов, хранящихся в файле, как показано ниже:

sizeOfFile1 || file1 || sizeOfFile2 || file2 ...

Размер файлов - это сериализованные длинные объекты, а файлы - это просто необработанные байты файлов.

Я пытаюсь извлечь файлы из входного файла. Ниже мой код:

FileInputStream fileInputStream = new FileInputStream("C:\Test.tst");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
while (fileInputStream.available() > 0)
{
  long size = (long) objectInputStream.readObject();
  FileOutputStream fileOutputStream = new FileOutputStream("C:\" + size + ".tst");
  BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
  int chunkSize = 256;
  final byte[] temp = new byte[chunkSize];
  int finalChunkSize = (int) (size % chunkSize);
  final byte[] finalTemp = new byte[finalChunkSize];
  while(fileInputStream.available() > 0 && size > 0)
  {
    if (fileInputStream.available() > finalChunkSize)
    {
      int i = fileInputStream.read(temp);
      secBufferedOutputStream.write(temp, 0, i);
      size = size - i;
    }
    else
    {
      int i = fileInputStream.read(finalTemp);
      secBufferedOutputStream.write(finalTemp, 0, i);
      size = 0;
    }
  }
  bufferedOutputStream.close();
}
fileOutputStream.close();

Мой код не выполняется после того, как он прочитал первый sizeOfFile; он просто читает остальную часть входного файла в один файл, когда хранится несколько файлов.

Кто-нибудь может увидеть проблему здесь?

С уважением.

4 ответа

Оберните это в DataInputStream и использовать readFully(byte[]),

Но я ставлю под сомнение дизайн. Сериализация и произвольный доступ не смешиваются. Похоже, вы должны использовать базу данных.

NB вы злоупотребляете available(), Смотрите страницу метода Javadoc. Никогда не правильно использовать его как счетчик общего количества байтов в потоке. Есть несколько правильных способов использования available() и это не один из них.

Вы могли бы попробовать NIO вместо...

FileChannel roChannel = new RandomAccessFile(file, "r").getChannel();
ByteBuffer roBuf = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, SIZE);

Это читает только байты размера из файла.

В

Это использует DataInput для чтения длинных. В этом конкретном случае я не использую readFully(), поскольку сегмент может быть слишком длинным, чтобы держать его в памяти:

DataInputStream in = new DataInputStream(FileInputStream());
byte[] buf = new byte[64*1024];
while(true) {
  OutputStream out = ...;
  long size;
  try { size = in.readLong(); } catch (EOFException e) { break; } 
  while(size > 0) {
    int len = (size > buf.length)?buf.length:size;
    len = in.read(buf, 0, len);
    out.write(buf, 0, len);
    size-=len;
  }
  out.close();
}

Избавьте себя от многих проблем, выполнив одно из следующих действий:

  1. Переключитесь на использование Avro, поверьте мне, вы бы с ума сошли. Это легко учиться, и будет приспосабливать изменения схемы. Использование ObjectXXXStream - одна из худших идей, когда вы изменяете свою схему, ваши старые файлы становятся мусором.
  2. или используйте Thrift
  3. или используйте Hibernate (но это, вероятно, не лучший вариант, hibernate занимает много времени для изучения и требует много настроек)

Если вы действительно отказываетесь переключаться на avro, я рекомендую прочитать в классе Apache IOUtils. У него есть метод для копирования из одного входного потока в другой, что избавляет вас от головной боли. К сожалению, то, что вы хотите сделать, немного сложнее, вы хотите, чтобы размер каждого файла начинался с префикса. Вы можете использовать комбинацию объектов SequenceInputStream для этого.

Есть также GzipOutputStream и ZipOutputStream, но я думаю, что для них также нужны некоторые другие jar-файлы, добавленные в ваш classpath.

Я не собираюсь писать пример, потому что я честно думаю, что вы должны просто изучить avro или thrift и использовать это.

Другие вопросы по тегам