Java: альтернатива BufferedReader

У меня проблемы с BufferedWriter/BufferedReader,

По сути, всякий раз, когда я пытаюсь прочитать файл с BufferedReader.readLine() он читает все до символа новой строки (т.е. символ новой строки опускается).

Например:

String temp;
File f = new File(path.toURI());
BufferedReader reader = new BufferedReader(new FileReader(f));

while ((temp = reader.readLine()) != null) {
    //Work with temp
}

Я знаю о существовании BufferedReader#newLine(), но похоже, что он не получает точно новую строку (разделитель?), которая ранее была опущена.

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

abcd\n
efgh\r\n
ijkl\r

Он вернется:

abcd\n
efgh\n
ijkl\n

Я спрашиваю, есть ли класс, который может читать символы, не пропуская их как BufferedInputStream, сохраняя при этом способность читать строки как BufferedReader#readLine()

3 ответа

\n это linux/unix окончание строки \r\n является windows конец строки.

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

Мое предложение будет, если вы когда-нибудь сталкивались с таким файлом, просто переформатируйте его, чтобы использовать \n или же \r\n (в зависимости от вашей ОС не то, что это имеет значение в настоящее время). это делает вашу жизнь проще, так что жизнь следующего человека, который будет использовать его дальше.

В качестве альтернативы (пожалуйста, не используйте это:/) вы можете переопределить BufferReader.readLine(Boolean b) к этому:

String readLine(boolean ignoreLF) throws IOException {
     StringBuffer s = null;
     int startChar;

     synchronized (lock) {
         ensureOpen();
         boolean omitLF = ignoreLF || skipLF;

     bufferLoop:
         for (;;) {

             if (nextChar >= nChars)
                 fill();
             if (nextChar >= nChars) { /* EOF */
                 if (s != null && s.length() > 0){
                   if(skipLF=='\r'){
                     return s.toString() + "\r\n";
                   }else{
                     return s.toString() + "\n";
                   }
                 }
                 else
                     return null;
             }
             boolean eol = false;
             char c = 0;
             int i;

             /* Skip a leftover '\n', if necessary */
             if (omitLF && (cb[nextChar] == '\n'))
                 nextChar++;
             skipLF = false;
             omitLF = false;

         charLoop:
             for (i = nextChar; i < nChars; i++) {
                 c = cb[i];
                 if ((c == '\n') || (c == '\r')) {
                     eol = true;
                     break charLoop;
                 }
             }

             startChar = nextChar;
             nextChar = i;

             if (eol) {
                 String str;
                 if (s == null) {
                     str = new String(cb, startChar, i - startChar);
                 } else {
                     s.append(cb, startChar, i - startChar);
                     str = s.toString();
                 }
                 nextChar++;
                 if (c == '\r') {
                     skipLF = true;
                 }
                 if(skipLF=='\r'){
                   return str + "\r\n";
                 }else{
                   return str + "\n";
                 }
             }

             if (s == null)
                 s = new StringBuffer(defaultExpectedLineLength);
             s.append(cb, startChar, i - startChar);
         }
     }
 }

КОД ИСТОЧНИКА отредактирован от:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/io/BufferedReader.java#BufferedReader.readLine%28boolean%29

Одним из решений может быть расширение BufferedReader и переопределить readLine() метод (как это уже было предложено в других ответах).

Возьмите этот упрощенный пример только как PoC.

class MyReader extends BufferedReader {
    int size = 8192;

    public MyReader(Reader in) {
        super(in);
    }

    public MyReader(Reader in, int sz) {
        super(in, sz);
        this.size = sz;
    }

    @Override
    public String readLine() throws IOException {
        StringBuilder sb = new StringBuilder(this.size);
        for (int read = super.read(); read >= 0 && read != '\n'; read = super.read()) {
            sb.append((char) read);
        }
        // in case you want also to preserve the line feed character
        // sb.append('\n');
        return sb.toString();
    }
}

,

public class MyReaderDemo{

    public static void main(String[] args) throws FileNotFoundException, IOException {
        String text = "abcd\n"
                + "efgh\r\n"
                + "ijkl\r";

        ByteArrayInputStream bis = new ByteArrayInputStream(
                text.getBytes(StandardCharsets.ISO_8859_1)
        );

        // BufferedReader in = new BufferedReader(new InputStreamReader(bis));
        BufferedReader in = new MyReader(new InputStreamReader(bis));

        System.out.println(Arrays.toString(in.readLine().getBytes()));
        System.out.println(Arrays.toString(in.readLine().getBytes()));
        System.out.println(Arrays.toString(in.readLine().getBytes()));

    }
}

вывод с BufferedReader

[97, 98, 99, 100]
[101, 102, 103, 104]
[105, 106, 107, 108]

вывод с MyReader

[97, 98, 99, 100]
[101, 102, 103, 104, 13]
[105, 106, 107, 108, 13]

Это, вероятно, не составит большого труда продлить BufferedReader включить \n или же \r в ответ от readLine(), На самом деле, пакет защищен readLine(boolean ignoreLF) Функция - это все, что вам нужно переопределить:

Читает строку текста. Строка считается завершенной любым из перевода строки ('\n'), разделителя возврата каретки ('\r') в результате или возврата каретки, за которым сразу следует перевод строки.

Параметры: ignoreLF Если true, следующий '\ n' будет пропущен

Возвращает: A String содержащий содержимое строки, не включая символы окончания строки, или ноль, если достигнут конец потока

Броски: IOException Если происходит ошибка ввода-вывода

Смотрите также: LineNumberReader.readLine()

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