如何按月过滤目录中的文件,如何按月对文件进行压缩,重命名,然后将其放置在包含zipfiles的文件夹中?

我的目录中包含1000多个文件,我需要根据月份对它们进行压缩,重命名并将压缩后的文件放在文件夹中。我通常会手动执行此操作,但是我厌倦了这种方式。我编写了一个程序来重命名文件并将其放置在新文件夹中,但是我不知道如何在Windows 10上按月过滤或使用Java压缩文件。

        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,len);
                }
                in.close();
                zos.closeEntry();
                zos.close();
                System.out.println("Done");
            } catch (IOException ex) {
                ex.printStackTrace();
            }

        }

    }

这就是我到目前为止所拥有的。该程序运行,但是没有给我所需的结果。它应该给我3个标有(基于lastModified()的zip文件夹2019_07、2019_08、2019_09,但我得到的是2019_06、2019_07、2019_08、2019_10,每个文件夹中只有1个文件。

hillingzhou 回答:如何按月过滤目录中的文件,如何按月对文件进行压缩,重命名,然后将其放置在包含zipfiles的文件夹中?

分组

您当前正在使用File API和旧的日期时间API(例如Date)。我会建议你:

  1. 使用java.nio.file API代替File API。
  2. 使用Java 8中添加的java.time API,而不是旧的日期时间API。
    • 这一点特别重要。创建新代码时,应不惜一切代价避免使用旧的日期时间API。

据我对您的问题的了解,您希望按文件的最后修改时间的年和月对文件进行分组,并将其放入自己的ZIP文件中。对于分组,我们可以使用YearMonth类和Files#walkFileTree(Path,Set,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 File System Provider(通过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实例属于同一提供者。

本文链接:https://www.f2er.com/3164661.html

大家都在问