用Java解析一个没有很好的大文件

时间:2010-12-04 18:32:40

标签: java parsing file-io

我必须解决一个接近解析像3 GB或更高版本的巨大文件的问题。好吧,该文件的结构如下:伪xml文件如:

<docFileNo_1>
<otherItems></otherItems>

<html>
<div=XXXpostag>
</html>

</docFileNo>
   ... others doc... 
<docFileNo_N>
<otherItems></otherItems>

<html>
<div=XXXpostag>
</html>

</docFileNo>

网上冲浪我读过有些人遇到管理文件的问题,但他们建议我用NIO映射文件。 所以我认为解决方案过于庞大,可能会让我抛出异常。所以我认为我的问题是解决2个doutbs:

  1. 如何及时有效地阅读 3 GB文本文件
  2. 如何解析     有效地从html提取     docFileNoxx,并应用规则     用于提取帖子的html标签 标签。
  3. 所以......我试着用这种方式解决第一个问题:

    1. _reader = new BufferedReader(new FileReader(filePath))//创建一个 文件缓冲读取器
    2. _currentLine = _reader.readLine(); //我迭代读取它的文件 逐行
    3. 对于每一行,我都附加了这些行 到一个String变量,直到遇到 标签
    4. 所以使用JSOUP和后期CSS过滤器 我提取内容,并把它 文件。
    5. 提取25 MB的过程平均需要大约88秒.... 所以我想表演。

      我可以进行提取吗?

3 个答案:

答案 0 :(得分:1)

对于大型XML文件,最好使用SAX样式解析器,这些解析器不会尝试在内存中为整个XML文件构建文档对象模型。我不会尝试逐行读取XML文件,我会在SAX实现中调用适当的方法。 Oracle有一个tutorial

答案 1 :(得分:1)

无论你做什么,都不要做(伪代码):

String data = "";
for line in file {
    data += line;
}

但使用StringBuilder:

StringBuilder data = new StringBuilder();
for line in file {
    data.append(line);
}
return data.toString();

此外,考虑浏览文件并创建仅包含有趣部分的地图。 我假设你没有XML但只看起来有点像它,你给出的例子是对内容的公平表示。

Map<String, String> entries = new HashMap<String,String>(1000);
StringBuilder entryData = null;
for line in file {
  if line starts with "<docFileNo" {
     docFileNo = extract number from line;
  } else if line starts with "<div=XXXpostag>" {
     // Content of this entry starts here
     entryData = new StringBuilder();
  } else if line starts with "</html>" {
     // content of this entry ends here
     // so store content, and indicate that the entry is finished by 
     // setting data to null
     entries.put(docFileNo, entryData.toString);
     entryData = null;
  } else if entryData is not null {
     // we're in an entry as data is not null, so store the line
     entryData.append(line);
  }
}

地图仅包含条目大小的字符串,这使得它们更容易处理。我认为您需要根据真实数据进行调整,但这可以在大约半小时内完成测试。

线索是entryData。它不仅是构建1个条目的数据的StringBuilder,而且如果不为null,它还表示我们看到了一个开始条目标记(div),如果为null,我们看到结束标记(</html>)表示下一个不需要存储行。

我假设您要保留doc号,并且XXXposttag是常量。

可以使用Scanner类来实现此逻辑的替代实现。

答案 2 :(得分:0)

如果你的问题是光盘部件,你可以通过使用带有大缓冲区的BufferedInputStream来加速这个过程 - 例如以下示例中为256KB:

InputStream in = new BufferedInputStream(new FileInputStream(filePath),256*1024)));
new BufferedReader(new InputStreamReader(in));

如果问题是CPU并且你有一台多核机器,你可以尝试将工作转移到一个单独的线程中。