как создать средство чтения из набора строк, не добавляя их сначала в StringBuilder?

Представьте, что у меня есть несколько Stings, содержащих большое количество данных. Я должен передать их объединение методу в библиотеке, которую использую. Я могу использовать для этого либо String, либо Reader.

  1. О добавлении их и передаче строки не может быть и речи, так как я могу столкнуться с OOM. Больше нет возможности изменить -Xmx.
  2. Итак, есть ли способ создать средство чтения на основе ВСЕХ моих строк без создания одной строки, а затем создания StringReader? Таким образом, я мог избежать OOM

ps: я уже задал начальную емкость StringBuilder для своего первого варианта, но этого мало, поэтому ищу способ реализовать 2.


person Persimmonium    schedule 19.12.2011    source источник


Ответы (4)


Вы можете реализовать собственный считыватель, данные которого извлекаются из списка ваших строк. Ваш конкретный подкласс должен будет реализовать только два метода: read(char[], int, int) и close(). Когда ваш читатель закончит использовать одну строку, переходите к следующей.

person Andy Thomas    schedule 19.12.2011
comment
спасибо, я как раз смотрел исходный код StringReader, чтобы сделать именно это. Я надеюсь, что эта вещь уже реализована... было бы легко испортить реализацию. - person Persimmonium; 19.12.2011
comment
Поскольку ваш ответ в основном такой же, как мой, я должен дать вам голос. :-) - person user949300; 19.12.2011
comment
Я реализовал нечто подобное для ReadableByteChannel, полученного из конкатенации. По сути, вы сохраняете итератор для строк как член вашего подкласса Reader и индекс внутри текущей строки. Реализуйте read() для чтения в цикле, пробуя оставшиеся символы и строки до тех пор, пока не будет завершен запрошенный объем чтения или у вас не закончатся строки. Удачи! - person Andy Thomas; 19.12.2011

Я не знаю встроенного способа или стороннего варианта, но не должно быть так сложно написать свой собственный ридер, взяв список (или массив) строк. Согласно читателю javadocs:

«Единственные методы, которые должен реализовать подкласс, это read(char[], int, int) и close()»

И close() должно быть легко. Таким образом, вам действительно нужно реализовать только один метод, read(char[], int, int). Сохраняйте индексы того, какую строку вы читаете, и где вы находитесь в строке. Остальное оставлено в качестве упражнения для читателя. :-) И вы можете захотеть реализовать read() для скорости.

person user949300    schedule 19.12.2011

Вы можете реализовать свою собственную версию считывателя, которая использует базу массивов строк, а затем выполняет цикл при вызове метода чтения.

Вы должны иметь возможность создать подкласс Reader, реализующий собственные версии методов read(char, int, int) и close(). Метод read(..), вероятно, может выглядеть примерно так, как показано ниже.

import java.io.IOException;
import java.util.Collection;
import java.io.*;

public class StringArrayReader extends Reader {
    private String[] strings;
    private int iString = 0, iCharInCurrentString = 0;

    public StringArrayReader(String[]strings) {
        this.strings = strings;
    }

    public StringArrayReader(Collection<String> strings) {
        this(strings.toArray(new String[strings.size()]));
    }



    @Override
    public int read(char[] buf, int off, int len) { 
        int iCurrentChar=0;
        while (iCurrentChar < len) {
            if (iCharInCurrentString < strings[iString].length()) {
                buf[iCurrentChar+off] = strings[iString].charAt(iCharInCurrentString);
            } else if (iString + 1 < strings.length) {
                iString++;
                iCharInCurrentString = 0;
                buf[iCurrentChar+off] = strings[iString].charAt(iCharInCurrentString);
            } else {   // current string is over and no more strings
                break;
            }
            iCurrentChar++;
            iCharInCurrentString++;
        }
        return iCurrentChar>0? iCurrentChar: -1;        
    }

    @Override
    public void close() throws IOException {
    }


    /* Demo */
    public static void main(String[] args) throws IOException {
        String s1 = "abcd";
        String s2 = "efgh";
        Reader r1 = new StringArrayReader(new String[]{s1,s2});
        int data = r1.read();
        while(data != -1){
            char dataChar = (char) data;
            System.out.println(dataChar);
            data = r1.read();
        }   
    }
}
person Steve Bennett    schedule 19.12.2011

Вы можете создать массив строк и передать его. Это займет гораздо меньше памяти, чем копирование всех строк в одну суперстроку.

Вы также можете увеличить объем памяти, используемой JVM, с помощью параметра -Xmx (например, -Xmx2g, чтобы разрешить до 2 ГБ памяти).

person James McLeod    schedule 19.12.2011
comment
-Xmx уже используется, мне нужно такое решение, как Reader, не могли бы вы уточнить массив строк? - person Persimmonium; 19.12.2011