Занятие №4
Работа с файловой системой. Потоки ввода/вывода. Обработка исключений
Соколов
Никита
Немного о себе
Соколов Никита Николаевич
Старший разработчик в компании
Опыт работы:
- 2008-2010 ФГУП "Почта России"
- 2010-2010 ООО "Квазар" г.Норильск
- 2010-2014 ОАО ЗФ "Норильский никель"
- 2014 по н.в. работаю в ООО "Сибирские интеграционные системы"
Работа с файловой системой | - Немного об основах - Классы / API - Потоки ввода/вывода - Практика |
Что вас ждет на этой лекции
Обработка исключений | - Что это - Зачем это - Как применять - Интерфейс "AutoCloseable" - Типы исключений |
Одним прекрасным днем вы понимаете ...
Мне Нужно поработать
с файлами
* Ввод информации |
- Пользовательские данные - Параметры приложения |
* Вывод результата |
- Результат обработки - Промежуточная информация |
Для чего ?
Где мои файлы ?
В классе !
Позволяет работать: |
---|
- С отдельными файлами - С каталогами |
boolean exists() | Существует? |
boolean isDirectory() | Это директория? |
boolean isFile() | Это файл? |
String getName() | Название файла |
String getPath() | Путь к файлу |
String getAbsolutePath() | Абсолютный путь к файлу |
String getCanonicalPath() | Абсолютный канонический путь |
boolean canRead() | Доступ на чтение (атрибут) |
boolean canWrite() | Доступ на запись (атрибут) |
boolean canExecute() | Доступ на исполнение (атрибут) |
File[] listFiles(FileFilter filter) | список файлов по фильтру |
boolean mkDir() | создание каталога |
boolean mkDirs() | создание каталога с подкаталогами |
int length() | размер файла |
Практика
Разберемся с некоторыми методами класса File
( Полное описание в ссылке в заголовке )
Java = кроссплатформенность
String dir = "C:/CON/PRN/CLOCK$/NUL/";
?
Как избавиться от сложности?
if (isWindows())
return "path\to\ubuntu\distr\\";
else if (isLinux())
return "keep/calm/and/use/linux/";
else
return "who are you man ?!";
Что будет с нашими строковыми путями в другой операционной системе?
Будут ошибки :(
Используйте Path
Path resolve(String other) | Добавить подкаталог |
Path resolve(Path other) | Добавить подкаталог |
File toFile() | Преобразовать в File |
Path subPath(int beginIndex, int endIndex) | Выбрать часть пути |
Path getParent() | Получить путь до родителя |
Практика
Разберемся с некоторыми методами класса Path
( Полное описание в ссылке в заголовке )
Paths.get("C:/temp1/temp2/someFile.txt");
Paths.get("C:/", "temp1", "temp2", "someFile.txt");
Используйте фабрику Paths:
Почему не просто
new SomePathImpl() ?
Path - это интерфейс. А как создать экземпляры ?
public final class Paths {
private Paths() {
}
public static Path get(String first, String... more) {
return Path.of(first, more);
}
public static Path get(URI uri) {
return Path.of(uri);
}
}
Под капотом метода get
public interface Path extends Comparable<Path>, Iterable<Path>, Watchable {
...
static Path of(String first, String... more) {
return FileSystems.getDefault().getPath(first, more);
}
Платформо-зависимая имплементация!
Но для чего знать все эти пути ?
А для того, чтобы считывать файлы и писать в них!
Хорошо, но как ?
Files.lines(Paths.get("some.file"))
.forEach(System.out::println);
Files.write(Paths.get("some.file"),
Arrays.asList("А", "и", "Б",
"Сидели на трубе", "..."));
Читаем файл:
Пишем файл:
Пример использования Files
Magic!
И всё ?
Конечно же, нет...
Потоки
Вывод
результата
Входные
данные
InputStream |
---|
FileInputStream |
ByteArrayInputStream |
OutputStream |
---|
FileOutputStream |
ByteArrayOutpuStream |
Диаграмма классов Stream
Path path = Paths.get(".")
.resolve("inputAuthors.csv");
File inputFile = path.toFile();
InputStream inputStream =
new FileInputStream(inputFile);
while (true) {
int read = inputStream.read();
if (read == -1) {
break;
}
System.out.print((char) read);
}
inputStream.close();
Читаем файл
1. Получить путь к файлу
2. Получить объект File
3. Входящий поток
4. Читать поток в цикле
5. Пока результат чтения не -1
6. Вывести полученный символ
7. Закрыть поток
Используйте FileInputStream
Path inputPath = Paths.get("inputAuthors.csv");
File inputFile = inputPath.toFile();
InputStream fis = new FileInputStream(inputFile);
Path copyPath = Paths.get(".", "copyAuthors.csv");
File copyFile = copyPath.ToFile();
OutputStream fos = new FileOutputStream(copyFile);
byte[] buffer = new byte[4096];
while (true) {
int read = fis.read(buffer);
if (read == -1) {
break;
}
fos.write(buffer, 0, read);
}
fis.close();
fos.close();
Пишем файл
1. Входящий поток
2. Исходящий поток копии
3. Читать входящий поток в переменную read
5. Запись в исходящий поток
6. Закрыть потоки
Используйте FileOutputStream
byte[] buffer = new byte[4096];
while (true) {
int read = fis.read(buffer);
if (read == -1) {
break;
}
fos.write(buffer, 0, read);
}
Буфер
Чтение определенного размера данных за раз
Jav
a_C
ool
a
J
v
a
_
C
o
o
l
!
Поток
while (true) {
int read = inputStream.read();
if (read == -1) {
break;
}
System.out.print((char) read);
}
Побайтовое чтение
Из примера с чтением:
Из примера с копированием:
!
А как работать с текстовыми данными ?
Символьные потоки
Reader / Writer
Path path = Paths.get("inputAuthors.csv");
File file = path.toFile();
InputStream fis = new FileInputStream(file);
Reader reader = new InputStreamReader(
fis, StandardCharsets.UTF_8);
BufferedReader lineReader =
new BufferedReader(reader);
while (true) {
String readLine = lineReader.readLine();
if (Objects.isNull(readLine)) {
break;
}
System.out.println(readLine);
}
lineReader.close();
Читаем текстовый файл
Создать BufferedReader - декоратор Reader, позволяющий работать с буфером.
Для чтения строки вызвать специальный метод readLine.
Закрывать объект Reader входящего потока не нужно. Достаточно закрыть BufferedReader.
А можно проще ?
Path path = Paths.get("inputAuthors.csv");
String charset = StandardCharsets.UTF_8.name;
Scanner scanner = new Scanner(path, charset);
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
scanner.close();
Можно проще!
Используйте Scanner
VS
Path path = Paths.get("inputAuthors.csv");
File file = path.toFile();
InputStream fis = new FileInputStream(file);
Reader reader = new InputStreamReader(
fis, StandardCharsets.UTF_8);
BufferedReader lineReader =
new BufferedReader(reader);
while (true) {
String readLine = lineReader.readLine();
if (Objects.isNull(readLine)) {
break;
}
System.out.println(readLine);
}
lineReader.close();
Path path = Paths.get(
"/","tmp", "test-file.log");
Writer writer = new FileWriter(
path.toFile(),
StandardCharsets.UTF_8);
Writer buffer = new BufferedWriter(writer);
List<String> list = Arrays.asList(
"Hello", " ", "world", "!");
for (String o : list) {
buffer.write(o);
}
buffer.close();
Пишем текстовый файл
1. Создать BufferedWriter
2. Записать данные
3. Закрыть BufferedWriter
А если на write произойдет ошибка?
for (String o : list) {
buffer.write(o);
}
buffer.close();
Буфер не будет закрыт!
Чем грозит?
1. Утечка памяти
2. Файл останется заблокированным
3. Может закончиться лимит на открытые файлы OS
Обработчик
Как избежать?
Программа
Обрабатывать Исключения
Делает что-то недопустимое ....
Пытается устранить проблему
Stacktrace
Метод НачатьИгру()
Метод БроситьМяч()
Метод ОтбитьМяч()
Метод ПойматьМяч()
Мяч в ловушке
Присудить очко команде нападения
Пример стэка
try {
BufferedWriter buffWriter =
Files.newBufferedWriter(path);
//Блок кода бросающий исключение IOException
//Например кончилось место на диске
buffWriter.write("someText");
buffWriter.close();
}
catch (IOException e) {
buffWriter.close();
}
Как поймать?
Используйте Try - Catch
1. Обернуть текст в блок Try
2. Вынести обработку исключения в блок Catch
А если другое исключение?
try {
BufferedWriter buffWriter =
Files.newBufferedWriter(path);
//Блок кода бросающий исключение IOException
//Например кончилось место на диске
buffWriter.write("someText");
//Блок кода, бросающий
//непредвиденное исключение
throw new IllegalArgumentException();
buffWriter.close();
}
catch (IOException e) {
buffWriter.close();
} finally {
buffWriter.close();
}
Используйте Finally
Вынести обработку любого непредвиденного исключения в блок Finally
Что с этим кодом все еще не так?
try {
BufferedWriter buffWriter =
Files.newBufferedWriter(path);
//Блок кода бросающий исключение IOException
//Например кончилось место на диске
buffWriter.write("someText");
//Блок кода, бросающий
//непредвиденное исключение
throw new IllegalArgumentException();
buffWriter.close();
}
catch (IOException e) {
buffWriter.close();
} finally {
buffWriter.close();
}
Если Writer не был создан из-за ошибки
При закрытии будет вызвано другое исключение!
А можно проще ?
Используйте try-with-resources
try (BufferedReader lineReader = new BufferedReader(reader)) {
while (true) {
String line = readLine = lineReader.readLine();
if (line == null) {
break;
}
System.out.println(readLine);
}
}
Любой наследник AutoCloseable может быть использован как ресурс.
Вернемся к примеру с чтением файла
- Имплементируем
- Переопределяем метод close()
- Используем в блоке try {}
Интерфейс AutoCloseable
Типы исключений
Throwable
Exception
Error
RuntimeException
Checked
Unchecked
- OutOfMemoryError |
- StackOverFlowError |
- LinkageError |
- IOException |
- FileNotFoundException |
- ArithmeticException |
- IndexOutOfBoundsException |
- NullPointerException |
Полезные сведения
Полезные библиотеки
IOAdapter<Author> authorAdapter =
new CSVAdapterImpl<>(Author.class,authorFileReader,authorFileWriter);
Author author = authorCsvAdapter.read(0);
assertEquals("Лев Николаевич Толстой",author.getName());
assertEquals("Ясная Поляна",author.getBirthPlace());
Author authorNew = new Author("Некоторый Автор", "Некоторый Город");
int rowIndex = authorCsvAdapter.append(authorNew);
Author authorNewOpened = authorCsvAdapter.read(rowIndex);
assertEquals("Некоторый Автор",author.getName());
assertEquals("Некоторый Город",author.getBirthPlace());
IOAdapter<Book> bookAdapter =
new CSVAdapterImpl<>(Book.class,bookFileReader,bookFileWriter);
...
Домашнее задание
1
1
2
IOAdapter<Author> authorAdapter =
new CSVAdapterImpl<>(Author.class,authorFileReader,authorFileWriter);
...
IOAdapter<Book> bookAdapter =
new CSVAdapterImpl<>(Book.class,bookFileReader,bookFileWriter);
1. Описать интерфейс и имплементацию для работы с CSV-файлами любых сущностей.
В примере используются Book и Author.
Вы также можете придумать и свои типы.
int rowIndex = authorCsvAdapter.append(authorNew);
Author authorNewOpened = authorCsvAdapter.read(rowIndex);
Обратите внимание на конструкцию методов.
2. Проверить запись и чтение файлов при помощи полученного адаптера.
- Проверить чтение из определенной строки
- Проверить запись. Новая строка в файле должна соответствовать поданной в метод записи сущности
Author author = authorCsvAdapter.read(0);
assertEquals("Лев Николаевич Толстой",author.getName());
assertEquals("Ясная Поляна",author.getBirthPlace());
Author authorNew = new Author("Некоторый Автор", "Некоторый Город");
int rowIndex = authorCsvAdapter.append(authorNew);
Author authorNewOpened = authorCsvAdapter.read(rowIndex);
assertEquals("Некоторый Автор",author.getName());
assertEquals("Некоторый Город",author.getBirthPlace());
Copy of Занятие 4
By nikitamugen
Copy of Занятие 4
Работа с файловой системой. Потоки ввода/вывода. Обработка исключений.
- 411