Чтение и запись файла в количестве фрагментов байтового буфера меньшей длины

Я пытаюсь прочитать файл в ByteBuffer фрагментах фиксированной длины, а затем сохранить его в списке ByteBuffer, а затем после некоторых операций прочитать эти ByteBuffer фрагменты в последовательном порядке, чтобы восстановить файл. Проблема в том, что при записи выходного файла позиция канала не увеличивается. Я не хочу использовать байтовые массивы, так как они имеют фиксированную длину и реконструкция файлов не работает должным образом. Поэтому я хотел бы знать, как увеличить размер позиции канала записи файла или каким-либо другим способом выполнить эту операцию. Пример кода приветствуется. Вот мои фрагменты кода,

file = new File(fileName);  // hello.txt - 20 MB size
fis = new FileInputStream(file);
inChannel = fis.getChannel();
double maxChunkSequenceNoFloat = ((int)inChannel.size()) / chunkSize;
int maxChunkSequenceNo = 1;
if(maxChunkSequenceNoFloat%10 > 0) {
    maxChunkSequenceNo = ((int)maxChunkSequenceNoFloat)+1;
} else if(maxChunkSequenceNoFloat%10 < 0) {
    maxChunkSequenceNo = 1;
} else {
    maxChunkSequenceNo = (int)maxChunkSequenceNoFloat;
}
maxChunkSequenceNo = (maxChunkSequenceNo == 0) ? 1 : maxChunkSequenceNo;            
ByteBuffer buffer = ByteBuffer.allocate(chunkSize);
buffer.clear();

while(inChannel.read(buffer) > 0) {
    buffer.flip();
    bufferList.add(buffer);
    buffer.clear();
    chunkSequenceNo++;
}
maxChunkSequenceNo = chunkSequenceNo;

// write
File file1 = new File("hello2.txt") ; 
buffer.clear();
FileOutputStream fos = new FileOutputStream(file1);
FileChannel outChannel = fos.getChannel();
chunkSequenceNo = 1;
for(ByteBuffer test : bufferList) {
    writeByteCount += outChannel.write(test);
    //outChannel.position() += writeByteCount;'
    System.out.println("main - channelPosition: "+outChannel.position()
                        +" tempBuffer.Position: "+test.position()
                        +" limit: "+test.limit()
                        +" remaining: "+test.remaining()
                        +" capacity: "+test.capacity());              
}
BufferedReader br = new BufferedReader(new FileReader(file1));
String line = null;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}
outChannel.close();
fos.close();

Позиция байтового буфера правильная, но позиция outChannel остается равной 1048, что соответствует размеру фрагмента.


person andi99    schedule 24.07.2017    source источник
comment
Будьте проще и (частично) используйте байтовые массивы. FileReader использует кодировку платформы по умолчанию.   -  person Joop Eggen    schedule 25.07.2017
comment
Дело не только в моем коде, но и в классе, обрабатывающем мои данные, требуются ByteBuffers, поэтому, как я ясно сказал в вопросе, прямое использование массива байтов не может быть и речи.   -  person andi99    schedule 25.07.2017
comment
Вы используете только один буфер, поэтому ваш код вообще не соответствует вашему описанию.   -  person user207421    schedule 25.07.2017


Ответы (1)


Следующее действительно будет поддерживать список байтовых буферов по запросу.

String fileName = "hello.txt";
final int chunkSize = 256;
List<ByteBuffer> bufferList = new ArrayList<>();
Path path = Paths.get(fileName);
try (SeekableByteChannel inChannel = Files.newByteChannel(path,
        EnumSet.of(StandardOpenOption.READ))) {
    long size = inChannel.size();
    while (size > 0) {
        ByteBuffer buffer = ByteBuffer.allocate(chunkSize);

        int nread = inChannel.read(buffer);
        if (nread <= 0) {
            break;
        }
        buffer.flip();
        bufferList.add(buffer);
        size -= nread;
    }
}

// write
Path file1 = Paths.get("hello2.txt") ;
try (SeekableByteChannel outChannel = Files.newByteChannel(file1,
        EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))) {
    for (ByteBuffer buffer : bufferList) {
        int nwritten = outChannel.write(buffer);
    }
}

Try-with-resources позаботится о закрытии каналов/файлов. Файлы (служебные функции) и Путь (более общий, чем Файл) полезны.

Нужно добавить новые экземпляры ByteBuffer при наличии ограничения chunkSize. (Таким образом, можно было бы также добавить базовые массивы байтов.)

Лучше не использовать плавающую точку, даже здесь.

person Joop Eggen    schedule 24.07.2017
comment
Спасибо, что работает. Я думаю, что байтбуфер нельзя использовать повторно, его нужно создать снова. - person andi99; 26.07.2017
comment
@andi99 andi99 Используйте перемотку и очистку буфера, чтобы повторно использовать буфер. - person AndroidDev; 23.05.2021