Как фильтровать файлы в каталоге по месяцам, архивировать их по месяцам, переименовывать, помещать в папку, содержащую zip-файлы? - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть каталог с более чем 1000 файлами, и мне нужно сжать их в зависимости от месяца, переименовать их и поместить заархивированные файлы в папку. Я обычно делаю это вручную, но устал от этого. Я написал программу, которая переименовывает файлы и помещает их в новую папку, но я не знаю, как фильтровать по месяцам или архивировать их с помощью Java в Windows 10.

        String path = "C:\\\\Users\\\\srs\\\\Desktop\\\\Test\\notProcessed";

        File[] filelist = new File(path).listFiles();

        for (File file : filelist) {
            Date d = new Date(file.lastModified());
            Calendar c = Calendar.getInstance();
            c.setTime(d);
            int iyear = c.get(Calendar.YEAR);
            int imonth = c.get(Calendar.MONTH);
            String syear = Integer.toString(iyear);
            String smonth = Integer.toString(imonth);
            System.out.println(syear + "_" + smonth);
            String destpath = "C:\\\\Users\\\\srs\\\\Desktop\\\\Test\\notProcessed\\\\TestZip\\\\";
            byte[] buffer = new byte[1024];
            try {
                FileOutputStream fos = new FileOutputStream(destpath + syear + "_" + smonth + ".zip");
                ZipOutputStream zos = new ZipOutputStream(fos);
                System.out.println("Output to Zip : " + file);
                System.out.println("File Added : " + file.getAbsolutePath().toString());
                ZipEntry ze = new ZipEntry(file.getName());
                zos.putNextEntry(ze);
                FileInputStream in = new FileInputStream(file);
                int len;
                while ((len = in.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
                in.close();
                zos.closeEntry();
                zos.close();
                System.out.println("Done");
            } catch (IOException ex) {
                ex.printStackTrace();
            }

        }

    }

Так вот, что у меня естьдо сих пор. Программа работает, но она не дает мне требуемого результата. Это должно дать мне 3 почтовых папки с надписью (которые основаны на lastModified()) 2019_07, 2019_08, 2019_09, но я получаю 2019_06, 2019_07, 2019_08, 2019_10 только с одним файлом в каждой.

1 Ответ

0 голосов
/ 05 ноября 2019

Группировка

В настоящее время вы используете File API и старый API даты и времени (например, Date). Я собираюсь предложить вам:

  1. Используйте java.nio.file API вместо File API.
  2. Используйте 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-файлов:

  1. java.util.zip API.
  2. Поставщик файловой системы 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 принадлежат одному провайдеру. .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...