Archiver (9)
Теперь займемся другой, не менее важной частью нашего архиватора. Очень часто пользователь хочет
создать архив не из одного файла, а из целой папки. Тогда архивация сводится к поочередному
добавлению элемента ZipEntry для каждого файла в архив.
Нам нужно написать класс FileManager для получения списка всех файлов в какой-то папке. У него должен быть конструктор, который будет принимать путь Path rootPath, указывающий на корень (папку, файлы в которой нас интересуют) и метод List<Path> getFileList(), который должен возвращать список относительных путей всех файлов, которые находятся по пути rootPath, включая файлы в подпапках.
Директория, в которой будем искать, может задаваться только один раз в конструкторе. Поэтому, прямо в конструкторе мы сразу можем сформировать список файлов (их относительных путей), сохранив его в переменную класса List<Path> fileList.
Осталось только решить, как нам собрать все файлы, даже те, которые могут быть в папке, которая в папке, которая в папке, которая в интересующей нас папке. Фух, чуть не вошел рекурсию. Хотя нам-то она и поможет! Сделаем метод collectFileList(Path path), который будет складывать в переменную класса fileList все файлы, обнаруженные внутри переданного пути path, вызывая сам себя для всех объектов, в обнаруженных директориях.
1. Создай класс FileManager с конструктором FileManager(Path rootPath) throws IOException
2. Объяви и проинициализируй приватные переменные класса:
2.1. Path rootPath – корневой путь директории, файлы которой нас интересуют
2.2. List<Path> fileList – список относительных путей файлов внутри rootPath
3. Создай геттер для fileList
4. Реализуй метод void collectFileList(Path path) throws IOException, который должен:
4.1. Проверить, если переданный путь path является обычным файлом (используй метод Files.isRegularFile), то получить его относительный путь относительно rootPath и добавить его в список fileList.
4.2. Если переданный путь path, является директорией (узнать это поможет метод Files.isDirectory), то пройтись по всему содержимому директории и вызвать collectFileList(Path path), передав в path обнаруженные элементы.
Пройтись по всему содержимому директории можно предварительно получив DirectoryStream с помощью метода newDirectoryStream класса Files. Не забудь закрыть созданный DirectoryStream.
5. Добавь вызов метода collectFileList(rootPath) в конструкторе FileManager.
6. Примени все свои знания об инкапсуляции к этому классу.
Выполняя это задание, ты написал алгоритм, который обходит дерево файлов. Но в Java есть специальный интерфейс FileVisitor для этих целей. Очень рекомендую разобраться как им пользоваться.
Требования:
1. В корне задачи должен быть создан класс FileManager c конструктором FileManager(Path rootPath) throws IOException.
2. В классе FileManager должны быть созданы приватные поля Path rootPath и List fileList, которые инициализируются в конструкторе.
3. В классе FileManager должен быть создан getter для поля fileList.
4. В классе FileManager нужно реализовать приватный метод void collectFileList(Path path) throws IOException согласно заданию.
5. Нужно добавить вызов метода collectFileList(rootPath) в конструктор FileManager.
package com.javarush.task.task31.task3110;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
public class FileManager {
private Path rootPath;
private List<Path> fileList;
FileManager(Path rootPath) throws IOException {
this.rootPath = rootPath;
this.fileList = new LinkedList<>();
this.collectFileList(rootPath);
}
public List<Path> getFileList() {
return this.fileList;
}
public void collectFileList(Path path) throws IOException {
if(Files.isRegularFile(path)) {
fileList.add(path.relativize(rootPath));
}
else if(Files.isDirectory(path)) {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
for(Path stream : directoryStream) {
if(Files.isRegularFile(stream)) {
fileList.add(stream.relativize(rootPath));
}
else if(Files.isDirectory(stream)) {
this.collectFileList(stream);
}
}
directoryStream.close();
}
}
}
package com.javarush.task.task31.task3110;
import com.javarush.task.task31.task3110.exception.WrongZipFileException;
import java.io.IOException;
public class Archiver {
public static void main(String[] args) throws IOException {
Operation operation = null;
do {
try {
operation = askOperation();
CommandExecutor.execute(operation);
} catch (WrongZipFileException e) {
ConsoleHelper.writeMessage("Вы не выбрали файл архива или выбрали неверный файл.");
} catch (Exception e) {
ConsoleHelper.writeMessage("Произошла ошибка. Проверьте введенные данные.");
}
} while (operation != Operation.EXIT);
}
public static Operation askOperation() throws IOException {
ConsoleHelper.writeMessage("");
ConsoleHelper.writeMessage("Выберите операцию:");
ConsoleHelper.writeMessage(String.format("\t %d - упаковать файлы в архив", Operation.CREATE.ordinal()));
ConsoleHelper.writeMessage(String.format("\t %d - добавить файл в архив", Operation.ADD.ordinal()));
ConsoleHelper.writeMessage(String.format("\t %d - удалить файл из архива", Operation.REMOVE.ordinal()));
ConsoleHelper.writeMessage(String.format("\t %d - распаковать архив", Operation.EXTRACT.ordinal()));
ConsoleHelper.writeMessage(String.format("\t %d - просмотреть содержимое архива", Operation.CONTENT.ordinal()));
ConsoleHelper.writeMessage(String.format("\t %d - выход", Operation.EXIT.ordinal()));
return Operation.values()[ConsoleHelper.readInt()];
}
}