你知道在Java应用程序中优化文件服务器的磁盘空间是非常重要的非功能性要求之一吗?如果管理得当,可以节省文件存储服务器上60%至70%的成本。因此,对于由Java Spring Boot API生成的数据文件进行压缩显得尤为非常重要。
Java提供了多个库来帮助我们压缩内容,同时也提供了本地文件操作来压缩数据文件。在本文中,我们使用本地方法来实现压缩。
我们创建一个实用程序,它可以打包在Java代码的任何位置,可以在你的微服务中的任何地方使用。你还可以将其放在共享库中,作为组织中所有微服务的实用程序公开。我们的实用程序将具有两个功能:
压缩给定的源文件
在压缩成功后删除原始文件
先决条件:
JDK ≥ 1.8 + Maven > 3.X + Spring Boot 2.X + Lombok + Common-IO
我们创建一个对象,该对象将具有基本参数用于压缩文件。在下面的代码中,我们创建了一个名为FileZipper类,它通过Lombok实现Builder和Getter功能。
@Builder(setterPrefix = "set") @Getter public class FileZipper { @NonNull private String sourceFilePath; @NonNull private String sourceFileName; @NonNull private String sourceFileExtension; @NonNull private String zippedFilePath; @NonNull private String zippedFileName; private boolean deleteSourceAfterZipped; }
现在,我们创建一个名为FileZippingService的Java服务类,它将根据用户输入压缩源文件。此服务类还具有文件删除功能,可以在文件压缩成功后删除源文件。
public class FileZippingService { private static final String DOT = "."; private static final String ZIP = ".zip"; private FileZippingService() { } static Logger logger = LoggerFactory.getLogger(FileZippingService.class); /** * Method to Zip a file * * @param fileZipper */ public static void zipExportFile(FileZipper fileZipper) { String sourceFileWithPath = fileZipper.getSourceFilePath().concat(fileZipper.getSourceFileName()).concat(DOT) .concat(fileZipper.getSourceFileExtension()); String zippedFileWithPath = fileZipper.getZippedFilePath().concat(fileZipper.getZippedFileName()).concat(ZIP); logger.info("Source File : {} will be zipped into {}", sourceFileWithPath, zippedFileWithPath); try { File fileToZip = new File(sourceFileWithPath); if (fileToZip.exists()) { FileOutputStream fos = new FileOutputStream(zippedFileWithPath); ZipOutputStream zipOut = new ZipOutputStream(fos); FileInputStream fis = new FileInputStream(fileToZip); ZipEntry zipEntry = new ZipEntry(fileToZip.getName()); zipOut.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while ((length = fis.read(bytes)) >= 0) { zipOut.write(bytes, 0, length); } zipOut.close(); fis.close(); fos.close(); logger.info("{} zipped successfully at {}", sourceFileWithPath, zippedFileWithPath); if (fileZipper.isDeleteSourceAfterZipped()) deleteFile(sourceFileWithPath); } } catch (IOException e) { logger.error("Error while Zipping the file", e); deleteFile(zippedFileWithPath); } } /** * Method to delete a file at given path * * @param fileToDelete */ private static void deleteFile(String fileToDelete) { File filetoDelete = new File(fileToDelete); if (filetoDelete.exists()) { if (FileUtils.deleteQuietly(filetoDelete)) { logger.info("{} deleted successfully.", fileToDelete); } else { logger.info("{} deletion unsuccessfull.", fileToDelete); } } else { logger.info("{} was not found for deletion.", fileToDelete); } } }
接下来我们通过运行Spring Boot应用程序来测试代码。在下面的Java文件中,你可以看到提供的源文件路径、名称和扩展名,从中需要读取文件;还提供了压缩文件的文件名以及压缩后需要存储的路径。此外,这里还设置了一个标志,用于决定是否在压缩后删除源文件。
@SpringBootApplication public class FileZippingApplication { public static void main(String[] args) { SpringApplication.run(FileZippingApplication.class, args); FileZipper fileZipper = FileZipper.builder() .setSourceFilePath("C:/Data/") .setSourceFileName("UserData") .setSourceFileExtension("xlsx") .setZippedFileName("ZippedUserData") .setZippedFilePath("C:/Data/") .setDeleteSourceAfterZipped(true) .build(); FileZippingService.zipExportFile(fileZipper); } }
上述代码的输出结果令人非常惊讶。在我们的一个业务应用程序中,有大量的CSV文件,大小一般在600MB到1 GB之间,占用消耗大量的磁盘空间,因为我们在一个小时内收到了1000多个请求。
但是,在使用上述代码压缩后,磁盘空间减少了85%,我们甚至可以通过电子邮件向客户发送文件。