前言
在网络编程中,我们到底在监控用户的输入的时候,往往采用换行符号,作为一次输入的结尾,但是用户发送的数据不可能每次只有一行,这就需要我们对用户的数据进行拆包和分包,假设的用户要输出的数据是
123456
12345678901234567890123
123456
kkkkkk
99999
000000000000000000000
ppppp
0
000000
思路
可以看到,假设我们设置的缓冲区大小是10,那么第一次读取的数据是123456\n123
这10个字节的数字,此时,如果第一次读取的数据,已经产生了黏包,需要把\n后面的123给取出,并且不能完全去除,还需要找个地方暂存起来。
接下来是第二轮读取,此时,由于暂存区还有第一次剩下的123
占用了3个字节,所以第二次读到的只能是读取到的第二行中的4567890
7个字符,此时缓冲区中的数据是1234567890
,此时显然还没有读取到换行符,此时,需要将这些字符全部另找一个地方存起来,并且,10个字节的缓存区,需要清空,以备下次再读取10个字节的字符,如此循环往复。
代码
package com.cloud;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
public class TestByteBuffer5 {
//集中写入
public static void main(String[] args) {
//解决思路,有可能第一次读取的是完整的,并且还多余了,
//第二次发的是完整的,但是是一半
try (FileChannel channel = new FileInputStream("data3.txt").getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(10);
StringBuilder builder = new StringBuilder();
while (true) {
//第一次读取10个字节123456\n123
int read = channel.read(buffer);
if (read == -1 && buffer.position()==0) {
break;
}
StringBuilder line = new StringBuilder();
//转化为读取模式
buffer.flip();
int i = 0;
while (buffer.hasRemaining()) {
byte b = buffer.get();
line.append((char) b);
if ((char) b == '\n') {
//读取到\n之后,应该把buffer给compact一下,把剩余的字符挪到buffer的最前面
//遇到\n,把第一行的数据输出
if (builder.toString().equals("")){
System.out.print(line);
} else {
System.out.print(builder+line.toString());
builder = new StringBuilder();
}
//此时把剩余的字符挪到buffer的最前面
buffer.compact();
break;
} else {
i++;
if (i == 10) {
//证明这一轮循环当中,并没有碰到换行符号,那么这次的字符应该全部缓存起来
builder.append(line);
//此时读取了10次,那么应该把buffer清空
buffer.clear();
break;
//那么什么时候把builder输出呢?
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
//每次读取遇到\n,那么就输出一次内容,并且,将剩余的内容,进行重新分配
}
}