Чтение CSV-файла

JavaJavaBeginner

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии (лабораторной работе) мы научимся считывать CSV (Comma-Separated Values, значения, разделенные запятыми) файлы на Java. CSV - это распространенный формат файлов, используемый для хранения табличных данных, таких как электронные таблицы или экспорт из базы данных. Каждая строка в CSV файле представляет строку данных, а столбцы разделены запятыми.

Мы рассмотрим три различных подхода к считыванию CSV файлов на Java:

  • Использование класса BufferedReader из пакета java.io
  • Использование класса Scanner из пакета java.util
  • Использование библиотеки OpenCSV, популярной сторонней библиотеки для обработки CSV файлов

К концу этого практического занятия (лабораторной работы) вы сможете выбрать наиболее подходящий метод для считывания CSV файлов в своих Java-приложениях, основываясь на своих конкретных требованиях.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/ConcurrentandNetworkProgrammingGroup(["Concurrent and Network Programming"]) java(("Java")) -.-> java/DataStructuresGroup(["Data Structures"]) java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java(("Java")) -.-> java/FileandIOManagementGroup(["File and I/O Management"]) java/DataStructuresGroup -.-> java/arrays("Arrays") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/arraylist("ArrayList") java/FileandIOManagementGroup -.-> java/files("Files") java/FileandIOManagementGroup -.-> java/create_write_files("Create/Write Files") java/FileandIOManagementGroup -.-> java/read_files("Read Files") java/FileandIOManagementGroup -.-> java/io("IO") java/ConcurrentandNetworkProgrammingGroup -.-> java/working("Working") subgraph Lab Skills java/arrays -.-> lab-117982{{"Чтение CSV-файла"}} java/arraylist -.-> lab-117982{{"Чтение CSV-файла"}} java/files -.-> lab-117982{{"Чтение CSV-файла"}} java/create_write_files -.-> lab-117982{{"Чтение CSV-файла"}} java/read_files -.-> lab-117982{{"Чтение CSV-файла"}} java/io -.-> lab-117982{{"Чтение CSV-файла"}} java/working -.-> lab-117982{{"Чтение CSV-файла"}} end

Создание примерного CSV-файла и структуры проекта

Перед тем, как мы начнем считывать CSV-файлы, убедимся, что наш проект настроен правильно. На этом этапе мы рассмотрим структуру нашего CSV-файла и создадим наш основный Java-класс.

Понимание CSV-файлов

CSV (Comma-Separated Values, значения, разделенные запятыми) файл хранит табличные данные в простом текстовом формате. Каждая строка представляет строку таблицы, а столбцы разделены запятыми. CSV-файлы широко используются для обмена данными из-за их простоты и совместимости с множеством приложений, таких как Excel, Google Sheets и системы управления базами данных.

Просмотр нашего примерного CSV-файла

В нашей лабораторной среде уже есть примерный CSV-файл по пути ~/project/sample.csv. Давайте сначала посмотрим на его содержимое:

cat ~/project/sample.csv

Вы должны увидеть следующий вывод:

name,age,city
John,25,New York
Alice,30,Los Angeles
Bob,28,Chicago
Eve,22,Boston

Этот CSV-файл содержит четыре строки данных (включая строку заголовка) с информацией о людях, их возрасте и городах проживания.

Создание нашего Java-класса

Теперь давайте создадим новый Java-класс с именем CSVReaderDemo.java в директории src, который мы будем использовать на протяжении всего практического занятия (лабораторной работы).

В VSCode нажмите на значок проводника в боковой панели, перейдите в директорию ~/project/src, щелкните правой кнопкой мыши по ней и выберите "New File" (Новый файл). Назовите файл CSVReaderDemo.java.

Добавьте в файл следующую базовую структуру:

public class CSVReaderDemo {
    public static void main(String[] args) {
        System.out.println("CSV Reader Demo");

        // Мы добавим код для чтения CSV-файла на следующих этапах
    }
}
Create Java File

Давайте скомпилируем и запустим наш Java-класс, чтобы убедиться, что все настроено правильно:

cd ~/project
javac -d . src/CSVReaderDemo.java
java CSVReaderDemo

Вы должны увидеть вывод:

CSV Reader Demo

Отлично! Теперь наша структура проекта готова. На следующих этапах мы реализуем различные методы для чтения нашего CSV-файла.

