如何正确读取字节java文件

如何正确读取字节java文件,java,nio,Java,Nio,我想在UTF-8中快速逐行读取大型csv文件(约1gb)。我已经为它创建了一个类,但它不能正常工作。UTF-8从2个字节解码西里尔字母符号。我使用字节缓冲区来读取它,例如,它有10个字节的长度。因此,如果文件中的符号由10字节和11字节组成,则无法正常解码:( 公共类MyReader扩展InputStream{ 专用文件通道; 私有ByteBuffer缓冲区=ByteBuffer.allocate(10); 私有int buffSize=0; 私有int位置=0; 私有布尔EOF=false;

我想在UTF-8中快速逐行读取大型csv文件(约1gb)。我已经为它创建了一个类,但它不能正常工作。UTF-8从2个字节解码西里尔字母符号。我使用字节缓冲区来读取它,例如,它有10个字节的长度。因此,如果文件中的符号由10字节和11字节组成,则无法正常解码:(

公共类MyReader扩展InputStream{
专用文件通道;
私有ByteBuffer缓冲区=ByteBuffer.allocate(10);
私有int buffSize=0;
私有int位置=0;
私有布尔EOF=false;
专用字符缓冲区字符缓冲区;
私有MyReader(){}
静态MyReader getFromFile(最终字符串路径)引发IOException{
MyReader MyReader=新建MyReader();
myReader.channel=FileChannel.open(Path.of(Path)),
标准OpenOption.READ);
myReader.initNewBuffer();
返回myReader;
}
私有void initNewBuffer(){
试一试{
buffSize=通道读取(缓冲区);
缓冲器位置(0);
charBuffer=Charset.forName(“UTF-8”)。解码(buffer);
缓冲器位置(0);
}捕获(IOE异常){
抛出新的运行时异常(“读取文件时出错:{}”,e);
}
}
@凌驾
public int read()引发IOException{
如果(EOF){
返回-1;
}
if(位置
坏的解决方案,但它可以工作)


第一:收益是值得怀疑的

Files
类有许多非常好的快速生成方法

高位为1(<0)的字节是UTF-8多字节序列的一部分。 对于高位10,它们是连续字节。 现在的序列可能多达6字节(我相信)

所以下一个缓冲区以一些延续字节开始,它们属于前一个缓冲区


我很乐意将编程逻辑留给您。

为什么您要创建自己的类,而不是使用
InputStreamReader
?我想要自己的实现:)现在您似乎有点力不从心。您正在混合流(IO)和通道(NIO),缓冲区处理错误(使用
position()
而不是
flip()
)等等。也许读一些教程?它太宽泛了,无法解释代码中所有的错误。谢谢。您可以共享教程的链接吗?
Charset
decode
方法用于处理完整的输入。您应该使用
CharsetDecoder
,如中所述。将其与替代调用
位置(0)
相结合,可以免费正确处理悬空的多字节字符。
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);
  }
}
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);
    }
  }