用Java解析格式不好的大文件
我必须解决一个问题,接近解析一个巨大的文件,如3 GB或更高。那么,该文件的结构类似于伪xml文件:用Java解析格式不好的大文件,java,parsing,file-io,Java,Parsing,File Io,我必须解决一个问题,接近解析一个巨大的文件,如3 GB或更高。那么,该文件的结构类似于伪xml文件: <docFileNo_1> <otherItems></otherItems> <html> <div=XXXpostag> </html> </docFileNo> ... others doc... <docFileNo_N> <otherItems></otherI
<docFileNo_1>
<otherItems></otherItems>
<html>
<div=XXXpostag>
</html>
</docFileNo>
... others doc...
<docFileNo_N>
<otherItems></otherItems>
<html>
<div=XXXpostag>
</html>
</docFileNo>
... 其他文件。。。
在网上冲浪时,我读到一些人在管理文件时遇到问题,但他们建议我用NIO映射文件。
所以我认为这个解决方案过于广泛,可能会给我带来一个异常。所以我认为我的问题是解决两个难题:
如何执行提取???对于大型XML文件,最好使用样式分析器,它们不会试图在内存中为整个XML文件构建文档对象模型。我不会尝试逐行读取XML文件,我会在SAX实现中调用适当的方法。Oracle有一个如果您的问题是磁盘io部分,您可以通过使用具有大缓冲区的BufferedInputStream(例如,在以下示例中为256KB)来加速该过程:
InputStream in = new BufferedInputStream(new FileInputStream(filePath),256*1024)));
new BufferedReader(new InputStreamReader(in));
如果问题是CPU,并且您有一台多核机器,那么您可以尝试将工作转移到单独的线程中 无论你做什么,都不要做(伪代码):
但请使用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);
}
}
Map条目=新的HashMap(1000);
StringBuilder entryData=null;
对于文件中的行{
如果一行以“SAX解析器处理非良好格式文档的能力如何?”开头,我在问题中读到它可能不是良好格式的:(示例数据中的问题似乎是div元素未关闭。需要转换为动态。关闭的docFileNo标记也需要后缀。请参阅Joachim Sauer建议在何处对格式不好的大文件使用过滤输入流/读取器Doh tankx…我已经阅读了文章…但如何修改3G file,在标记包装器和结束包装器之后放入顶部xml定义??记住…我必须管理像3G这样的文件…我有50 TB的ile…:(…据我所知,原则是您不修改磁盘上的文件,您的程序在将数据流输入SAX解析器时修改数据流。您能举一个例子说明它如何与STAX??ora SAX解析器一起工作吗?因为我不知道如何管理数据流,以便修改文件添加xml标记,如文章中建议的那样le..tanx.3G中有多少是实际数据(jn div),有多少是结构(docfileno tags等)?因为您不需要在字符串中存储所有可复制的内容。为什么在遇到标记之前需要追加行?步骤3:不要使用字符串,而是使用stringbuilder。字符串+运算符每次都会创建一个新字符串(如果JVM没有对其进行优化,我不确定)。@extraneon的优点,我错过了它,因为我不认为不使用stringbuilder就可以完成它。
:)@khachik我实际上认为,如果concat逻辑是内联写在循环中的,JVM甚至编译器会自动修复这个问题。但我不能保证这一点。如果没有优化,这将是导致OutOfMemory错误的一个很好的原因,因为在3GB时,下一个concat需要大约6GB(旧值和新值)不幸的是,我有一个2.8 GHz的奔腾4处理器。因此我加快了读取文件的过程…但我最大的问题是理解如何加快以下过程:1.将html保存在新的StringBuilder()中2.因此,高效地提取html结构中的帖子内容。我之前解释过,将帖子保存在html中的过程是使用html解析器JSOUP完成的。但我认为JSOUP在处理html时保持了很长的时间。好的。首先,所有的TANX都非常长。我已经按照您的建议修改了我的代码。一切都好了更好…不幸的是,XXXpostag不是常量,但为了检索post标记,我实现了一个过滤器,其中包含一些规则,允许我提取某些cms的内容,如blogger、wordpress..事实上还有另一个问题,那就是应用一个规则:1.识别cms生成器中的post标记。1.1识别cms生成器,正在寻找用于提取内容的任务的规则。所有cms的规则都在xml中。我的疑问是,与规则的字节相比,将所有cms规则转换为字节和…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);
}
}