File工具总结
一、IO
1、按操作方式分类结构图
2、按操作对象分类结构图
3、IO流的分类
- 按照流的流向分,可以分为【输入流】与【输出流】。
- 按照操作单元划分,可以分为分为【字节流】与【字符流】。
- 按照流的角色划分可以分为【节点流】与【处理流】。
4、流的原理浅析
java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java Io流的40多个类都是从如下4个抽象类基类中派生出来的。
- InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
- OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
二、Path和Files
1、Path
- 创建一个Path
- File和Path之间的转换,File和URI之间的转换
- 获取Path的相关信息
- 移除Path中的冗余项
2、Files类
- Files.exists() 检测文件路径是否存在
- Files.createFile() 创建文件
- Files.createDirectories()和Files.createDirectory()创建文件夹
- Files.delete()方法 可以删除一个文件或目录
- Files.copy()方法可以吧一个文件从一个地址复制到另一个位置
- 获取文件属性
- 遍历一个文件夹
- Files.walkFileTree()遍历整个目录
3、文件路径
获取文件路径
1、class.getResource(path)
其中的参数path有两种形式,一种是以“/”开头的,另一种是不以"/"开头;
- 「以’/'开头的表示」:从项目的**根路径下去获取文件即classPath**目录下。
- 不以"/"开头:以该类对象所在位置**为根路径来进行查找的。
// 1.获取当前文件所在的路径
System.out.println(this.getClass().getResource("").getPath());
// 2.获取再 target 下 classpath 路径
System.out.println(this.getClass().getResource("/").getPath());
class.getResource()和class.getResourceAsStream()方式的使用在路径上是一致的。
2、ClassLoader.getResource(path)
// 3.也是获取 classpath 的绝对路径
System.out.println(Thread.currentThread().getContextClassLoader().getResource("").getPath());
// 4.也是获取 classpath 的绝对路径
System.out.println(this.getClass().getClassLoader().getResource("").getPath());
// 5.也是获取 classpath 的绝对路径
System.out.println(ClassLoader.getSystemResource("").getPath());
3、项目路径
//6.获取当前项目路径(此方法与 7 效果相同,但是可以将路径转为标准形式,会处理“.”和“..”)
System.out.println(new File("").getCanonicalPath());
// 7.获取项目绝对路径(不会处理“.”和“..”)
System.out.println(new File("").getAbsolutePath());
//8.user.dir
System.out.println(System.getProperty("user.dir"));
三、文件操作
1、上传文件
1、文件路径
2、文件名称
3、文件内容
4、保存文件的路径
2、下载【响应码 ResponseEntity】
1、文件的路径、名称、内容。
2、通过response写到浏览器只能够(响应头【文件名称】、响应体)
下载文件的几种方式
- 以流的形式下载【直接通过response write出】
response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
response.addHeader("Content-Length", "" + file.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
- 下载本地文件【先read文件,后在通过response write出】
// 下载本地文件
String fileName = "Operator.doc".toString(); // 文件的默认保存名
// 读到流中
InputStream inStream = new FileInputStream("c:/Operator.doc");// 文件的存放路径
// 设置输出的格式
response.reset();
response.setContentType("bin");
response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// 循环取出流中的数据
byte[] b = new byte[100];
int len;
try {while ((len = inStream.read(b)) > 0)response.getOutputStream().write(b, 0, len);inStream.close();
} catch (IOException e) {e.printStackTrace();
}
- 下载网络文件
- 支持在线打开的方式
3、MultipartFile转String
public static String readForSingleFile(MultipartFile multipartFile) {String text = null;try {int num;byte[] buffer = new byte[8192];ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();InputStream inputStream = multipartFile.getInputStream();while ((num = inputStream.read(buffer, 0, buffer.length)) > -1) {byteArrayOutputStream.write(buffer, 0, num);}byte[] bytes = byteArrayOutputStream.toByteArray();//将字节数组转化为字符串,UTF-8格式(容许中文)text = new String(bytes, "UTF-8");byteArrayOutputStream.close();inputStream.close();} catch (IOException e) {e.printStackTrace();log.error("压缩包读取异常");throw ExceptionFactory.service(ResponseCode.IO_EXCEPTION);}return text;
}
4、将文件保存在本地
/**** @param content* @return 文件绝对路径*/
public static String saveLocal(String content, String fileName) {// 保存文件到本地服务器,回传地址,文件名是db中的idFile father = new File(basePath);if (!father.exists()) {father.mkdirs();}String path = basePath;try {// basePath 要以/结尾 或为空path = path + fileName;File file = new File(path);if (!file.exists()) {file.createNewFile();}Writer writer = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), StandardCharsets.UTF_8);writer.write(content);writer.close();return file.getAbsolutePath();} catch (FileNotFoundException e) {e.printStackTrace();return null;} catch (IOException e) {e.printStackTrace();return null;}
}
5、生成.tar.gz文件
@PostMapping("/log/file")
@ResponseBody
@ApiOperation(value = "下载日志", notes = "选中单个日志文件下载,logB20Id")
@AccessPermit(one = {"006-001-002", "006-002-002"})
@ApiResponse(response = Response.class, code = 200, message = "成功")
public ResponseEntity<Resource> downloadLogFile(@RequestBody List<String> b20Ids) throws InterruptedException, IOException {ConcurrentHashMap<LogDO, String> filesContent = new ConcurrentHashMap<>();// 使用线程池来完成 现在是同步的操作CountDownLatch countDownLatch = new CountDownLatch(b20Ids.size());b20Ids.forEach(b20Id -> {threadPoolTaskExecutor.submit(() -> {LogDO log = monitorApplicationService.getLogDO(Long.valueOf(b20Id));try {String content = monitorApplicationService.downloadLog(Long.valueOf(b20Id));filesContent.put(log, content);countDownLatch.countDown();} catch (Exception e) {e.printStackTrace();filesContent.put(log, e.getMessage());monitorApplicationService.deleteLog(Long.valueOf(b20Id));countDownLatch.countDown();}});});countDownLatch.await();// gz文件 名称 TAR GZ 就是 .tar.gzString gzPath = "logs-" + RandomStringUtils.randomAlphabetic(8) + ".tar.gz";ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();TarArchiveOutputStream tarArchiveOutputStream = null;GZIPOutputStream gzipOutputStream = null;try {tarArchiveOutputStream = new TarArchiveOutputStream(byteArrayOutputStream);// 将所有文件打包成 tar文件try {for (Map.Entry<LogDO, String> entry : filesContent.entrySet()) {TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(entry.getKey().getName());tarArchiveEntry.setSize(entry.getValue().getBytes().length);tarArchiveOutputStream.putArchiveEntry(tarArchiveEntry);IOUtils.copy(new ByteArrayInputStream(entry.getValue().getBytes()), tarArchiveOutputStream);tarArchiveOutputStream.closeArchiveEntry();}} catch (IOException e) {e.printStackTrace();} finally {if (tarArchiveOutputStream != null) {tarArchiveOutputStream.flush();tarArchiveOutputStream.close();}}gzipOutputStream = new GZIPOutputStream(new FileOutputStream(gzPath));gzipOutputStream.write(byteArrayOutputStream.toByteArray());} finally {if (byteArrayOutputStream != null) {byteArrayOutputStream.close();}if (gzipOutputStream != null) {gzipOutputStream.flush();gzipOutputStream.close();}}File file = new File(gzPath);byte[] byteArray = Files.readAllBytes(Paths.get(file.getPath()));Long length = file.length();file.delete();ByteArrayResource resource = new ByteArrayResource(byteArray);return ResponseEntity.ok().header("Content-Disposition", "attachment;filename=" + gzPath)//设置响应头,告诉浏览器不要去解析,是以附件的形式打开.contentLength(length) //文件的长度.contentType(MediaType.APPLICATION_OCTET_STREAM)//设置响应头的类型,浏览器是以MIME的类型来识别类型。.body(resource);
}
6、读取Resource下的文件
public static String mockdata(String fileName) {StringBuilder result = new StringBuilder();//String path = Thread.currentThread().getContextClassLoader().getResource(fileName).getPath();File file = new File(path);try {//构造一个BufferedReader类来读取文件BufferedReader br = new BufferedReader(new FileReader(file));String s = null;//使用readLine方法,一次读一行while ((s = br.readLine()) != null) {result.append(System.lineSeparator() + s);}br.close();} catch (Exception e) {e.printStackTrace();}return result.toString();
}
7、常见文件操作
@Slf4j
@Component
public class FileUtil {@Autowiredprivate ContractInfoDAO contractInfoDAO;@Autowiredprivate ContractVersionInfoDAO contractVersionInfoDAO;private static String MINIO_URL;private static String MINIO_ACCESS_KEY;private static String MINIO_SECRET_KEY;private static String MINIO_CONTRACT_BUCKET;private static String MINIO_CONTRACT_ENTITY_BUCKET;private static final String basePath = "";private static boolean SCHEDULING_OPEN;@Value("${stdb.minio.url}")public void setMinioUrl(String url) {FileUtil.MINIO_URL = url;}@Value("${stdb.minio.accesskey}")public void setMinioAccessKey(String accessKey) {FileUtil.MINIO_ACCESS_KEY = accessKey;}@Value("${stdb.minio.secretkey}")public void setMinioSecretKey(String secretKey) {FileUtil.MINIO_SECRET_KEY = secretKey;}@Value("${minio.contract.bucket}")public void setMinioContractBucket(String contractBucket) {FileUtil.MINIO_CONTRACT_BUCKET = contractBucket;}@Value("${minio.contract.entity.bucket}")public void setMinioContractEntityBucket(String contractEntityBucket) {FileUtil.MINIO_CONTRACT_ENTITY_BUCKET = contractEntityBucket;}@Value("${scheduling.open}")public void setSchedulingOpen(boolean schedulingOpen) {FileUtil.SCHEDULING_OPEN = schedulingOpen;}public static String readForSingleFile(MultipartFile multipartFile) {String text = null;try {int num;byte[] buffer = new byte[8192];ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();InputStream inputStream = multipartFile.getInputStream();while ((num = inputStream.read(buffer, 0, buffer.length)) > -1) {byteArrayOutputStream.write(buffer, 0, num);}byte[] bytes = byteArrayOutputStream.toByteArray();//将字节数组转化为字符串,UTF-8格式(容许中文)text = new String(bytes, "UTF-8");byteArrayOutputStream.close();inputStream.close();} catch (IOException e) {e.printStackTrace();log.error("压缩包读取异常");throw ExceptionFactory.service(ResponseCode.IO_EXCEPTION);}return text;}/*** 压缩文件** @param map* @return* @throws IOException*/public static ByteArrayOutputStream compress(Map<String, byte[]> map) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream);Set<Map.Entry<String, byte[]>> entries = map.entrySet();for (Map.Entry<String, byte[]> entry : entries) {zipOut.putNextEntry(new ZipEntry(entry.getKey()));zipOut.write(entry.getValue());}zipOut.close();return byteArrayOutputStream;}/*** 将文件保存在指定bucket中** @param filePath* @param content* @param bucket* @return*/public static String saveFile(String filePath, String content, String bucket) {// 将文件上传至minio// 保存文件到本地服务器,回传地址,文件名是db中的idFile father = new File(basePath);if (!father.exists()) {father.mkdirs();}String path = basePath;try {// basePath 要以/结尾 或为空path = path + filePath;File file = new File(path);if (!file.exists()) {file.createNewFile();}Writer writer = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), StandardCharsets.UTF_8);writer.write(content);writer.close();// 创建minio客户端MinioClient minioClient = new MinioClient(MINIO_URL, MINIO_ACCESS_KEY, MINIO_SECRET_KEY);// 判断bucket是否存在,不存在则创建boolean isExist = minioClient.bucketExists(bucket);if (!isExist) {minioClient.makeBucket(bucket);}// 单合约相关文件到miniolog.debug("上传文件名:" + path);InputStream inputStream = new FileInputStream(path);PutObjectOptions putObjectOptions = new PutObjectOptions(inputStream.available(), -1);minioClient.putObject(bucket, path, inputStream, putObjectOptions);file.delete();} catch (MinioException | NoSuchAlgorithmException | InvalidKeyException | IOException e) {log.error("upload contract to minio err: ", e);throw ExceptionFactory.service(ResponseCode.CONTRACT_UPLOAD_TO_MINIO_FAIL);}return path;}/*** 构造一个文件并将文件上传至minIO** @param filePath 文件绝对路径 带后缀* @param content 文件的内容* @return 文件的保存的路径*/public static String saveFile(String filePath, String content) {// 将文件上传至minio// 保存文件到本地服务器,回传地址,文件名是db中的idFile father = new File(basePath);if (!father.exists()) {father.mkdirs();}String path = basePath;try {// basePath 要以/结尾 或为空path = path + filePath;File file = new File(path);if (!file.exists()) {file.createNewFile();}Writer writer = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), StandardCharsets.UTF_8);writer.write(content);writer.close();// 创建minio客户端MinioClient minioClient = new MinioClient(MINIO_URL, MINIO_ACCESS_KEY, MINIO_SECRET_KEY);// 判断bucket是否存在,不存在则创建boolean isExist = minioClient.bucketExists(MINIO_CONTRACT_BUCKET);if (!isExist) {minioClient.makeBucket(MINIO_CONTRACT_BUCKET);}// 单合约相关文件到miniolog.debug("上传文件名:" + path);InputStream inputStream = new FileInputStream(path);PutObjectOptions putObjectOptions = new PutObjectOptions(inputStream.available(), -1);minioClient.putObject(MINIO_CONTRACT_BUCKET, path, inputStream, putObjectOptions);file.delete();} catch (MinioException | NoSuchAlgorithmException | InvalidKeyException | IOException e) {log.error("upload contract to minio err: ", e);throw ExceptionFactory.service(ResponseCode.CONTRACT_UPLOAD_TO_MINIO_FAIL);}return path;}/*** 将文件保存在本地** @param content* @return 文件绝对路径*/public static String saveLocal(String content, String fileName) {// 保存文件到本地服务器,回传地址,文件名是db中的idFile father = new File(basePath);if (!father.exists()) {father.mkdirs();}String path = basePath;try {// basePath 要以/结尾 或为空path = path + fileName;File file = new File(path);if (!file.exists()) {file.createNewFile();}Writer writer = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), StandardCharsets.UTF_8);writer.write(content);writer.close();return file.getAbsolutePath();} catch (FileNotFoundException e) {e.printStackTrace();return null;} catch (IOException e) {e.printStackTrace();return null;}}/*** minIO直接删除 filePath(包含后缀) 的文件** @param filePath 其实是文件名* @return 成功/失败*/public static boolean deleteFile(String filePath) {try {// 创建minio客户端MinioClient minioClient = new MinioClient(MINIO_URL, MINIO_ACCESS_KEY, MINIO_SECRET_KEY);minioClient.removeObject(MINIO_CONTRACT_BUCKET, filePath);return true;} catch (MinioException | NoSuchAlgorithmException | InvalidKeyException | IOException e) {log.error("delete contract from minio err: ", e);throw ExceptionFactory.service(ResponseCode.CONTRACT_DELETE_FAIL);}}/*** 先删除原文件,后存入新文件** @param oriFilePath* @param newFilePath* @param content* @return 更新后的文件绝对路径*/public static String updateFile(String oriFilePath, String newFilePath, String content) {// 本质是替换文件内容deleteFile(oriFilePath);return saveFile(newFilePath, content);}/*** 读取文件的内容** @param filePath 文件的绝对路径* @return*/public static String readFileContent(String filePath, String bucket) {try {// 创建minio客户端MinioClient minioClient = new MinioClient(MINIO_URL, MINIO_ACCESS_KEY, MINIO_SECRET_KEY);// 从minio获取文件流InputStream inputStream = minioClient.getObject(bucket, filePath);ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();byte[] buf = new byte[8192];int num;while ((num = inputStream.read(buf, 0, buf.length)) > -1) {byteArrayOutputStream.write(buf, 0, num);}inputStream.close();byteArrayOutputStream.close();return new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8);} catch (MinioException | NoSuchAlgorithmException | InvalidKeyException | IOException e) {log.error("download contract from minio err: ", e);throw ExceptionFactory.service(ResponseCode.CONTRACT_DOWNLOAD_FAIL);}}/*** 归档 .tar 保证文件存在** @param entry 文件路径* @return* @throws IOException* @date 2017年5月27日下午1:48:23*/public static String archive(String entry) throws IOException {File file = new File(entry);TarArchiveOutputStreamtos = new TarArchiveOutputStream(new FileOutputStream(file.getAbsolutePath() + ".tar"));String base = file.getName();if (file.isDirectory()) {archiveDir(file, tos, base);} else {archiveHandle(tos, file, base);}tos.close();return file.getAbsolutePath() + ".tar";}/*** 递归处理,准备好路径** @param file* @param tos* @param basePath* @throws IOException*/private static void archiveDir(File file, TarArchiveOutputStream tos, String basePath) throws IOException {File[] listFiles = file.listFiles();for (File fi : listFiles) {if (fi.isDirectory()) {archiveDir(fi, tos, basePath + File.separator + fi.getName());} else {archiveHandle(tos, fi, basePath);}}}/*** 具体归档处理(文件)** @param tos* @param fi* @param basePath* @throws IOException*/private static void archiveHandle(TarArchiveOutputStream tos, File fi, String basePath) throws IOException {TarArchiveEntry tEntry = new TarArchiveEntry(basePath + File.separator + fi.getName());tEntry.setSize(fi.length());tos.putArchiveEntry(tEntry);BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fi));byte[] buffer = new byte[1024];int read = -1;while ((read = bis.read(buffer)) != -1) {tos.write(buffer, 0, read);}bis.close();tos.closeArchiveEntry();//这里必须写,否则会失败}/*** 文件转换成base64的形式** @param file* @return*/public static String file2Base64(File file) {if (file == null) {return null;}String base64 = null;FileInputStream fin = null;try {fin = new FileInputStream(file);byte[] buff = new byte[fin.available()];fin.read(buff);base64 = Base64.getEncoder().encodeToString(buff);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fin != null) {try {fin.close();} catch (IOException e) {e.printStackTrace();}}}return base64;}/*** @param sources 源文件集合* @param outPath 目标文件名称 无后缀的 例子 G:\backup\logstash-2020.04.22* @return 返回压缩结果* @功能描述 压缩tar.gz 文件*/public static String gzCompress(List<String> sources, String outPath) throws IOException {// gz文件 名称 TAR GZ 就是 .tar.gzString gzPath = outPath + ".tar.gz";ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();TarArchiveOutputStream tarArchiveOutputStream = null;GZIPOutputStream gzipOutputStream = null;try {tarArchiveOutputStream = new TarArchiveOutputStream(byteArrayOutputStream);// 将所有文件打包成 tar文件try {for (String source : sources) {File file = new File(source);tarArchiveOutputStream.putArchiveEntry(new TarArchiveEntry(file, file.getName()));IOUtils.copy(new FileInputStream(file), tarArchiveOutputStream);tarArchiveOutputStream.closeArchiveEntry();}} catch (IOException e) {e.printStackTrace();} finally {if (tarArchiveOutputStream != null) {tarArchiveOutputStream.flush();tarArchiveOutputStream.close();}}gzipOutputStream = new GZIPOutputStream(new FileOutputStream(gzPath));gzipOutputStream.write(byteArrayOutputStream.toByteArray());} finally {if (byteArrayOutputStream != null) {byteArrayOutputStream.close();}if (gzipOutputStream != null) {gzipOutputStream.flush();gzipOutputStream.close();}}return gzPath;}@Scheduled(cron = "0 0 1 * * ?")public void clear() throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {log.info("开始清理minio合约文件。。。");if (true) {// 创建minio客户端MinioClient minioClient = new MinioClient(MINIO_URL, MINIO_ACCESS_KEY, MINIO_SECRET_KEY);if (minioClient.bucketExists(MINIO_CONTRACT_BUCKET)) {List<ContractInfoPO> all = contractInfoDAO.findAll();List<String> objects = new ArrayList<>();all.forEach(contractInfoPO -> {objects.add(contractInfoPO.getContentPath());});Iterable<Result<Item>> results = minioClient.listObjects(MINIO_CONTRACT_BUCKET);for (Result<Item> itemResult : results) {String objectName = itemResult.get().objectName();if (!objects.contains(objectName)) {minioClient.removeObject(MINIO_CONTRACT_BUCKET, objectName);}}}if (minioClient.bucketExists(MINIO_CONTRACT_ENTITY_BUCKET)) {List<ContractVersionInfoPO> all = contractVersionInfoDAO.findAll();List<String> objects = new ArrayList<>();all.forEach(contractInfoPO -> {objects.add(contractInfoPO.getContentPath());});Iterable<Result<Item>> results = minioClient.listObjects(MINIO_CONTRACT_ENTITY_BUCKET);for (Result<Item> itemResult : results) {String objectName = itemResult.get().objectName();if (!objects.contains(objectName)) {minioClient.removeObject(MINIO_CONTRACT_ENTITY_BUCKET, objectName);}}}}}
}