2015-07-31 4 views
1

Я пытался понять, как работает Java ByteBuffer. Моя цель - написать строку до ByteBuffer и прочитать его обратно. Я хочу понять, как ByteBuffer свойства, подобные Limit, Capacity, Remaining, Position, пострадают из-за операций чтения/записи.Понимание java ByteBuffer

Ниже приведена моя тестовая программа (для краткости удалены операторы импорта).

public class TestBuffer { 

private ByteBuffer bytes; 
private String testStr = "Stackoverflow is a great place to discuss tech stuff!"; 

public TestBuffer() { 
    bytes = ByteBuffer.allocate(1000); 
    System.out.println("init: " + printBuffer()); 
} 

public static void main(String a[]) { 
    TestBuffer buf = new TestBuffer(); 
    try { 
     buf.writeBuffer(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    buf.readBuffer(); 
} 

// write testStr to buffer 
private void writeBuffer() throws IOException { 
    byte[] b = testStr.getBytes(); 
    BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(b)); 
    in.read(bytes.array()); 
    in.close(); 
    System.out.println("write: " + printBuffer()); 
} 

// read buffer data back to byte array and print 
private void readBuffer() { 
    bytes.flip(); 
    byte[] b = new byte[bytes.position()]; 
    bytes.position(0); 
    bytes.get(b); 
    System.out.println("data read: " + new String(b)); 
    System.out.println("read: " + printBuffer()); 
} 

public String printBuffer() { 
    return "ByteBuffer [limit=" + bytes.limit() + ", capacity=" + bytes.capacity() + ", position=" 
      + bytes.position() + ", remaining=" + bytes.remaining() + "]"; 
} 

}

Выход

init: ByteBuffer [limit=1000, capacity=1000, position=0, remaining=1000] 
write: ByteBuffer [limit=1000, capacity=1000, position=0, remaining=1000] 
data read: 
read: ByteBuffer [limit=0, capacity=1000, position=0, remaining=0] 

Как вы можете видеть, что нет никаких данных после вызова readBuffer() и никаких изменений в стоимости, если различные поля после записи и чтения операций.

Update

Ниже рабочая часть кода из Android Screen Library который я первоначально пытается понять

// retrieve the screenshot 
      // (this method - via ByteBuffer - seems to be the fastest) 
      ByteBuffer bytes = ByteBuffer.allocate (ss.width * ss.height * ss.bpp/8); 
      is = new BufferedInputStream(is); // buffering is very important apparently 
      is.read(bytes.array());    // reading all at once for speed 
      bytes.position(0);     // reset position to the beginning of ByteBuffer 

Пожалуйста, помогите мне понять это.

Благодаря


+0

Вы никогда не должны игнорировать возвращаемое значение 'in.read (byte [])'. Вы не можете получить все байты, о которых вы просите. Указанный буфер байтового массива не может быть полностью заполнен (так как вы можете достичь конца потока до этого, или поток может иметь другие причины, чтобы дать частичное сообщение в ответ). –

ответ

1

Вы ничего в методе writeBuffer() не сочинительство.

Вы можете использовать что-то наподобие bytes.put(b).

+0

Я думаю, строка 'in.read (bytes.array());' должна читать данные ByteBuffer – iuq

+0

@iuq Нет, что не считывает данные в 'ByteBuffer'. – Jesper

3

Ваш буфер не заполняется. bytes.array() просто извлекает массив байтовых байт. Если вы что-то пишете, то поля ByteBuffer - за исключением самого массива, конечно, не затронуты. Таким образом, позиция остается равной нулю.

Что вы делаете в in.read(bytes.array()), идентично byte[] tmp = bytes.array(), а затем in.read(tmp). Изменения в переменной tmp не могут быть отражены в экземпляре bytes. Массив базы изменяется, что может означать, что содержимое ByteBuffer также изменяется. Но смещения в массив байтовых байт - в том числе позиция и предел - нет.

Вы должны заполнить только ByteBuffer с использованием любых методов put (которые не принимают индекс), таких как put(byte[]).


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

import java.nio.ByteBuffer; 
import java.nio.CharBuffer; 
import java.nio.charset.CharsetEncoder; 
import java.nio.charset.CoderResult; 
import java.nio.charset.StandardCharsets; 

public class TestBuffer { 

    private static final String testStr = "Stackoverflow is a great place to discuss tech stuff!"; 
    private static final boolean END_OF_INPUT = true; 

    private ByteBuffer bytes = ByteBuffer.allocate(1000); 

    public TestBuffer() { 

     System.out.println("init : " + bytes.toString()); 
    } 

    public static void main(String a[]) { 
     TestBuffer buf = new TestBuffer(); 
     buf.writeBuffer(); 
     buf.readBuffer(); 
    } 

    // write testStr to buffer 
    private void writeBuffer() { 
     CharBuffer testBuffer = CharBuffer.wrap(testStr); 
     CharsetEncoder utf8Encoder = StandardCharsets.UTF_8.newEncoder(); 
     CoderResult result = utf8Encoder.encode(testBuffer, bytes, END_OF_INPUT); 
     if (result.isError()) { 
      bytes.clear(); 
      throw new IllegalArgumentException("That didn't go right because " + result.toString()); 
     } 
     if (result.isOverflow()) { 
      bytes.clear(); 
      throw new IllegalArgumentException("Well, too little buffer space."); 
     } 
     System.out.println("written: " + bytes.toString()); 
     bytes.flip(); 
    } 

    // read buffer data back to byte array and print 
    private void readBuffer() { 
     byte[] b = new byte[bytes.remaining()]; 
     bytes.get(b); 
     System.out.println("data : " + new String(b, StandardCharsets.UTF_8)); 
     System.out.println("read : " + bytes.toString()); 
     bytes.clear(); 
    } 
} 

Обратите внимание, что буферы и потоки действительно два отдельных пути обработка последовательных данных. Если вы пытаетесь использовать оба из них одновременно, возможно, вы тоже станете умным.

Вы также могли бы решить эту проблему без CharBuffer и ByteBuffer используя byte[] буфер и StringReader обернут ReaderInputStream.


Это Android кусок кода полностью злоупотребляет ByteBuffer. Он должен был просто создать byte[] и обернуть его, установив предел на вместимости. Что бы вы ни делали, не использовать его в качестве примера на ByteBuffer обработка. Это отвратило мои глаза. Подобный код - ошибка, ожидающая появления.

+0

Не следует ли 'in.read (bytes.array()) читать в ByteBuffer? Здесь 'bytes' относится к ByteBuffer. – iuq

+0

Нет, это не так. Он заполняет только массив подстановки, но экземпляр ByteBuffer не получает (не может) получать уведомление об этом. Другими словами, * содержимое * ByteBuffer изменяется, но ни один из смещений, включая позицию и предел, не изменяется. Это то же самое, что 'byte [] tmp = bytes.array()', за которым следует 'in.read (tmp)'. –

+0

Включил это в ответ и привел пример, который полностью переписал метод writeBuffer без потоков. Это дает понять, как вы можете использовать буферы, не требуя буфера того же размера, что и строка. Он не требует потоков, хотя альтернатива будет использовать 'InputStreamReader' вместо' CharBuffer' и 'ByteBuffer'. –

Смежные вопросы