Чтение CSV-файлов с использованием BufferedReader

На этом этапе мы реализуем наш первый подход к чтению CSV-файлов с использованием класса BufferedReader из пакета java.io. Это распространенный и простой метод для чтения текстовых файлов на Java.

Понимание BufferedReader

BufferedReader - это класс, который читает текст из символьного входного потока, буферизируя символы для эффективного чтения символов, массивов и строк. Размер буфера можно указать или использовать размер по умолчанию.

Реализация чтения CSV с использованием BufferedReader

Давайте обновим файл CSVReaderDemo.java, чтобы прочитать CSV-файл с использованием BufferedReader. Замените весь контент файла следующим кодом:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CSVReaderDemo {
    public static void main(String[] args) {
        System.out.println("Reading CSV using BufferedReader");

        // Path to our CSV file
        String csvFile = "sample.csv";

        // Lists to store our data
        List<List<String>> data = new ArrayList<>();

        // Try-with-resources to ensure the reader gets closed automatically
        try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
            String line;

            // Read each line from the file
            while ((line = br.readLine()) != null) {
                // Split the line by comma and convert to a List
                String[] values = line.split(",");
                List<String> lineData = Arrays.asList(values);

                // Add the line data to our main list
                data.add(lineData);
            }

            // Print the data we read
            System.out.println("\nData read from CSV file:");
            for (int i = 0; i < data.size(); i++) {
                List<String> row = data.get(i);
                System.out.println("Row " + i + ": " + String.join(", ", row));
            }

        } catch (IOException e) {
            System.err.println("Error reading the CSV file: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
Update Java File

Давайте скомпилируем и запустим наш обновленный код:

cd ~/project
javac -d . src/CSVReaderDemo.java
java CSVReaderDemo

Вы должны увидеть вывод, похожий на следующий:

Reading CSV using BufferedReader

Data read from CSV file:
Row 0: name, age, city
Row 1: John, 25, New York
Row 2: Alice, 30, Los Angeles
Row 3: Bob, 28, Chicago
Row 4: Eve, 22, Boston

Пояснение к коду

  1. Мы импортируем необходимые Java-классы для операций ввода-вывода файлов и структур данных.
  2. Мы определяем путь к нашему CSV-файлу (sample.csv).
  3. Мы создаем List<List<String>> для хранения наших CSV-данных в виде двумерного списка.
  4. Мы используем блок try-with-resources для автоматического закрытия BufferedReader после использования.
  5. Мы читаем каждую строку из файла с помощью br.readLine().
  6. Для каждой строки мы разделяем ее по запятым с использованием line.split(",") и преобразуем в List.
  7. Мы добавляем каждую строку в наш основной список данных.
  8. Наконец, мы выводим данные, чтобы убедиться, что мы прочитали их правильно.

Подход с использованием BufferedReader прост и эффективен для чтения текстовых файлов, в том числе CSV-файлов. Однако он имеет ограничения при работе с более сложным форматированием CSV, например, когда поля содержат запятые или переносы строк, заключенные в кавычки.

На следующем этапе мы рассмотрим другой подход с использованием класса Scanner.

Чтение CSV-файлов с использованием Scanner

На этом этапе мы реализуем второй подход к чтению CSV-файлов с использованием класса Scanner из пакета java.util. Класс Scanner предоставляет удобный способ чтения форматированного ввода из различных источников.

Понимание Scanner

Класс Scanner разбивает входные данные на токены с использованием шаблона-разделителя, который по умолчанию соответствует пробельным символам. Затем полученные токены могут быть преобразованы в значения различных типов с помощью различных методов next.

Реализация чтения CSV с использованием Scanner

Давайте обновим файл CSVReaderDemo.java, чтобы прочитать CSV-файл с использованием Scanner. Замените весь контент файла следующим кодом:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class CSVReaderDemo {
    public static void main(String[] args) {
        System.out.println("Reading CSV using Scanner");

        // Path to our CSV file
        String csvFile = "sample.csv";

        // Lists to store our data
        List<List<String>> data = new ArrayList<>();

        try (Scanner scanner = new Scanner(new File(csvFile))) {
            // Read each line from the file
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();

                // Split the line by comma and convert to a List
                String[] values = line.split(",");
                List<String> lineData = Arrays.asList(values);

                // Add the line data to our main list
                data.add(lineData);
            }

            // Print the data we read
            System.out.println("\nData read from CSV file:");
            for (int i = 0; i < data.size(); i++) {
                List<String> row = data.get(i);
                System.out.println("Row " + i + ": " + String.join(", ", row));
            }

        } catch (FileNotFoundException e) {
            System.err.println("CSV file not found: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Давайте скомпилируем и запустим наш обновленный код:

cd ~/project
javac -d . src/CSVReaderDemo.java
java CSVReaderDemo

Вы должны увидеть вывод, похожий на следующий:

Reading CSV using Scanner

Data read from CSV file:
Row 0: name, age, city
Row 1: John, 25, New York
Row 2: Alice, 30, Los Angeles
Row 3: Bob, 28, Chicago
Row 4: Eve, 22, Boston

Пояснение к коду

  1. Мы импортируем необходимые Java-классы для операций с файлами, Scanner и структур данных.
  2. Мы определяем путь к нашему CSV-файлу (sample.csv).
  3. Мы создаем List<List<String>> для хранения наших CSV-данных в виде двумерного списка.
  4. Мы используем блок try-with-resources для автоматического закрытия Scanner после использования.
  5. Мы читаем каждую строку из файла с помощью scanner.nextLine(), пока scanner.hasNextLine() возвращает true.
  6. Для каждой строки мы разделяем ее по запятым с использованием line.split(",") и преобразуем в List.
  7. Мы добавляем каждую строку в наш основной список данных.
  8. Наконец, мы выводим данные, чтобы убедиться, что мы прочитали их правильно.

Подход с использованием Scanner похож на подход с BufferedReader, но предоставляет более удобные методы для разбора различных типов данных. Однако, как и BufferedReader, он имеет ограничения при работе с сложным форматированием CSV.

На следующем этапе мы рассмотрим более надежный подход с использованием библиотеки OpenCSV, которая более эффективно обрабатывает сложное форматирование CSV.

Чтение CSV-файлов с использованием библиотеки OpenCSV

На этом этапе мы реализуем третий подход к чтению CSV-файлов с использованием библиотеки OpenCSV. OpenCSV - это сторонняя библиотека, которая предоставляет надежные возможности парсинга CSV, обрабатывая сложные сценарии, такие как поля, содержащие запятые или переносы строк, заключенные в кавычки.

Понимание OpenCSV

OpenCSV - это библиотека для парсинга CSV на Java, которая поддерживает все основные вариации формата CSV. В отличие от предыдущих подходов, OpenCSV правильно обрабатывает поля в кавычках, содержащие запятые, разрывы строк и другие специальные символы, которые иначе могут нарушить простое разделение по запятым.

Настройка OpenCSV

Сначала давайте скачаем библиотеку OpenCSV и ее зависимости:

cd ~/project
mkdir -p lib
curl -L -o lib/opencsv-5.7.1.jar https://repo1.maven.org/maven2/com/opencsv/opencsv/5.7.1/opencsv-5.7.1.jar
curl -L -o lib/commons-lang3-3.12.0.jar https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar
curl -L -o lib/commons-text-1.10.0.jar https://repo1.maven.org/maven2/org/apache/commons/commons-text/1.10.0/commons-text-1.10.0.jar
curl -L -o lib/commons-beanutils-1.9.4.jar https://repo1.maven.org/maven2/commons-beanutils/commons-beanutils/1.9.4/commons-beanutils-1.9.4.jar
curl -L -o lib/commons-collections-3.2.2.jar https://repo1.maven.org/maven2/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar
curl -L -o lib/commons-logging-1.2.jar https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar

Создание более сложного CSV-файла

Давайте создадим более сложный CSV-файл, который включает поля в кавычках с запятыми:

echo 'name,description,price
"Laptop","High-performance laptop, with SSD",999.99
"Smartphone","Latest model, with dual camera",499.99
"Headphones","Noise-canceling, wireless",149.99' > ~/project/products.csv

Реализация чтения CSV с использованием OpenCSV

Теперь давайте обновим файл CSVReaderDemo.java, чтобы прочитать CSV-файл с использованием OpenCSV. Замените весь контент файла следующим кодом:

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;
import java.io.FileReader;
import java.io.IOException;

public class CSVReaderDemo {
    public static void main(String[] args) {
        System.out.println("Reading CSV using OpenCSV");

        // Path to our CSV file with complex data
        String csvFile = "products.csv";

        try (CSVReader reader = new CSVReader(new FileReader(csvFile))) {
            // Read and print the header
            String[] header = reader.readNext();
            if (header != null) {
                System.out.println("\nHeader: " + String.join(", ", header));
            }

            // Read and print each line
            String[] nextLine;
            int rowNumber = 1;

            System.out.println("\nData read from CSV file:");
            while ((nextLine = reader.readNext()) != null) {
                System.out.println("Row " + rowNumber + ":");
                for (int i = 0; i < nextLine.length; i++) {
                    System.out.println("  " + header[i] + ": " + nextLine[i]);
                }
                rowNumber++;
                System.out.println();
            }

        } catch (IOException | CsvValidationException e) {
            System.err.println("Error reading the CSV file: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Давайте скомпилируем и запустим наш обновленный код:

cd ~/project
javac -cp ".:lib/*" -d . src/CSVReaderDemo.java
java -cp ".:lib/*" CSVReaderDemo

Вы должны увидеть вывод, похожий на следующий:

Reading CSV using OpenCSV

Header: name, description, price

Data read from CSV file:
Row 1:
  name: Laptop
  description: High-performance laptop, with SSD
  price: 999.99

Row 2:
  name: Smartphone
  description: Latest model, with dual camera
  price: 499.99

Row 3:
  name: Headphones
  description: Noise-canceling, wireless
  price: 149.99

Пояснение к коду

  1. Мы импортируем необходимые классы из библиотеки OpenCSV и пакета Java I/O.
  2. Мы определяем путь к нашему CSV-файлу (products.csv).
  3. Мы создаем объект CSVReader для чтения CSV-файла.
  4. Мы читаем строку заголовка с помощью reader.readNext() и сохраняем ее для дальнейшего использования.
  5. Затем мы читаем каждую последующую строку с помощью reader.readNext() в цикле, пока не закончатся строки.
  6. Для каждой строки мы выводим каждое поле вместе с соответствующим заголовком.

Библиотека OpenCSV автоматически обрабатывает сложное форматирование CSV, правильно парся поля с запятыми, заключенными в кавычки. Это делает ее идеальным выбором для реальных CSV-файлов, которые могут содержать сложные данные.

Преимущества OpenCSV

OpenCSV имеет несколько преимуществ по сравнению с базовыми подходами:

  1. Она правильно обрабатывает поля в кавычках, содержащие запятые, переносы строк и другие специальные символы.
  2. Она предоставляет встроенную поддержку для чтения в объекты (Java-объекты).
  3. Она поддерживает расширенные функции, такие как пользовательские разделители, символы кавычек и символы экранирования.
  4. Она эффективно обрабатывает большие CSV-файлы.

Для большинства реальных приложений, работающих с CSV-файлами, использование специальной библиотеки, такой как OpenCSV, является рекомендуемым подходом.

Резюме

В этом практическом занятии (лабораторной работе) мы рассмотрели три различных подхода к чтению CSV-файлов на Java:

  1. Использование BufferedReader: Простой подход с использованием стандартной библиотеки ввода-вывода Java. Он хорошо работает для простых CSV-файлов, но имеет ограничения при работе с сложным форматированием CSV.
  2. Использование Scanner: Другой подход с использованием стандартной утилитарной библиотеки Java. Как и BufferedReader, он подходит для простых CSV-файлов, но не поддерживает сложное форматирование CSV.
  3. Использование OpenCSV: Надежный подход с использованием сторонней библиотеки, специально разработанной для обработки CSV. Она обрабатывает сложное форматирование CSV, включая поля в кавычках, содержащие запятые, переносы строк и другие специальные символы.

Каждый подход имеет свои преимущества и области применения:

  • BufferedReader и Scanner - хорошие выборы для простых CSV-файлов, если вы хотите избежать внешних зависимостей.
  • OpenCSV - лучший выбор для реальных приложений, работающих с потенциально сложными CSV-файлами.

Понимая эти различные подходы, вы можете выбрать наиболее подходящий метод на основе своих конкретных требований и сложности ваших CSV-данных.

CSV-файлы широко используются в сценариях обработки данных, обмена данными и интеграции данных. Возможность читать и обрабатывать CSV-файлы является ценным навыком для Java-разработчиков, особенно в приложениях, ориентированных на обработку данных, и при интеграции с другими системами.