Java中的文本文件解析

时间:2009-05-21 00:13:26

标签: java file parsing

我正在使用FileInputStream读取文本文件,将文件内容放入字节数组中。然后我使用新的String(byte)将字节数组转换为String。

一旦我有了字符串,我正在使用String.split("\n")将文件拆分为一个String数组,然后获取该字符串数组并通过执行String.split(",")解析它并将内容保存在Arraylist中。

我有一个 200MB + 文件,当我使用1GB内存启动JVM时,内存不足。我知道我必须在某处正确地做某事,我只是不确定我解析的方式是不正确的还是我正在使用的数据结构。

这也花了大约12秒来解析文件似乎很多时间。任何人都可以指出我可能在做什么导致我内存不足以及可能导致程序运行缓慢的原因吗?

文件内容如下所示:

"12334", "100", "1.233", "TEST", "TEXT", "1234"
"12334", "100", "1.233", "TEST", "TEXT", "1234"
.
.
.
"12334", "100", "1.233", "TEST", "TEXT", "1234"

由于

6 个答案:

答案 0 :(得分:11)

我不确定它在内存方面的效率如何,但我的第一种方法是使用Scanner因为它非常容易使用:

File file = new File("/path/to/my/file.txt");
Scanner input = new Scanner(file);

while(input.hasNext()) {
    String nextToken = input.next();
    //or to process line by line
    String nextLine = input.nextLine();
}

input.close();

检查API以了解如何更改用于拆分令牌的分隔符。

答案 1 :(得分:9)

听起来你对我做错了 - 正在进行大量的对象创作。

“测试”文件的代表性如何?你在用这些数据做什么?如果这是你真正拥有的典型内容,我会说这些数据有很多重复。

如果它总是在Strings中,那么从BufferedReader开始读取每一行。将该List预分配到接近您所需的大小,这样您就不会浪费资源每次都添加到它。用逗号分隔每一行;一定要剥掉双引号。

您可能想问自己:“为什么我需要一次性将所有文件都放在内存中?”你能读一点,处理一点,并且永远不会把整个事情记在内存中吗?只有你能够很好地了解你的问题才能回答。

如果你有JDK 6并且看看内存发生了什么,也许你可以启动jvisualvm。那将是一个很好的线索。

答案 2 :(得分:5)

看看这些页面。它们包含许多开源CSV解析器。 JSaPar就是其中之一。

答案 3 :(得分:4)

听起来你现在在内存中有3个整个文件的副本:字节数组,字符串和行数组。

不是将字节读入字节数组然后使用new String()转换为字符,而是使用InputStreamReader,它将逐步转换为字符,而不是全部预先转换为字符。

此外,您不应使用String.split(“\ n”)来获取各行,而应一次读取一行。您可以使用readLine()中的BufferedReader方法。

尝试这样的事情:

BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
try {
  while (true) {
    String line = reader.readLine();
    if (line == null) break;
    String[] fields = line.split(",");
    // process fields here
  }
} finally {
  reader.close();
}

答案 4 :(得分:2)

如果您有200,000,000个字符文件并且每五个字符拆分一次,那么您有40,000,000个String个对象。假设他们正在与原始的400 MB共享实际字符数据Stringchar是2个字节)。 String表示32个字节,因此是String个对象的1,280,000,000个字节。

(可能值得注意的是,这非常依赖于实现。split可以使用全新的支持char[]创建完全字符串,或OTOH,共享一些常见的String值。一些Java实现不使用char[]的切片。有些可能使用类似UTF-8的紧凑形式,并且给出非常差的随机访问时间。)

即使假设更长的字符串,这也是很多对象。有了那么多数据,您可能希望以原始的紧凑形式(仅使用索引)处理大部分数据。只转换为您需要的对象。实现应该是数据库(尽管它们传统上不能有效地处理可变长度字符串)。

答案 5 :(得分:0)

在调用/调用程序时,您可以使用以下命令:java [-options] className [args ...]
代替[-options]提供更多的内存,例如-Xmx1024m或更多。但这只是一种解决方法,你必须改变你的解析机制。