我有一个程序可以从亚马逊s3读取文本文件,但文件大约是400M。我增加了我的堆大小,但我仍然得到Java堆大小错误。所以,我不确定我的代码是否正确。我使用Amazon SDK for java和Guava来处理文件流。
请帮忙
S3Object object = s3Client.getObject(new GetObjectRequest(bucketName, folder + filename));
final InputStream objectData = object.getObjectContent();
InputSupplier supplier = CharStreams.newReaderSupplier(new InputSupplier() {
@Override
public InputStream getInput() throws IOException {
return objectData;
}
}, Charsets.UTF_8);
String content = CharStreams.toString(supplier);
objectData.close();
return content;
我将此选项用于我的JVM。 -Xms512m -Xmx2g
。我使用ant来运行主程序,所以我也将jvm选项包含在ANT_OPTS中。但它还没有奏效。
答案 0 :(得分:7)
InputSupplier
的重点 - 尽管您现在应该使用ByteSource
和CharSource
- 但您永远不应该从外部访问InputStream
,所以你不必记得关闭它。
如果您在引入ByteSource
和CharSource
之前使用旧版本的番石榴,那么这应该是
InputSupplier supplier = CharStreams.newReaderSupplier(new InputSupplier() {
@Override
public InputStream getInput() throws IOException {
S3Object object = s3Client.getObject(
new GetObjectRequest(bucketName, folder + filename));
return object.getObjectContent();
}
}, Charsets.UTF_8);
String content = CharStreams.toString(supplier);
如果您正在使用Guava 14,那么这可以更加流畅地完成
new ByteSource() {
@Override public InputStream openStream() throws IOException {
S3Object object = s3Client.getObject(
new GetObjectRequest(bucketName, folder + filename));
return object.getObjectContent();
}
}.asCharSource(Charsets.UTF_8).read();
那就是说:你的文件可能是400MB,但是Java String
存储为UTF-16,这可以轻松地将其内存消耗加倍。您可能需要更多内存,或者需要找到一种方法来避免将整个文件同时保留在内存中。
答案 1 :(得分:2)
不是将整个文件存储在内存中,而是可以按部件读取文件,这样整个文件就不会在内存中。避免将整个文件存入内存,以免因内存有限而导致内存问题
GetObjectRequest rangeObjectRequest = new GetObjectRequest(bucketName, key);
rangeObjectRequest.setRange(0, 1000); // retrieve 1st 1000 bytes.
S3Object objectPortion = s3Client.getObject(rangeObjectRequest);
InputStream objectData = objectPortion.getObjectContent();
//现在进入循环并通过从s3读取内容并在循环中追加文件来本地生成文件,这样就不会在内存中存储整个内容