gpt4 book ai didi

java - MappedByteBuffer 查询

转载 作者:行者123 更新时间:2023-11-29 07:47:26 24 4
gpt4 key购买 nike

我想读取一个 150 MB 的文本文件并将文件的内容拆分为单词。当我使用 MappedByteBuffer 执行此操作时,文件大小为 135 mb 需要 12 秒。当我对 BufferedReader 做同样的事情时,它会花费更多时间。是否可以缩短时间?

这是我的代码。

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.ConcurrentHashMap;


public class mappedcompare {

public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
long one =System.currentTimeMillis();
String line=null;



File f= new File("D:\\dinesh\\janani.txt");
FileInputStream fin = new FileInputStream(f);
FileChannel fc = fin.getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0L, fc.size());
String[] words=null;
ConcurrentHashMap <String,Integer> dictionary=new ConcurrentHashMap<String,Integer>(50,1);
byte[] buffer = new byte[(int) fc.size()];
mbb.get(buffer);
ByteArrayInputStream isr = new ByteArrayInputStream(buffer);
InputStreamReader ip = new InputStreamReader(isr);
BufferedReader br = new BufferedReader(ip);
while((line=br.readLine())!=null){
line=line.replace(':', ' ');
line=line.replace(';', ' ');
line=line.replace('"', ' ');
line=line.replace('!', ' ');
line=line.replace(',',' ');
line=line.replace('.', ' ');
line =line.replace('/', ' ');
line=line.replace('\\', ' ');
line=line.replace('%', ' ');
line=line.replace('(', ' ');
line=line.replace(')', ' ');
line=line.replace('\'', ' ');
for(String word: line.split("\\s+"))
{
dictionary.putIfAbsent(word, 1);

if(dictionary.containsKey("word")){
int value =dictionary.get(word);
dictionary.replace(word, ++value);
}

}
}
System.out.println(System.currentTimeMillis() - one);
fin.close();

}

}

最佳答案

首先,不要在单线程操作中使用ConcurrentHashMap。与简单的 HashMap 相比,使用此类没有任何好处。在 Java 7 中,HashMap 不提供操作 putIfAbsent 等,但这不是限制,而是清理您的 Map 更新的机会代码:

dictionary.putIfAbsent(word, 1);

if(dictionary.containsKey("word")){
int value =dictionary.get(word);
dictionary.replace(word, ++value);
}

在这里,您正在执行四个哈希查找操作,putIfAbsentcontainsKeygetreplace,其中你实际上只需要两个(除了寻找 "word" 而不是 word 对我来说看起来很糟糕):

Integer old=dictionary.get(word);
dictionary.put(word, old==null? 1: old+1);

这只需要两次查找并使用普通的 HashMap


接下来,摆脱 line=line.replace(…, ' '); 调用的序列,因为它们中的每一个都会创建一个新的 String想要的是在您的 split 操作中处理这些特殊字符,例如 ' ' 。因此,您可以调整 split 操作以将这些字符视为分隔符:for(String word: line.split("[:;\"!,./\\\\%( )'\\s]+")).


因此,将所有这些放在一起,您的代码将变得更具可读性,这比您可以节省几秒钟的时间更大。

File f= new File("D:\\dinesh\\janani.txt");
try(FileInputStream fin = new FileInputStream(f);
FileChannel fc = fin.getChannel();) {
final MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0L, fc.size());
HashMap<String, Integer> dictionary=new HashMap<>();
byte[] buffer = new byte[(int) fc.size()];
mbb.get(buffer);
ByteArrayInputStream isr = new ByteArrayInputStream(buffer);
InputStreamReader ip = new InputStreamReader(isr);
BufferedReader br = new BufferedReader(ip);
while((line=br.readLine())!=null){
for(String word: line.split("[:;\"!,./\\\\%()'\\s]+")) {
Integer old=dictionary.get(word);
dictionary.put(word, old==null? 1: old+1);
}
}
}

最后,我建议尝试一下 Files.readAllLines(...)。它是否更快取决于环境,但即使它稍微慢一点,由于可读性获胜,我更喜欢它而不是你的 MappedByteBuffer 方法:

File f= new File("D:\\dinesh\\janani.txt");
HashMap<String, Integer> dictionary=new HashMap<>();
for(String line:Files.readAllLines(f.toPath(), Charset.defaultCharset())) {
for(String word: line.split("[:;\"!,./\\\\%()'\\s]+")) {
Integer old=dictionary.get(word);
dictionary.put(word, old==null? 1: old+1);
}
}

如果性能真的那么重要,您可以更深入地处理您在 byte 级别手动拆分,并仅在找到匹配项后创建 String。这假设您使用的编码对每个 char 使用一个 byte 并直接映射较低的值(即 ASCII 字符),这是常见编码(如 Window CP1258)的情况。

HashMap<String, Integer> dictionary=new HashMap<>();
final CharsetDecoder cs = Charset.defaultCharset().newDecoder();
assert cs.averageCharsPerByte()==1;
try(FileChannel ch=FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
MappedByteBuffer mbb=ch.map(MapMode.READ_ONLY, 0, ch.size());
ByteBuffer slice=mbb.asReadOnlyBuffer();
int start=0;
while(mbb.hasRemaining()) {
switch(mbb.get()) {
case ' ': case 9: case 10: case 11: case 13: case '\f':
case ':': case ';': case '\\': case '"': case '!': case ',':
case '.': case '/': case '%': case '(': case ')': case '\'':
int pos=mbb.position();
if(pos>start) {
slice.limit(mbb.position()).position(start);
String word=cs.decode(slice).toString();
Integer old=dictionary.get(word);
dictionary.put(word, old==null? 1: old+1);
start=mbb.position();
}
start=pos+1;
}
}
}

这可以以不完全便携为代价显着加速这种低级操作。

关于java - MappedByteBuffer 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24389112/

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