Как правильно прочитать байт Java-файл - PullRequest
0 голосов
/ 27 сентября 2019

Я хочу читать быстрые построчно большие CSV-файлы (около ~ 1 ГБ) в UTF-8.Я создал класс для него, но он не работает должным образом.UTF-8 декодирует кириллический символ из 2 байтов.Я использую байтовый буфер для его чтения, например, он имеет длину 10 байтов.Таким образом, если символ состоит из 10 и 11 байтов в файле, он не будет нормально декодироваться: (

Tipical error

public class MyReader extends InputStream {

  private FileChannel channel;
  private ByteBuffer buffer = ByteBuffer.allocate(10);
  private int buffSize = 0;
  private int position = 0;
  private boolean EOF = false;
  private CharBuffer charBuffer;

  private MyReader() {}

  static MyReader getFromFile(final String path) throws IOException {
    MyReader myReader = new MyReader();
    myReader.channel = FileChannel.open(Path.of(path),
        StandardOpenOption.READ);
    myReader.initNewBuffer();
    return myReader;
  }
  private void initNewBuffer() {
    try {
      buffSize = channel.read(buffer);
      buffer.position(0);
      charBuffer = Charset.forName("UTF-8").decode(buffer);
      buffer.position(0);
    } catch (IOException e) {
      throw new RuntimeException("Error reading file: {}", e);
    }
  }
  @Override
  public int read() throws IOException {
    if (EOF) {
      return -1;
    }
    if (position < charBuffer.length()) {
      return charBuffer.array()[position++];
    } else {
      initNewBuffer();
      if (buffSize < 1) {
        EOF = true;
      } else {
        position = 0;
      }
      return read();
    }
  }
  public char[] readLine() throws IOException {
    int readResult = 0;
    int startPos = position;
    while (readResult != -1) {
      readResult = read();
    }
    return Arrays.copyOfRange(charBuffer.array(), startPos, position);
  }
}

Ответы [ 2 ]

1 голос
/ 27 сентября 2019

Плохое решение, но оно работает)

private void initNewBuffer() {
    try {
      buffSize = channel.read(buffer);
      buffer.position(0);
      charBuffer = StandardCharsets.UTF_8.decode(buffer);
      if (buffSize > 0) {
        byte edgeByte = buffer.array()[buffSize - 1];
        if (edgeByte == (byte) 0xd0 ||
            edgeByte == (byte) 0xd1 ||
            edgeByte == (byte) 0xc2 ||
            edgeByte == (byte) 0xd2 ||
            edgeByte == (byte) 0xd3
        ) {
          channel.position(channel.position() - 1);
          charBuffer.limit(charBuffer.limit()-1);
        }
      }
      buffer.position(0);
    } catch (IOException e) {
      throw new RuntimeException("Error reading file: {}", e);
    }
  }
0 голосов
/ 27 сентября 2019

Первое: усиление сомнительно.

Класс Files имеет много хороших и довольно быстрых методов производства.

Байты с старшим битом 1 (<0) являются частью UTF-8 многобайтовая последовательность.С старшими битами 10 они являются байтами продолжения.Последовательности могут быть до 6 байтов в настоящее время (я полагаю). </p>

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

Логика программирования, которую я с удовольствием оставлю вам.

...