# Техническое задание: чтение и дозапись `Student` в CSV ## Задача Реализовать два независимых класса для работы с объектами `Student` в формате CSV: - `StudentCsvWriter` — дозапись студентов в файл; - `StudentCsvReader` — последовательное чтение студентов из файла. Для работы с форматом CSV использовать готовую библиотеку для работы с CSV. Самостоятельно реализовывать парсинг CSV запрещено. Оба класса должны принимать **абсолютный путь к файлу**. Исключения `Student` и `StudentBuilder` не обрабатывать. --- # Формат CSV-файла Первая строка файла должна содержать заголовок: ```text groupNumber,averageGrade,recordBookNumber ``` Каждая следующая строка содержит данные одного студента: ```text groupNumber,averageGrade,recordBookNumber ``` Пример: ```text groupNumber,averageGrade,recordBookNumber A12,4.5,10001 B07,3.8,10002 C25,4.9,10003 ``` Для формирования и чтения CSV использовать стандартную библиотеку для работы с форматом CSV. --- ## `StudentCsvWriter` ### Назначение Дозаписывать одного студента в **существующий** CSV-файл. ### Контракт Конструктор: ```java public StudentCsvWriter(String absoluteFilePath) ``` Метод: ```java public void write(Student student) throws IOException ``` ### Требования 1. Метод принимает одного `Student`. 2. Указанный файл должен уже существовать. 3. Запись выполняется в режиме добавления. 4. Существующие записи не должны изменяться. 5. Заголовок CSV не должен записываться повторно. 6. Если файл не существует, новый файл **не создавать**. 7. Если файл не существует, метод должен выбросить `IOException`. 8. При успешной записи метод завершается без исключения. 9. Метод не возвращает значение. 10. Исключения, связанные с записью файла, не обрабатывать внутри метода. 11. Исключения `Student` и `StudentBuilder` также не обрабатывать. ## Невозможность записи Если указанный файл не существует, метод должен выбросить `IOException`. Также `IOException` должен возникать и передаваться вызывающему коду, если: - файл недоступен для записи; - отсутствуют права на запись; - произошла ошибка файловой системы; - запись в файл невозможна по другой причине. Создание файла с именем вида: ```text students-yyyy-MM-dd-HH-mm.csv ``` `StudentCsvWriter` **не выполняет**. ## Пример теста: несуществующий файл Передать путь к несуществующему файлу: ```java writer.write(student); ``` Проверить: ```text IOException ``` Проверить также, что новый файл не был создан. ## Изменение теста существующего файла Для существующего файла: ```text groupNumber,averageGrade,recordBookNumber A12,4.5,10001 ``` выполнить: ```java writer.write(student2); ``` Проверить, что результат: ```text groupNumber,averageGrade,recordBookNumber A12,4.5,10001 B07,3.8,10002 ``` Заголовок присутствует только один раз. ## Дополнительный метод `StudentCsvWriter` Кроме метода записи одного студента: ```java public void write(Student student) throws IOException; ``` необходимо реализовать метод: ```java public void write(MyList[] students) throws IOException; ``` ### Контракт Метод должен: 1. Принимать массив `MyList`. 2. Последовательно обрабатывать все переданные коллекции. 3. Записывать каждого студента в указанный CSV-файл. 4. Сохранять порядок: - коллекций в массиве; - студентов внутри каждой `MyList`. 5. Использовать тот же формат CSV и те же правила записи, что и `write(Student)`. 6. Работать только с уже существующим файлом. 7. Не создавать файл, если он отсутствует. 8. При отсутствии файла выбрасывать `IOException`. 9. Не изменять переданные `MyList`. 10. Не обрабатывать исключения, возникающие при создании или валидации `Student`. 11. При ошибке записи прекращать операцию и передавать исключение вызывающему коду. ### Пример ```java MyList[] studentLists = ...; writer.write(studentLists); ``` Если: ```text studentLists[0] = [Student A, Student B] studentLists[1] = [Student C] studentLists[2] = [Student D, Student E] ``` в файл должны последовательно добавиться: ```text Student A Student B Student C Student D Student E ``` ### Проверка пустых коллекций Пустые `MyList` внутри массива не должны приводить к ошибке и не должны добавлять записей в файл. ### Проверка пустого массива Для: ```java MyList[] studentLists = ...; // размер 0 ``` метод не должен добавлять никаких записей и не должен изменять файл. ### Проверка отсутствующего файла Для несуществующего файла: ```java writer.write(studentLists); ``` должен выбрасываться `IOException`. Файл создавать запрещено. --- # `StudentCsvReader` ## Назначение Последовательно читать студентов из CSV-файла. ## Контракт Класс должен реализовывать: ```java Iterator ``` Конструктор: ```java public StudentCsvReader(String absoluteFilePath) ``` Методы: ```java @Override public boolean hasNext() ``` ```java @Override public Student next() ``` ### Требования к `hasNext()` 1. Проверяет наличие следующей записи `Student`. 2. Заголовок CSV не считается записью. 3. Повторный вызов `hasNext()` не должен пропускать следующую запись. 4. После окончания файла метод возвращает `false`. ### Требования к `next()` 1. Возвращает следующего `Student`. 2. `Student` создаётся через существующий `StudentBuilder`. 3. При отсутствии следующего элемента выбрасывается: ```text NoSuchElementException ``` 1. Весь файл не должен предварительно загружаться в коллекцию. ## Невозможность прочитать студента Если следующую запись невозможно прочитать или преобразовать в `Student`, например: - некорректный формат CSV; - отсутствует обязательное поле; - значение невозможно преобразовать в нужный тип; - данные не проходят валидацию `Student`; исключение должно передаваться вызывающему коду. Исключения `Student` и `StudentBuilder` **не перехватывать и не обрабатывать**. Некорректные записи не должны молча пропускаться. --- # Общие требования 1. Оба класса принимают абсолютный путь к файлу. 2. Использовать готовую библиотеку для работы с CSV. 3. Не реализовывать собственный CSV-парсер. 4. Не использовать стандартные коллекции Java как основное хранилище студентов. 5. Не дублировать в этих классах валидацию `Student`. 6. Не дублировать логику создания `Student` вне `StudentBuilder`. 7. `StudentCsvWriter` отвечает только за запись. 8. `StudentCsvReader` отвечает только за чтение. --- # Примеры тестов ## `StudentCsvWriter` ### Создание нового файла Передать путь к несуществующему файлу и вызвать: ```java writer.write(student); ``` Проверить: - файл создан; - имя соответствует `students-yyyy-MM-dd-HH-mm.csv`; - присутствует заголовок; - студент записан; - метод завершился без исключения. ### Дозапись Создать файл с одним студентом и выполнить: ```java writer.write(student2); ``` Проверить, что: - первая запись сохранилась; - `student2` добавлен в конец; - заголовок присутствует только один раз. ### Несколько последовательных записей ```java writer.write(student1); writer.write(student2); writer.write(student3); ``` Проверить наличие трёх записей в правильном порядке. ### Невозможность записи Передать путь, по которому невозможно создать или открыть файл для записи. Проверить, что `write()` выбрасывает `IOException`. Не проверять специальное возвращаемое значение — метод ничего не возвращает. --- ## `StudentCsvReader` ### Чтение корректного файла Для файла: ```text groupNumber,averageGrade,recordBookNumber A12,4.5,10001 B07,3.8,10002 C25,4.9,10003 ``` Проверить: - `hasNext()` возвращает `true` до последнего студента; - `next()` возвращает студентов в правильном порядке; - после последнего студента `hasNext()` возвращает `false`. ### Повторный вызов `hasNext()` ```java reader.hasNext(); reader.hasNext(); Student student = reader.next(); ``` Проверить, что первый студент не был пропущен. ### `next()` после окончания файла После чтения всех студентов вызвать: ```java reader.next(); ``` Проверить выброс: ```text NoSuchElementException ``` ### Некорректная запись Передать файл: ```text groupNumber,averageGrade,recordBookNumber A12,4.5,10001 INVALID C25,4.9,10003 ``` Проверить, что ошибка при чтении некорректной записи передаётся вызывающему коду. ### Некорректные данные `Student` Передать данные, нарушающие ограничения `Student`. Проверить, что исключение от `Student` или `StudentBuilder` выходит наружу и не перехватывается `StudentCsvReader`. --- # Названия файлов ```text StudentCsvWriter.java StudentCsvReader.java ``` # Git Название ветки: ```text feature/csv-student-io ``` Conventional Commit: ```text feat: add csv student reader and writer ```