BufferedReader 如何从 S3 读取文件?

How does BufferedReader read files from S3?

我在 AWS S3 中有一个非常大的文件(几 GB),我只需要文件中满足特定条件的少量行。我不想将整个文件加载到内存中,然后搜索并打印那几行——这样做的内存负载会太高。正确的方法是只加载内存中需要的那些行。

根据 AWS 文档to read from file

fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key));
 displayTextInputStream(fullObject.getObjectContent());

private static void displayTextInputStream(InputStream input) throws IOException {
    // Read the text input stream one line at a time and display each line.
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));
    String line = null;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    System.out.println();
}

这里我们使用了BufferedReader。我不清楚这里下面发生了什么。

我们是否在每次读取新行时都对 S3 进行网络调用,并且只将当前行保留在缓冲区中?还是将整个文件加载到内存中,然后由 BufferedReader 逐行读取?还是介于两者之间?

取决于文件中行的大小。 readLine() 将继续构建字符串,以缓冲区大小的块为单位从流中获取数据,直到您遇到行终止符。所以使用的内存将是你的行长+缓冲区长度的顺序。

您链接的文档中已经给出了您问题的其中一个答案:

Your network connection remains open until you read all of the data or close the input stream.

A BufferedReader 不知道它读取的数据来自哪里,因为您正在将另一个 Reader 传递给它。 BufferedReader 创建一个特定大小的缓冲区(例如 4096 个字符),并在开始分发 read() 或 [=15 的调用数据之前通过从底层 Reader 读取来填充此缓冲区=].

你传递给 BufferedReaderReader 是 - 顺便说一句 - 使用另一个缓冲区来完成从基于 byte 的流到 char基reader。它的工作方式与 BufferedReader 相同,因此内部缓冲区通过读取传递的 InputStream 来填充,这是由您的 S3 客户端编辑的 InputStream return。

如果您尝试从流中加载数据,此客户端中究竟发生了什么取决于实现。一种方法是保持打开一个网络连接,您可以根据需要从中读取,或者可以在读取一大块数据后关闭网络连接,并在您尝试获取下一个数据时打开一个新连接。

上面引用的文档似乎说我们这里有前一种情况,所以:不,readLine 的调用不会导致单个网络调用。

并回答您的其他问题:不,BufferedReaderInputStreamReader 和很可能由 S3 客户端编辑的 InputStream return 没有加载将整个文件存入内存。这将与首先使用流的整个目的相矛盾,S3 客户端可以简单地 return 一个 byte[][] 来代替(绕过每个 byte 数组 2^32 字节的限制)

编辑:最后一段有一个例外。如果整个千兆字节的大文档没有换行符,调用 readLine 实际上会导致将整个数据读入内存(并且很可能导致 OutOfMemoryError)。我在回答您的问题时假设了一个 "regular" 文本文档。

如果您基本上不是在搜索特定的 word/words,并且知道字节范围,您也可以在 S3 中使用范围 header。当您处理一个几 GB 大小的文件时,这应该特别有用。指定 Range 不仅有助于减少内存,而且速度更快,因为只读取文件的指定部分。

Is there "S3 range read function" that allows to read assigned byte range from AWS-S3 file?

希望对您有所帮助。

Sreram

只对 AWS 基础设施进行一次 HTTP 调用,数据以小块的形式读入内存,其大小可能会有所不同,并且不受您的直接控制。

假设文件中的每一行都相当小,这已经非常节省内存了。

假设您的 "certain condition" 是一个简单的字符串匹配,进一步优化(针对网络和计算资源)的一种方法是使用 S3 Select:https://aws.amazon.com/s3/features/#s3-select