Как читать огромный CSV-файл из Google Cloud Storage построчно, используя Java? - PullRequest
1 голос
/ 18 марта 2019

Я новичок в Google Cloud Platform.Я пытаюсь прочитать файл CSV, присутствующий в облачном хранилище Google (непубличное хранилище, доступ к которому осуществляется с помощью ключа учетной записи службы), строка за строкой, которая составляет около 1 ГБ.

Не удалось найти какой-либо вариант для чтения файла, присутствующего в Google Cloud Storage (GCS), построчно.Я вижу только параметры чтения размером в чанкс / байт.Так как я пытаюсь прочитать CSV, я не хочу использовать чтение по chunksize, так как это может разделить запись во время чтения.

Решения, которые до сих пор пробовали: Попытка копирования содержимого из файла CSV, присутствующего в GCS, во временный локальный файл и чтения временного файла с использованием приведенного ниже кода.Приведенный ниже код работает должным образом, но я не хочу копировать огромный файл в мой локальный экземпляр.Вместо этого я хочу читать построчно из GCS.

    StorageOptions options = 
    StorageOptions.newBuilder().setProjectId(GCP_PROJECT_ID)
            .setCredentials(gcsConfig.getCredentials()).build();
    Storage storage = options.getService();
    Blob blob = storage.get(BUCKET_NAME, FILE_NAME);
    ReadChannel readChannel = blob.reader();
    FileOutputStream fileOuputStream = new FileOutputStream(TEMP_FILE_NAME);
    fileOuputStream.getChannel().transferFrom(readChannel, 0, Long.MAX_VALUE);
    fileOuputStream.close();

Пожалуйста, предложите подход.

Ответы [ 3 ]

2 голосов
/ 18 марта 2019

Брэндон Ярбро прав, и добавил бы к его ответу:

если вы используете gcloud для входа с учетными данными, тогда код Брэндона будет работать: google-cloud-nio будет использовать ваш логин для доступа к файлам (и этобуду работать даже если они не будут публичными).

Если вы предпочитаете делать все это в программном обеспечении, вы можете использовать этот код для считывания учетных данных из локального файла, а затем для доступа к своему файлу из Google Cloud:

    String myCredentials = "/path/to/my/key.json";
    CloudStorageFileSystem fs =
        CloudStorageFileSystem.forBucket(
            "bucket",
            CloudStorageConfiguration.DEFAULT,
            StorageOptions.newBuilder()
                .setCredentials(ServiceAccountCredentials.fromStream(
                    new FileInputStream(myCredentials)))
                .build());
    Path path = fs.getPath("/lolcat.csv");
    List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);

редактировать: вы неВы не хотите читать все строки одновременно, поэтому не используйте realAllLines, но, получив Path, вы можете использовать любой из других методов, описанных выше, чтобы прочитать только ту часть файла, которая вам нужна: вы можетечитать по одной строке за раз или получить объект Channel.

2 голосов
/ 18 марта 2019

Одним из самых простых способов может быть использование пакета google-cloud-nio, который уже используется библиотекой google-cloud-java: https://github.com/googleapis/google-cloud-java/tree/v0.30.0/google-cloud-contrib/google-cloud-nio

Он включает Google Cloud Storage в NIO Java, поэтому после его запуска вы можете обращаться к ресурсам GCS точно так же, как и к файлу или URI. Например:

Path path = Paths.get(URI.create("gs://bucket/lolcat.csv"));
try (Stream<String> lines = Files.lines(path)) {
   lines.forEach(s -> System.out.println(s));
} catch (IOException ex) {
   // do something or re-throw...
}
1 голос
/ 18 марта 2019

Поскольку я выполняю пакетную обработку, я использую приведенный ниже код в методе init () моего ItemReader, который аннотируется @PostConstruct. И в readRe) моего ItemReader я строю список. Размер списка совпадает с размером чанка. Таким образом, я могу читать строки, основываясь на моем chunkSize, вместо того, чтобы читать все строки одновременно.

StorageOptions options = 
StorageOptions.newBuilder().setProjectId(GCP_PROJECT_ID)
        .setCredentials(gcsConfig.getCredentials()).build();
Storage storage = options.getService();
Blob blob = storage.get(BUCKET_NAME, FILE_NAME);
ReadChannel readChannel = blob.reader();
BufferedReader br = new BufferedReader(Channels.newReader(readChannel, "UTF-8"));
...