【问题标题】:Java reading a big fileJava读取一个大文件
【发布时间】:2021-03-13 08:47:34
【问题描述】:

所以我的想法是我需要阅读这个 .json 文件。 它太大了,我什至无法使用记事本或 Visual Studio 代码打开它。

我试过这个:

BufferedReader in = new BufferedReader(new FileReader("path to the file"));
String line = in.readLine();

我得到这个错误:

线程“主”java.lang.OutOfMemoryError 中的异常:Java 堆空间 在 java.base/java.util.Arrays.copyOf(Arrays.java:3536) 在 java.base/java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:228) 在 java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:735) 在 java.base/java.lang.StringBuilder.append(StringBuilder.java:227) 在 java.base/java.io.BufferedReader.readLine(BufferedReader.java:372) 在 java.base/java.io.BufferedReader.readLine(BufferedReader.java:392) 在 com.ReadJSON.TagValues.listFilesForFolder(TagValues.java:133) 在 com.ReadJSON.TagValues.listFilesForFolder(TagValues.java:129) 在 com.ReadJSON.TagValues.listFilesForFolder(TagValues.java:129) 在 com.ReadJSON.TagValues.listFilesForFolder(TagValues.java:129) 在 com.ReadJSON.Main.main(Main.java:18)

我在互联网上搜索了一些解决方案是更改内存设置,但它不起作用,它返回相同的错误。 另一个问题是整个文件是ONELINE。文件的全部内容写在一行中。 我想我必须在某个时间打破该行的读取部分,这样它就不会超过分配的最大内存,存储该值并从我离开的地方再次开始读取。一遍又一遍地这样做,直到行尾。

我应该如何阅读这个文件有什么建议吗?我应该尝试不同的方式来阅读它还是有什么技巧可以打破 readLine()?

谢谢!

【问题讨论】:

标签: java file memory readline


【解决方案1】:

即使您可以增加 JVM 内存限制,但这是不必要的,并且分配像 1GB 这样的巨大内存来处理文件过度杀伤和资源密集型。

InputStream inFileReader = channelSFtp.get(path); // file reading from ssh.
byte[] localbuffer = new byte[2048];

int i = 0;
while (-1 != (i = inFileReader.read(buffer))) {
    //Deal with the current read 2KB file chunk here
}

inFileReader.close();

这样你就可以逐段阅读了。

【讨论】:

  • 从技术上讲,这是复制流或将读取字节缓冲区推送到下游的好建议,但这似乎与 OP 的问题无关。 OP 似乎在一行中收集整个文件的瓶颈处被烧毁,而 JSON 内容(根据提供的堆栈跟踪)最有可能直接与输入流和读取器一起使用。
【解决方案2】:

对于如此庞大的 JSON 文件,不应将整个 JSON DOM(文档对象模型)读入内存。但是使用流解析器。

如果只有一个大行,带有 readLine 的 BufferedReader 无论如何都是错误的。 JSON 文件通常也采用 UT-8 编码。 FileReader 是一个使用默认字符编码的旧实用程序类:不可移植代码,错误。

有一个 Jackson Streaming API。对于使用 maven 的项目:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.3</version>
</dependency>

代码类似于:

JsonFactory factory = new JsonFactory();
try (JsonParser parser = jactory.createParser(...)) {
    while (parser.nextToken() != JsonToken.END_OBJECT) {
        String field = parser.getCurrentName();
        switch (field) {
        case "...":
            ...
            ... parser.getText();
            ... parser.getIntValue();
            break;
    }
}

用于提取部分数据,或将数据存储在数据库中。

【讨论】:

  • 我有一个离题但有点相关的问题:Jackson 是否提供任何 API 来读取巨大的属性名称和巨大的字符串文字?
  • 我从来不需要巨大的令牌,所以你需要自己试试。有一些二进制数据存储为 Base64,它们很大。我认为字符串可能有 Integer.MAX_VALUE 限制。
【解决方案3】:

您可以查看DSM 流媒体库。您可以在解析 JSON 文档时对其进行处理。您在 yaml 中为要处理的数据定义映射。它根据映射文件处理 JSON 文档。 DSM 使用 Jackson 流 api。

您可以查看此问题中的示例

JAVA - Best approach to parse huge (extra large) JSON file

【讨论】:

    猜你喜欢
    • 2017-10-02
    • 1970-01-01
    • 2011-01-22
    • 2011-05-06
    • 1970-01-01
    • 2021-04-02
    • 2016-12-06
    • 2013-09-01
    相关资源
    最近更新 更多