BufferedReader 耗时太长
BufferedReader taking too long
这是为了更快地读取文件而不是写入文件。
我有一个 150MB 的文件,里面有一个 JSON 对象。我目前使用以下代码阅读它:
String filename ="/tmp/fileToRead";
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename), Charset.forName("UTF-8")));
decompressedString = reader.readLine();
reader.close();
JSONObject obj = new JSONObject(decompressedString);
JSONArray profileData = obj.getJSONObject("profileData").getJSONArray("children");
....
它是一个单行文件,因为它是 JSON 我不能拆分它(或者至少我是这么认为的)。阅读文件给我 OutOfMemory Error
或 TLE
。读取文件需要超过 7 秒,这会导致 TLE,因为整个代码的执行不能超过 7 秒。我在 decompressedString = reader.readLine();
.
上遇到了 OOM
有什么方法可以减少使用的内存或完全读取所需的时间?
您手头有几个问题:
你抢先解析的太多了
当您阅读您说 "I get the OOM on decompressedString = reader.readLine();
" 后的行时,您遇到的错误已经发生了。
您永远不要尝试逐行阅读 数据。 BufferedReader.readLine()
将阻塞,直到您读完字符 \r
或 \n
或序列 \r\n
。在处理任何长度的数据时,您永远不会确定您会得到这些字符之一。此外,您永远无法确定自己会得到数据本身 之外的那些字符。所以你的字符串可能太长或格式不正确。所以永远不要假装知道格式。 BufferedReader.readLine()
必须在解析时使用,获取数据时不能使用
您没有为您的用例使用合适的库
阅读您的 JSON 很重要,是的,但是您一次阅读的内容太多了。创建 JSON 时,您可能希望从流(InputStream
、Reader
或任何 nio 的 Channel
/Buffer
之一)构建它。
目前您正在 String
制作 JSON。一个巨大的。所以我可以放心地假设你会在某一时刻需要两倍于你需要的内存。一次在字符串中,一次在最终对象中。
要减少这种情况,请使用适当的库,您可以将上述流之一传递到该库。我在评论中提到了以下内容:Gson, JSON.simple and Jackson.
你的文件可能太大了。
如果您获取了数据并且只想获取其中的一个子集(在这里,您想要 {"profileData":{"children": <DATA>}}
下的所有内容)。但你可能有太多了。与 profileData
处于同一级别的元素有多少?与 children
处于同一级别的元素有多少?你知道吗?可能太多了。不在profileData.children
下的都是没用的。那是你总数据的多少百分比? 50%? 90%? 99%?
要解决这个问题,您可能需要以下两种方法之一:您想要更少的数据,或者您希望能够集中您的请求。
如果您想要更少的数据,请让您的数据提供商提供更少的数据:只提供您需要的数据。为什么要得到更多?这没有道理。这么告诉他然后说 "I want less".
如果您想要集中数据,请使用允许您解析和减少数据量的库。您可能希望有一个库可以这样说:"parse this JSON and return only the processingData.children
element"。 不幸的是,我知道没有图书馆这样做。如果其他人这样做,请添加评论或回答。 显然,如果您自己使用 JsonReader
并有选择地使用 skipValue()
,Gson 能够做到这一点。
这是为了更快地读取文件而不是写入文件。 我有一个 150MB 的文件,里面有一个 JSON 对象。我目前使用以下代码阅读它:
String filename ="/tmp/fileToRead";
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename), Charset.forName("UTF-8")));
decompressedString = reader.readLine();
reader.close();
JSONObject obj = new JSONObject(decompressedString);
JSONArray profileData = obj.getJSONObject("profileData").getJSONArray("children");
....
它是一个单行文件,因为它是 JSON 我不能拆分它(或者至少我是这么认为的)。阅读文件给我 OutOfMemory Error
或 TLE
。读取文件需要超过 7 秒,这会导致 TLE,因为整个代码的执行不能超过 7 秒。我在 decompressedString = reader.readLine();
.
有什么方法可以减少使用的内存或完全读取所需的时间?
您手头有几个问题:
你抢先解析的太多了
当您阅读您说 "I get the OOM on
decompressedString = reader.readLine();
" 后的行时,您遇到的错误已经发生了。您永远不要尝试逐行阅读 数据。
BufferedReader.readLine()
将阻塞,直到您读完字符\r
或\n
或序列\r\n
。在处理任何长度的数据时,您永远不会确定您会得到这些字符之一。此外,您永远无法确定自己会得到数据本身 之外的那些字符。所以你的字符串可能太长或格式不正确。所以永远不要假装知道格式。BufferedReader.readLine()
必须在解析时使用,获取数据时不能使用您没有为您的用例使用合适的库
阅读您的 JSON 很重要,是的,但是您一次阅读的内容太多了。创建 JSON 时,您可能希望从流(
InputStream
、Reader
或任何 nio 的Channel
/Buffer
之一)构建它。目前您正在
String
制作 JSON。一个巨大的。所以我可以放心地假设你会在某一时刻需要两倍于你需要的内存。一次在字符串中,一次在最终对象中。要减少这种情况,请使用适当的库,您可以将上述流之一传递到该库。我在评论中提到了以下内容:Gson, JSON.simple and Jackson.
你的文件可能太大了。
如果您获取了数据并且只想获取其中的一个子集(在这里,您想要
{"profileData":{"children": <DATA>}}
下的所有内容)。但你可能有太多了。与profileData
处于同一级别的元素有多少?与children
处于同一级别的元素有多少?你知道吗?可能太多了。不在profileData.children
下的都是没用的。那是你总数据的多少百分比? 50%? 90%? 99%?要解决这个问题,您可能需要以下两种方法之一:您想要更少的数据,或者您希望能够集中您的请求。
如果您想要更少的数据,请让您的数据提供商提供更少的数据:只提供您需要的数据。为什么要得到更多?这没有道理。这么告诉他然后说 "I want less".
如果您想要集中数据,请使用允许您解析和减少数据量的库。您可能希望有一个库可以这样说:"parse this JSON and return only the
processingData.children
element"。不幸的是,我知道没有图书馆这样做。如果其他人这样做,请添加评论或回答。显然,如果您自己使用JsonReader
并有选择地使用skipValue()
,Gson 能够做到这一点。