gpt4 book ai didi

Java FileChannel 与 BufferedReader - Spring Batch - Reader

转载 作者:行者123 更新时间:2023-12-01 17:52:01 26 4
gpt4 key购买 nike

我们处理巨大的文件(有时每个文件 50 GB)。应用程序读取这一文件,并根据业务逻辑,写入多个输出文件(4-6)。

文件中的记录长度可变,记录中的每个字段均由分隔符分隔。

据了解,使用带有 ByteBuffer 的 FileChannel 读取文件总是比使用 BufferedReader.readLine 然后使用分隔符分割更好。

  • BufferSizes 尝试了 10240(10KB) 甚至更多
  • 提交间隔 - 5000、10000 等

下面是我们如何使用文件 channel 读取:

  • 逐字节读取。检查读取的字节是否为换行符(10) -这意味着行尾。
  • 检查分隔符字节。捕获字节数组中读取的字节(我们使用最大字段大小 350 字节初始化此字节数组),直到遇到分隔符字节。
  • 使用 UTF-8 编码将到目前为止读取的这些字节转换为 String - new String(byteArr, 0, index,"UTF-8") 具体来说 - index 是直到分隔符为止读取的字节数。<

使用这种使用 FileChannel 读取文件的方法需要 57 分钟来处理文件。

我们想减少这个时间,并尝试使用 BufferredReader.readLine(),然后使用分隔符分割,看看效果如何。

令人震惊的是,同一个文件仅用了 7 分钟就完成了处理。

这里有什么问题?为什么 FileChannel 比缓冲读取器花费更多时间,然后使用字符串分割。

我一直假设 ReadLine 和 Split 组合会对性能产生很大的影响?

如果我以错误的方式使用 FileChannel,有人可以指出吗?一个

提前致谢。希望我已经正确总结了这个问题。

下面是示例代码:

while (inputByteBuffer.hasRemaining() && (b = inputByteBuffer.get()) != 0){
boolean endOfField = false;
if (b == 10){
break;
}
else{
if (b == 94){//^
if (!inputByteBuffer.hasRemaining()){
inputByteBuffer.clear();
noOfBytes = inputFileChannel.read(inputByteBuffer);
inputByteBuffer.flip();
}
if (inputByteBuffer.hasRemaining()){
byte b2 = inputByteBuffer.get();
if (b2 == 124){//|
if (!inputByteBuffer.hasRemaining()){
inputByteBuffer.clear();
noOfBytes = inputFileChannel.read(inputByteBuffer);
inputByteBuffer.flip();
}

if (inputByteBuffer.hasRemaining()){
byte b3 = inputByteBuffer.get();
if (b3 == 94){//^
String field = new String(fieldBytes, 0, index, encoding);
if(fieldIndex == -1){
fields = new String[sizeFromAConfiguration];
}else{
fields[fieldIndex] = field;
}

fieldBytes = new byte[maxFieldSize];
endOfField = true;
fieldIndex++;
}
else{
fieldBytes = addFieldBytes(fieldBytes, b, index);
index++;
fieldBytes = addFieldBytes(fieldBytes, b2, index);
index++;
fieldBytes = addFieldBytes(fieldBytes, b3, index);
}
}
else{
endOfFile = true;
//fields.add(new String(fieldBytes, 0, index, encoding));
fields[fieldIndex] = new String(fieldBytes, 0, index, encoding);
fieldBytes = new byte[maxFieldSize];
endOfField = true;
}
}else{
fieldBytes = addFieldBytes(fieldBytes, b, index);
index++;
fieldBytes = addFieldBytes(fieldBytes, b2, index);

}
}else{
endOfFile = true;
fieldBytes = addFieldBytes(fieldBytes, b, index);
}
}
else{
fieldBytes = addFieldBytes(fieldBytes, b, index);
}
}

if (!inputByteBuffer.hasRemaining()){
inputByteBuffer.clear();
noOfBytes = inputFileChannel.read(inputByteBuffer);
inputByteBuffer.flip();
}

if (endOfField){
index = 0;
}
else{
index++;
}

}

最佳答案

常量 hasRemaining() 造成了大量开销/read()检查以及常量 get()来电。 get() 可能会更好将整个缓冲区放入数组并直接处理,只需调用 read()当你到达终点时。

要回答评论中的问题,您不应分配新的 ByteBuffer每次阅读。这很贵。继续使用同一个。请注意,使用 DirectByteBuffer对于这个应用程序。这是不合适的:仅当您希望数据位于 JVM/JNI 边界以南时才合适,例如仅在 channel 之间复制时。

但我想我会扔掉它,或者更确切地说,使用 BufferedReader.read() 重写它。 ,而不是 readLine()接下来是字符串分割,并使用与此处大致相同的逻辑,当然,除了您不需要继续调用 hasRemaining()并填充缓冲区,BufferedReader会自动为您完成。

您必须小心存储 read() 的结果进入int ,并在每个 read() 之后检查它是否为 -1 .

我不清楚您是否应该使用 Reader事实上,除非你知道你有多字节文本。可能是一个简单的BufferedInputStream会更合适。

关于Java FileChannel 与 BufferedReader - Spring Batch - Reader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49061304/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com