Группировка
В настоящее время вы используете File
API и старый API даты и времени (например, Date
). Я собираюсь предложить вам:
- Используйте
java.nio.file
API вместо File
API. - Используйте
java.time
API, добавленный в Java 8 вместостарого API даты и времени. - Это имеет особое значение. При создании нового кода следует избегать старого API даты и времени любой ценой.
Из того, что я понимаю по вашему вопросу, вы хотите сгруппировать файлы по году и месяцу. их последнее измененное время и поместите их в свой собственный файл ZIP. Для группировки мы можем использовать класс YearMonth
и метод Files#walkFileTree(Path,Set,int,FileVisitor)
. Вот пример:
Map<YearMonth, List<Path>> groupFiles(Path dir, int depth) throws IOException {
Map<YearMonth, List<Path>> result = new HashMap<>();
Files.walkFileTree(dir, Set.of(), depth, new SimpleFileVisitor<>() {
private final ZoneId systemZone = ZoneId.systemDefault();
private final YearMonth currentYearMonth = YearMonth.now();
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
YearMonth yearMonth = getYearMonthOfLastModifiedTime(attrs);
if (yearMonth.isBefore(currentYearMonth)) {
result.computeIfAbsent(yearMonth, k -> new ArrayList<>()).add(file);
}
return FileVisitResult.CONTINUE;
}
private YearMonth getYearMonthOfLastModifiedTime(BasicFileAttributes attrs) {
Instant lastModInstant = attrs.lastModifiedTime().toInstant();
return YearMonth.from(LocalDate.ofInstant(lastModInstant, systemZone));
}
});
return result;
}
Выше используется системный часовой пояс по умолчанию. Я также добавляю опцию для указания максимальной глубины, к которой нужно обращаться при поиске в дереве файлов (с корнем в dir
). Если вы хотите только найти файлы, которые являются прямыми потомками dir
, используйте 1
. Кроме того, в случае, когда максимальная глубина всегда будет 1
, вы можете использовать DirectoryStream
вместо FileVisitor
.
Обратите внимание, что для получения Path
Например, вы можете позвонить File#toPath()
. Однако, поскольку мы пытаемся избежать класса File
, было бы лучше использовать Path#of(String,String...)
(или, если не используется Java 11+, Paths#get
). Например:
Path path = Path.of("C:", "Users", "srs", "Desktop", "Test", "notProcessed");
Вышеуказанное Path
будет связано со значением по умолчанию FileSystem
.
Создание ZIP
После группировки файлов. к YearMonth
времени их последнего изменения вам нужно поместить их в ZIP-файл. В JDK есть по крайней мере два варианта создания ZIP-файлов:
-
java.util.zip
API. - Поставщик файловой системы ZIP (используется через
java.nio.file
API).
Первый вариант, как мне кажется, дает вам больший контроль над процессом сжатия. Однако второй вариант позволяет вам прозрачно обращаться с ZIP-файлом так же, как и с любой другой файловой системой. Для этого ответа я приведу пример второго варианта:
List<Path> compressFiles(Path zipDir, Map<YearMonth, List<Path>> groupedFiles)
throws IOException {
List<Path> zipFiles = new ArrayList<>(groupedFiles.size());
DateTimeFormatter zipFilenameFormatter = DateTimeFormatter.ofPattern("uuuu_MM'.zip'");
for (Map.Entry<YearMonth, List<Path>> entry : groupedFiles.entrySet()) {
Path zipFile = zipDir.resolve(zipFilenameFormatter.format(entry.getKey()));
zipFiles.add(zipFile);
URI uri = URI.create("jar:" + zipFile.toUri());
Map<String, ?> env = Map.of("create", Boolean.toString(Files.notExists(zipFile)));
try (FileSystem zipFileSystem = FileSystems.newFileSystem(uri, env)) {
Path zipRoot = zipFileSystem.getRootDirectories().iterator().next();
for (Path source : entry.getValue()) {
Files.move(source, zipRoot.resolve(source.getFileName().toString()));
}
}
}
return zipFiles;
}
Я использую DateTimeFormatter
, потому что ваш вопрос указывает, что имена файлов ZIP должны быть year_month.zip
(с подчеркиванием). Метод YearMonth#toString()
вернет year-month
(с тире), поэтому DateTimeFormatter
используется для разделения года и месяца на подчеркивание. Если вы не возражаете против тире, вы можете создать имя файла, просто используя yearMonth.toString() + ".zip"
.
. Выше указано, что Files#move(Path,Path,CopyOption...)
используется для фактического добавления файла в ZIP-файл. Файл будет сжат. Обратите внимание, что это не удастся, если запись с таким именем уже существует в файле ZIP, но вы можете изменить это с помощью REPLACE_EXISTING
. Вызов #move
удалит исходный файл;если это нежелательно, рассмотрите возможность использования Files#copy
.
Примечание. Я использую Path#resolve(String)
вместо Path#resolve(Path)
, поскольку, по моему опыту, два экземпляра Path
принадлежат одному провайдеру. .