Files
aston-team-project/docs/tasks/CsvStudentIO.md
T

442 lines
13 KiB
Markdown

# Техническое задание: чтение и дозапись `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<Student>[] students) throws IOException;
```
### Контракт
Метод должен:
1. Принимать массив `MyList<Student>`.
2. Последовательно обрабатывать все переданные коллекции.
3. Записывать каждого студента в указанный CSV-файл.
4. Сохранять порядок:
- коллекций в массиве;
- студентов внутри каждой `MyList`.
5. Использовать тот же формат CSV и те же правила записи, что и `write(Student)`.
6. Работать только с уже существующим файлом.
7. Не создавать файл, если он отсутствует.
8. При отсутствии файла выбрасывать `IOException`.
9. Не изменять переданные `MyList<Student>`.
10. Не обрабатывать исключения, возникающие при создании или валидации `Student`.
11. При ошибке записи прекращать операцию и передавать исключение вызывающему коду.
### Пример
```java
MyList<Student>[] 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<Student>` внутри массива не должны приводить к ошибке и не должны добавлять записей в файл.
### Проверка пустого массива
Для:
```java
MyList<Student>[] studentLists = ...; // размер 0
```
метод не должен добавлять никаких записей и не должен изменять файл.
### Проверка отсутствующего файла
Для несуществующего файла:
```java
writer.write(studentLists);
```
должен выбрасываться `IOException`. Файл создавать запрещено.
---
# `StudentCsvReader`
## Назначение
Последовательно читать студентов из CSV-файла.
## Контракт
Класс должен реализовывать:
```java
Iterator<Student>
```
Конструктор:
```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
```