目前对这个文件的操作,我觉得得有专门的一个自己很熟练的工具来使用,目前为止,我觉得应该集多家的文件处理Util所长为自己所用
apache.common 里面的工具,还有就是spring中的工具,还有就是自己本身的一些工具
所有的这些工具都给自己
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.1</version></dependency>
1.创建文件
2.文件内容添加
3.文件迭代创建
4.本机的文件加锁
其中本机的文件锁其实必要性不是很大,因为通常情况下就直接采用分布式锁就可以了
场景:
1.单机多进程,竞争同一个资源
import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.isyscore.isc.neo.NeoMap;import lombok.experimental.UtilityClass;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.apache.commons.lang3.time.DateUtils;import org.quartz.*;import java.io.*;import java.lang.management.ManagementFactory;import java.net.HttpURLConnection;import java.net.URL;import java.nio.charset.Charset;import java.nio.charset.StandardCharsets;import java.nio.file.Files;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.Objects;import java.util.stream.Stream;/*** @author shizi* @since 2019/12/3 11:48 上午*/@Slf4j@UtilityClasspublic class FileUtil {private Charset CRYPTO_CHARSET = StandardCharsets.UTF_8;private static SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();private static Scheduler scheduler;static {try {scheduler = schedulerFactory.getScheduler();scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}/*** 获取文件*/public File getFile(String fileName) throws IOException {File file = new File(fileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}if (!file.exists()) {file.createNewFile();}file.setReadable(true);file.setWritable(true);return file;}/*** 获取文件夹类型的文件*/public File getDirectFile(String fileName) {File file = new File(fileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}if (!file.exists()) {file.mkdir();}file.setReadable(true);file.setWritable(true);return file;}@SuppressWarnings("all")public Boolean createFile(String fileName) throws IOException {File file = new File(fileName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}if (!file.exists() && file.createNewFile()) {return file.setReadable(true) && file.setWritable(true);}return false;}public Boolean exist(String fileFullPath){File file = new File(fileFullPath);return file.exists();}/*** 向文件中写入对应的文件*/public void writeFile(File file, String content) throws IOException {try (FileOutputStream outputStream = new FileOutputStream(file)) {outputStream.write(content.getBytes(CRYPTO_CHARSET));outputStream.flush();}}public void writeFile(String file, String content) throws IOException {try (FileOutputStream outputStream = new FileOutputStream(new File(file))) {outputStream.write(content.getBytes(CRYPTO_CHARSET));outputStream.flush();}}public BufferedReader readFile(File file) throws IOException {return Files.newBufferedReader(file.toPath(), CRYPTO_CHARSET);}public String readFromFile(File file) throws IOException {StringBuilder stringBuilder = new StringBuilder();try (BufferedReader bufferedReader = readFile(file)) {String line;while ((line = bufferedReader.readLine()) != null) {stringBuilder.append(line).append("\n");}}return stringBuilder.toString();}/*** 读取资源文件中的内容* @param cls 类所在的位置* @param resourceFileName 资源文件中的位置比如:/script/base.groovy,其中前面一定要有"/"* @return 文件的字符数据*/public String readFromResource(Class cls, String resourceFileName) throws IOException {StringBuilder stringBuilder = new StringBuilder();InputStream inputStream = cls.getResourceAsStream(resourceFileName);BufferedReader bufferedReader = null;try {bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = bufferedReader.readLine()) != null) {stringBuilder.append(line).append("\n");}} finally {inputStream.close();assert bufferedReader != null;bufferedReader.close();}return stringBuilder.toString();}/*** 通过文件的绝对路径读取文件信息*/public String read(String filePath) throws IOException {FileReader fileReader;StringBuilder stringBuilder = new StringBuilder();fileReader = new FileReader(filePath);char[] cbuf = new char[32];int hasRead = 0;while ((hasRead = fileReader.read(cbuf)) > 0) {stringBuilder.append(cbuf, 0, hasRead);}return stringBuilder.toString();}public FileInputStream readToStream(String filePath) throws IOException {File file = new File(filePath);if (file.exists()) {return new FileInputStream(file);}return null;}/*** 向绝对路径中的文件写入对应的数据信息*/public void write(String filePath, String content) throws IOException {writeFile(getFile(filePath), content);}public String readUrl(String FileName) throws IOException {String read;StringBuilder stringBuilder = new StringBuilder();try {URL url = new URL(FileName);HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();urlCon.setConnectTimeout(5000);urlCon.setReadTimeout(5000);BufferedReader br = new BufferedReader(new InputStreamReader(urlCon.getInputStream()));while ((read = br.readLine()) != null) {stringBuilder.append(read);}br.close();} catch (IOException e) {}return stringBuilder.toString();}public void appendFile(String filePath, List<String> content) {FileWriter fw = null;if (content == null || content.isEmpty()) {return;}try {//如果文件存在,则追加内容;如果文件不存在,则创建文件File file = getFile(filePath);if ((!file.exists()) &&(!file.createNewFile())) {throw new IOException("create file '" + filePath +"' failure.");}fw = new FileWriter(file, true);PrintWriter pw = new PrintWriter(fw);for (String str : content) {if(str != null && !"".equals(str)) {pw.println(str);}}pw.flush();fw.flush();pw.close();fw.close();} catch (IOException e) {e.printStackTrace();}}public void appendFile(String filePath, String content) {List<String> contents = new ArrayList<>();contents.add(content);appendFile(filePath, contents);}public boolean delete(String filePath) {return delete(new File(filePath));}public boolean delete(File file) {if (null == file || !file.exists()) {return false;}if (file.isFile()) {return file.delete();} else {File[] childFile = file.listFiles();if (null == childFile) {return false;}for (File fileMeta : childFile) {delete(fileMeta);}}return file.delete();}/*** 文件加锁* <p>* <ul>* <li>1.可重入</li>* <li>2.锁有过期时间</li>* <li>3.自动延长过期时间</li>* </ul>** @param lockFile 加锁对应的文件的路径* @return true:加锁成功,false:加锁失败*/public boolean lock(String lockFile) {try {File compressLock = new File(lockFile);if (compressLock.isDirectory()) {return false;}String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];String tid = String.valueOf(Thread.currentThread().getId());if (!compressLock.exists() && null != getFile(lockFile)) {NeoMap dataMap = NeoMap.of();dataMap.put("time", DateUtils.addMinutes(new Date(), -1).getTime());dataMap.put("pid", pid);dataMap.put("tid", tid);writeFile(compressLock, JSON.toJSONString(dataMap));startDelayThread(lockFile);return true;} else {String lockData = readFromFile(compressLock);JSONObject dataMap = JSONObject.parseObject(lockData);if (null == dataMap) {return false;}// 锁可重入if (dataMap.containsKey("pid") && dataMap.containsKey("tid")) {String pidCache = dataMap.getString("pid");String tidCache = dataMap.getString("tid");if (!StringUtils.isEmpty(pidCache) && pidCache.equals(pid) && !StringUtils.isEmpty(tidCache) && tidCache.equals(tid)) {// 重入后,顺便更新下下次时间dataMap.put("time", getNextTime());writeFile(compressLock, JSON.toJSONString(dataMap));return true;}}if (dataMap.containsKey("time")) {Long timeLong = dataMap.getLong("time");if (timeLong < System.currentTimeMillis()) {// 锁过期,则重新占有if (createFile(lockFile + "_lock")) {dataMap.put("time", getNextTime());dataMap.put("pid", pid);dataMap.put("tid", tid);writeFile(compressLock, JSON.toJSONString(dataMap));delete(lockFile + "_lock");return true;}return false;}}}} catch (IOException e) {log.error("lock exception", e);return false;}return false;}/*** 启动延期保护线程,20秒执行一次,每次向后默认延长1分钟*/private void startDelayThread(String filePath) {try {JobDetail job = JobBuilder.newJob(InnerJob.class).withIdentity(new JobKey(filePath)).usingJobData("filePath", filePath).build();Trigger trigger = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(30)).build();scheduler.scheduleJob(job, trigger);} catch (SchedulerException e) {e.printStackTrace();}}/*** 关闭延期保护线程*/private void closeDelayThread(String filePath) {try {scheduler.deleteJob(new JobKey(filePath));} catch (SchedulerException e) {e.printStackTrace();}}private Long getNextTime() {return DateUtils.addMinutes(new Date(), 1).getTime();}public boolean unlock(String lockFile) {File compressLock = new File(lockFile);if (compressLock.isDirectory()) {return false;}String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];String tid = String.valueOf(Thread.currentThread().getId());try {String lockData = readFromFile(compressLock);JSONObject dataMap = JSONObject.parseObject(lockData);if (null == dataMap) {return false;}if (dataMap.containsKey("pid") && dataMap.containsKey("tid")) {String pidCache = dataMap.getString("pid");String tidCache = dataMap.getString("tid");// 保证删除的是自己的if (!StringUtils.isEmpty(pidCache) && pidCache.equals(pid) && !StringUtils.isEmpty(tidCache) && tidCache.equals(tid)) {closeDelayThread(lockFile);return compressLock.delete();}}} catch (IOException e) {e.printStackTrace();}return false;}public class InnerJob implements Job {public InnerJob() {}@Overridepublic void execute(JobExecutionContext context) {String filePath = context.getJobDetail().getJobDataMap().getString("filePath");try {if (!exist(filePath)) {return;}String content = read(filePath);JSONObject contentObject = JSONObject.parseObject(content);// 默认向后延长1分钟contentObject.put("time", getNextTime());write(filePath, contentObject.toJSONString());} catch (IOException e) {e.printStackTrace();}}}}
