我正在使用java中的BufferedReader读取大型日志文件。我必须过滤文件的内容并将数据存储在数据库中。 示例
BufferedReader br=new BufferedReader(new FileReader("test.log"));
String line;
while((line=br.readLine())!=null){
if(line.contains("filter1") || line.contains("filter2") ||
line.contains("filter3") || line.contains("filter4")...){
//creating object and storing using hibernate
}
}
我有超过50个这样的过滤器,并且在读取超过100 MB的文件时会出现问题。在匹配这些过滤字符串时浪费了很多时间。
如果条件是读取行的子字符串,我不能使用Collection.contains(line)作为过滤器。所花费的时间不是由于IO,而是内容的过滤和创建用于存储的对象。
编辑1: - filter1,filter2仅为简单起见。在实际情况下,过滤器就像 - "新文件","报告","从文件夹",#34;架构",& #34;移动","复制","添加到队列","唯一ID"这些是我检查的特定关键字,以查看该行是否包含用于存储的相关数据。
请建议更好的方法来实现同样的目标。
答案 0 :(得分:1)
在Java 8中,您可以使用Files.lines将文件读取为Stream。
此示例显示如何使用Stream过滤内容,将整个内容转换为大写并将其作为List返回。
c://lines.txt – A simple text file for testing
line1
line2
line3
line4
line5
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestReadFile {
public static void main(String args[]) {
String fileName = "c://lines.txt";
List<String> list = new ArrayList<>();
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
//1. filter line 3
//2. convert all content to upper case
//3. convert it into a List
list = stream
.filter(line -> !line.startsWith("line3"))
.map(String::toUpperCase)
.collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}
list.forEach(System.out::println);
}
}
答案 1 :(得分:0)
这取决于过滤器的外观。如果确实是filter1
,filter2
等,那么您可以使用正则表达式
private static final Pattern pattern = Pattern.compile("filter[0-9]");
... // in a loop
if (pattern.matcher(line).matches()) {...}
(你也可以避免分配)。这里不需要精确的过滤器,只是排除非匹配行的概率很高(并且不包括匹配的行)。
例如,您可以使用4克或类似物,使用rolling hash之类的
/// Initialization
Set<Integer> hashesOf4grams = new HashSet<>();
for (String s : filters) {
if (s.length() < 4) {
... do some handling for short strings, omitted here as probably not needed.
}
int hash = 0;
for (int i = 0; i < 4; ++i) {
hash = (hash << 8) + s.charAt(i);
}
hashesOf4grams.add(hash);
}
/// Loop.
for (String line : lines) {
boolean maybeMatching = false;
int hash = 0;
for (int i = 0; i < line.length() && !maybeMatching; ++i) {
hash = (hash << 8) + line.charAt(i);
maybeMatching = hashesOf4grams.contains(hash);
}
if (!maybeMatching) {
continue;
}
// Slow test.
boolean surelyMatching = false;
for (String s : filters) {
if (line.contains(s)) {
surelyMatching = true;
break;
}
}
if (surelyMatching) {...}
}
上面的转移确保只有最后4个字符很重要。可以使用一些原始集合代替Set.contains
(使用装箱)。
您可以使用tries ...
您也可以使用常见的子串。你的例子对于任何有用的东西来说仍然太短,但是像
这样的东西private static final Pattern pattern = Pattern.compile("new file|re(port|moved from folder)");
可以比单独测试所有内容更好。我想,尝试应该是最好的,但是N-gram更简单,并且可以很好地工作。
在上面的实现中,我假设所有过滤器的长度至少为4。