2016-03-19 6 views
2

Я пытаюсь реализовать собственный класс FilterReader. Класс должен преобразовывать то, что он читает (неважно, как). Проблема, с которой я сталкиваюсь, состоит в том, что строка после преобразования длиннее первоначальной, прочитанной в буфере символов, поэтому я получаю ArrayIndexOutOfBoundsException, когда пытаюсь вставить новую строку в буфер.Как реализовать собственный фильтр FilterReader?

Вот метод чтения() мой пользовательский класс FilterReader:

@Override 
public int read(char[] cbuf, int off, int len) throws IOException { 
    int result = in.read(cbuf, off, len); 

    if(result != -1){ 
     String str = new String(cbuf, off, len); 
     str = someStringTranformationMethod(str); 

     //cbuf = new char[str.length()]; 

     str.getChars(0, str.length(), cbuf, 0); 

     result = str.length(); 
    } 

    return result; 
} 

Я думал, что я мог бы решить эту проблему, перераспределяя новый обугленный буфер для cbuf, который является тем, что я пытался на комментировал линии. Однако это, похоже, не работает вообще, потому что тогда мой вывод от читателя является исходной (нетрансформированной) строкой.

У меня есть чувство, что я собираюсь сделать что-то совершенно назад здесь, но нелегко найти хорошие примеры этого материала в Интернете. Все пользовательские фильтры FilterReaders, которые я нашел, только что сделали некоторые основные верхние/нижние символы символов, где длина новой строки такая же, как и исходная.

Как я могу реализовать это с помощью функции преобразования строк, которая приводит к более длинной строке, чем исходная?

+0

Если перед и перед преобразованием существует верхняя граница для коэффициента str.lengths, чтение может соответственно уменьшить длину, поэтому преобразованные символы все равно будут помещаться в буфер. – laune

+0

В качестве (более сложной) альтернативы someStringTranformationMethod должен знать о своей максимальной выходной длине и кэшировать лишние символы, которые будут перенаправлены при следующем вызове. В этом случае трансформатор должен предоставить способ информирования вызывающего абонента о длине ожидающих данных, чтобы был указан вызов без дополнительного считывания. (Это позволяет избежать неограниченного накопления кэшированных данных.) – laune

+0

Основываясь на значении 'len', вы можете узнать длину полученной строки? Если да, не можете ли вы рассчитать количество символов для чтения из исходного потока, который даст вам символ 'len'? – WeaponsGrade

ответ

2

Вы должны сделать свой Stateful реализации и следить за «оставшимися» персонажей:

private String str = ""; 
private int pos = 0; 

public int read(char[] cbuf, int off, int len) throws IOException { 
    if (pos == str.length()) { 
    // No leftovers from a previous call available, need to actully read more 
    int result = in.read(cbuf, off, len); 
    if(result <= 0){ 
     return -1; 
    } 
    str = new String(cbuf, off, result); 
    str = someStringTranformationMethod(str); 
    pos = 0; 
    } 

    // Return as much as we have available, but not more than len 
    int available = Math.min(str.length() - pos, len);  
    str.getChars(pos, pos + available, cbuf, off); 
    pos += available; 
    return available; 
} 

Обратите внимание, что читать() только нужно читать только (at least) один символ, если конец поток не был достигнут. Эта реализация использует это.

+0

Работает как очарование! – BadCash

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