JavaNIO通过ByteBuffer扫描某些字节和带节的字

JavaNIO通过ByteBuffer扫描某些字节和带节的字,java,nio,bytebuffer,filechannel,Java,Nio,Bytebuffer,Filechannel,好的,所以我尝试做一些看起来应该相当简单的事情,但是有了这些新的NIO接口,事情让我非常困惑!这就是我要做的,我需要扫描一个文件作为字节,直到遇到某些字节!当我遇到那个些特定的字节时,我需要抓取那个段数据并对其进行处理,然后继续并再次这样做。我本以为有了所有这些标记、位置和限制,我就能做到这一点,但我似乎无法做到!这是我到目前为止得到的 test.text: this is a line of text a this is line 2b line 3 line 4 line etc.etc.e

好的,所以我尝试做一些看起来应该相当简单的事情,但是有了这些新的NIO接口,事情让我非常困惑!这就是我要做的,我需要扫描一个文件作为字节,直到遇到某些字节!当我遇到那个些特定的字节时,我需要抓取那个段数据并对其进行处理,然后继续并再次这样做。我本以为有了所有这些标记、位置和限制,我就能做到这一点,但我似乎无法做到!这是我到目前为止得到的

test.text:

this is a line of text a
this is line 2b
line 3
line 4
line etc.etc.etc.
Test.java:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class Test {
    public static final Charset ENCODING = Charset.forName("UTF-8");
    public static final byte[] NEWLINE_BYTE = {0x0A, 0x0D};

    public Test() {

        String pathString = "test.txt";

        //the path to the file
        Path path = Paths.get(pathString);

        try (FileChannel fc = FileChannel.open(path, 
                StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {            
            if (fc.size() > 0) {
                int n;
                ByteBuffer buffer = ByteBuffer.allocate((int) fc.size());
                do {                    
                    n = fc.read(buffer);
                } while (n != -1 && buffer.hasRemaining());
                buffer.flip();
                int pos = 0;
                System.out.println("FILE LOADED: |" + new String(buffer.array(), ENCODING) + "|");
                do {
                    byte b = buffer.get();
                    if (b == NEWLINE_BYTE[0] || b == NEWLINE_BYTE[1]) {
                        System.out.println("POS: " + pos);
                        System.out.println("POSITION: " + buffer.position());
                        System.out.println("LENGTH: " + Integer.toString(buffer.position() - pos));
                        ByteBuffer lineBuffer = ByteBuffer.wrap(buffer.array(), pos + 1, buffer.position() - pos);
                        System.out.println("LINE: |" + new String(lineBuffer.array(), ENCODING) + "|");
                        pos = buffer.position();
                    }
                } while (buffer.hasRemaining());
            } 
        } catch (IOException ioe) {
           ioe.printStackTrace();
        }
    }
    public static void main(String args[]) {
        Test t = new Test();
    }
}
因此第一部分工作正常,fc.read(buffer)函数只运行一次,并将整个文件拉入ByteBuffer。然后在第二个do循环中,我可以一个字节一个字节地循环,当它命中一个\n(或\r)时,它确实会命中if语句,但是我不知道如何将刚才查看的那部分字节放入一个单独的字节数组中使用!我试过拼接和各种翻转,也试过按照上面代码所示的方式进行换行,但似乎无法正常工作,两个缓冲区都有完整的文件,我拼接或换行的任何内容都是如此


我只需要一个字节一个字节地循环文件,每次查看某个部分,然后我的最终目标是,当我查看并找到正确的位置时,我想在正确的位置插入一些数据!我需要在“LINE:”处输出的lineBuffer,以便只包含到目前为止我循环使用的部分字节!帮帮忙,谢谢你

将I/O放在一边,一旦您在
字节缓冲区中有了内容,通过
asCharBuffer()
将其转换为
CharBuffer
会简单得多。然后,
CharBuffer
实现了
CharSequence
,这为您提供了许多可使用的
String
和regex方法。

下面是我最终得到的解决方案,每次使用ByteBuffer的bulk relative get函数获取块。我想我正在使用mark()函数,尽管我使用了一个附加变量(pos)来跟踪标记,因为我在ByteBuffer中找不到一个函数来返回标记本身的相对位置。此外,我还提供了显式功能,可以按顺序查找\r\n或两者。请记住,此代码仅适用于UTF-8编码的数据。我希望这对其他人有帮助

public class Test {
    public static final Charset ENCODING = Charset.forName("UTF-8");
    public static final byte[] NEWLINE_BYTES = {0x0A, 0x0D};

    public Test() {
        //test text file sequence of any strings followed by newline
        String pathString = "test.txt";
        Path path = Paths.get(pathString);

        try (FileChannel fc = FileChannel.open(path, 
                StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {

            if (fc.size() > 0) {
                int n;
                ByteBuffer buffer = ByteBuffer.allocate((int) fc.size());
                do {                    
                    n = fc.read(buffer);
                } while (n != -1 && buffer.hasRemaining());
                buffer.flip();
                int newlineByteCount = 0;
                buffer.mark();
                do {
                    //get one byte at a time
                    byte b = buffer.get();

                    if (b == NEWLINE_BYTES[0] || b == NEWLINE_BYTES[1]) {
                        newlineByteCount++;

                        byte nextByte = buffer.get();
                        if (nextByte == NEWLINE_BYTES[1]) {
                            newlineByteCount++;
                        } else {
                            buffer.position(buffer.position() - 1);
                        }

                        int pos = buffer.position();
                        //reset the buffer back to the mark() position
                        buffer.reset();
                        //create an array just the right length and get the bytes we just measured out 
                        int length = pos - buffer.position() - newlineByteCount;
                        byte[] lineBytes = new byte[length];
                        buffer.get(lineBytes, 0, length);

                        String lineString = new String(lineBytes, ENCODING);
                        System.out.println("LINE: " + lineString);

                        buffer.position(buffer.position() + newlineByteCount);

                        buffer.mark();
                        newlineByteCount = 0;
                    } else if (newlineByteCount > 0) {

                    }
                } while (buffer.hasRemaining());
            } 
        } catch (IOException ioe) { ioe.printStackTrace(); }
    }
    public static void main(String args[]) { new Test(); }
}

我需要类似的东西,但比拆分单个缓冲区更一般。在我的例子中,我有多个缓冲区;事实上,我的代码是Spring的一个修改,它可以将
通量
()转换为
通量


TL;DR有一个
ByteBuffer#wrap(byte[],int,int)
似乎就是你要找的for@Eugene比如:ByteBuffer lineBuffer=ByteBuffer.wrap(buffer.array(),startOfLine,buffer.position());是的,看起来像。。。让我知道如果这样做有效,BTW将无法让它工作,我尝试创建一个用该部分包装的缓冲区。代码正在运行,但每次整个文件都在缓冲区中,而不仅仅是第一行!编辑问题以添加更新的代码。奇怪。。。我真的不想调试您的代码,但看看这个,因为它工作得很好:
String test=“123456789”;ByteBuffer newB=ByteBuffer.wrap(test.getBytes(),1,3);System.out.println(StandardCharsets.UTF_8.decode(newB));//234
实际上,我打算显式地将每一行转换为字符串,并使用正则表达式对其进行解析,但我想在让java的解析器接管并将所有字符串转换为UTF-16之前,先用二进制进行初步的反序列化,以验证这些内容。有关更一般的解决方案,请参阅我的答案。