20230727-随笔

目录

  • List删除满足条件的元素,并且避免索引错误或并发修改异常常用方法
    • 使用迭代器删除元素
    • 通过逆向循环删除元素
    • Java8+ 的 removeIf()方法
  • 获取不到日志内容问题排查
    • 尝试解决
    • 最终解决

List删除满足条件的元素,并且避免索引错误或并发修改异常常用方法

使用迭代器删除元素

List list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {String element = iterator.next();if (element.equals("B")) {iterator.remove(); // 使用迭代器的 remove() 方法删除元素}
}

通过逆向循环删除元素

List list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (int i = list.size() - 1; i >= 0; i--) {if (list.get(i).equals("B")) {list.remove(i); // 通过逆向循环删除元素}
}

Java8+ 的 removeIf()方法

  • 简单的,使用 Lambda 表达式
List list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.removeIf(element -> element.equals("B"));
  • 复杂的,通过使用匿名类实现 Predicate 接口的方式
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
// 假如 List<Test> tests,则为new Predicate<Test>()
list.removeIf(new Predicate<String>() {@Overridepublic boolean test(String element) {// 在这里编写复杂的逻辑来判断是否删除元素// 返回 true 表示删除该元素,返回 false 表示保留该元素return element.startsWith("A") || element.endsWith("D");}
});

获取不到日志内容问题排查

通过FileUtils.readFileToString()读取日志文件获取文件内容,日志文件有数据,但是获取不到内容,可能原因:

  • 文件路径问题:请确保logFile参数指定的文件路径是正确的路径,并且可以访问该文件。您可以在代码中添加一些调试语句,输出logFile的路径,然后验证该路径是否正确。
  • 文件读取权限:确保您正在以足够的权限运行代码,以便能够读取指定的日志文件。如果您在一个受限制的环境中运行代码,则可能需要提升您的权限或更改文件的权限设置。
  • 文件内容编码问题:如果日志文件使用了特定的编码方式进行编码(例如UTF-8),请确保在使用FileUtils.readFileToString()时指定正确的编码方式。可以尝试使用FileUtils.readFileToString(logFile, “UTF-8”)来明确指定编码方式。
  • 文件访问冲突:如果您的代码与其他程序同时访问该日志文件,可能发生访问冲突或文件锁定导致无法读取文件内容。在调试期间,确保没有其他程序或进程锁定或占用了该日志文件。

尝试解决

  • 改成异步方法:日志依然读取不到,但是作业状态确实是完结状态,日志应该已经写完了(springboot异步方法配置:启动类添加@EnableAsync,异步方法上添加@Async注解
  • 判断文件写入完成后再进行读取操作:依然无效,而且假如中间有几秒没有写入日志,但是写文件并没有结束,容易误判结束
import java.io.File;public class LogFileReader {private static final int CHECK_INTERVAL_MS = 1000; // 检查间隔时间,单位为毫秒public static void main(String[] args) {String filePath = "path/to/logfile.txt"; // 替换为您的日志文件路径File logFile = new File(filePath);// 获取初始文件长度和修改时间long initialSize = logFile.length();long lastModified = logFile.lastModified();while (true) {// 等待指定时间间隔try {Thread.sleep(CHECK_INTERVAL_MS);} catch (InterruptedException e) {e.printStackTrace();}// 检查文件是否发生变化long currentSize = logFile.length();long currentModified = logFile.lastModified();if (currentSize == initialSize && currentModified == lastModified) {// 文件大小和修改时间未发生变化,文件写入完成String logContent = FileUtils.readFileToString(logFile, "UTF-8");System.out.println(logContent);break; // 退出循环}// 更新初始文件长度和修改时间initialSize = currentSize;lastModified = currentModified;}}}
  • 替换FileUtils.readFileToString(),通过BufferedReader读取日志:BufferedReader 和 FileReader 来逐行读取文件的内容。通过调用 readLine() 方法,可以一次读取一行内容,并将其存储到 line 变量中。然后可以对每行内容进行处理,例如打印出来或进行其他操作。使用这种方式,即使文件未完全写入,也能读取到已经写入的部分内容。但是结果是依然读取不到。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;public class LogFileReader {public static void main(String[] args) {String filePath = "path/to/logfile.txt"; // 替换为您的日志文件路径File logFile = new File(filePath);try (BufferedReader reader = new BufferedReader(new FileReader(logFile))) {String line;while ((line = reader.readLine()) != null) {// 处理每行日志内容System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}}

最终解决

没有调用项目中日志处理类的end()方法导致的。对于BufferedReader来说,在文件正在写入的过程中,它是可以读取到已经写入部分内容的。之所以依然查看不到日志内容,是因为没有调用 end() 方法来完成日志的写入操作和关闭文件流的操作,可能导致读取不到已经写入的内容:

  • 写入缓冲区未刷新:使用FileWriter来写入文件,而FileWriter内部使用了写入缓冲区,它会先将数据写入缓冲区,然后根据一定条件将缓冲区的数据刷新到文件中。如果没有调用end()方法,缓冲区的数据可能还未被刷新到文件中,从而导致BufferedReader读取不到正确的文件内容。
  • 文件流未关闭: 在调用end()方法时,会关闭文件流(FileWriter),关闭文件流会将缓冲区的剩余数据刷新到文件中,并释放系统资源。如果没有调用end()方法关闭文件流,可能会导致缓冲区中的数据没有被刷新到文件中,从而无法读取到正确的文件内容。

以下为日志处理类源码,供参考分析:

import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 日志处理器.*/
@Slf4j
@Component
public class LogHandler {private static Map<Long, List<String>> logMap = new HashedMap();private static Map<Long, FileWriter> fileWriterMap = new HashMap<>();private static String taskLogPath;@PostConstructpublic void init() {write();}@PreDestroypublic void destory() {fileWriterMap.forEach((batchId, fw) -> {try {fw.flush();fw.close();} catch (IOException e) {log.error("关闭流失败:{}", e);}});}public static synchronized void start(Long batchId) {try {if (logMap.containsKey(batchId)) {log.info("已存在批次号:{}的任务!", batchId);return;}File logFile = new File(getLogPath(batchId));if (logFile.exists()) {log.info("批次号:{}已存在日志文件,不能重复提交!", batchId);return;}logFile.createNewFile();logMap.put(batchId, new ArrayList<String>());fileWriterMap.put(batchId, new FileWriter(logFile, true));} catch (Exception e) {log.error("批次号:{}开始记录任务失败:{}", batchId, e);}}/*** 记录日志.*/public static void log(Long batchId, String logContent) {if (null != logMap.get(batchId)) {logMap.get(batchId).add(DateUtils.formatDateTime(DateUtils.now()) + " 批次号:{" + batchId + "} " + logContent);}}/*** 记录异常.*/public static void exception(Long batchId, Exception e) {if (null != logMap.get(batchId)) {logMap.get(batchId).add(DateUtils.formatDateTime(DateUtils.now()) + " " + Throwables.getStackTraceAsString(e));}}/*** 日志记录到文件中.*/private static void write() {Thread logWriteThread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {logMap.forEach((batchId, logContentList) -> {if (CollectionUtils.isEmpty(logContentList)) {return;}try {FileWriter fw = fileWriterMap.get(batchId);if (null != fw) {writeLog2File(fw, logContentList, true);logContentList.clear();}} catch (Exception e) {log.error("批次号为:{}的日志写入文件报错:{}", batchId, e);}});sleep(15);}}});logWriteThread.start();}/*** 该batchId的日志记录结束.*/public static synchronized void end(Long batchId) {if (!fileWriterMap.containsKey(batchId)) {log.info("批次号为:{}的输出流不存在", batchId);return;}FileWriter fw = fileWriterMap.get(batchId);try {List<String> logContentList = logMap.get(batchId);if (CollectionUtils.isNotEmpty(logContentList)) {try {writeLog2File(fw, logContentList, true);logContentList = null;} catch (Exception e) {log.error("批次号为:{}的日志写入文件报错:{}", batchId, e);}}logMap.remove(batchId);fileWriterMap.remove(batchId);} finally {try {fw.close();} catch (IOException e) {log.error("关闭流错误:{}", e);}}}private static void writeLog2File(FileWriter fw, List<String> logContentList, boolean flush) throws Exception {for (String logContent : logContentList) {fw.write(logContent);fw.write("\r\n");}if (flush) {fw.flush();}}public static String getLogPath(Long batchId) {return taskLogPath + batchId + ".log";}private static void sleep(long timeOut) {try {Thread.sleep(timeOut * 1000);} catch (InterruptedException e) {log.error("sleep error:{}", e);}}@Value("${log_path}")public void setTaskLogPath(String taskLogPath) {LogHandler.taskLogPath = taskLogPath;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/15014.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

排序算法汇总

每日一句&#xff1a;你的日积月累终会成为别人的望尘莫及 目录 常数时间的操作 选择排列 冒泡排列 【异或运算】 面试题&#xff1a; 1&#xff09;在一个整形数组中&#xff0c;已知只有一种数出现了奇数次&#xff0c;其他的所有数都出现了偶数次&#xff0c;怎么找到…

51单片机IO口控制

51单片机IO口控制 1.点亮LED灯 原理&#xff1a;根据电路图&#xff0c;指向IO口的引脚&#xff1b;拉低电平&#xff0c;灯亮、 如图&#xff1a; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zfco4IjK-1690308697530)(C:/Users/xie19/Pictur…

C++基础篇(一)常用关键字及示例

一、C常见关键词 1、auto auto: 自动类型推断。它可以让编译器根据变量的初始值自动推断出变量的类型。例如&#xff1a; auto x 42; // x 的类型为 int auto y 3.14; // y 的类型为 double2、decltype decltype: 类型推断。它可以根据表达式的类型推断出一个类型。例如&…

面试之CurrentHashMap的底层原理

首先回答HashMap的底层原理? HashMap是数组链表组成。数字组是HashMap的主体&#xff0c;链表则是主要为了解决哈希冲突而存在的。要将key 存储到&#xff08;put&#xff09;HashMap中&#xff0c;key类型实现必须计算hashcode方法&#xff0c;默认这个方法是对象的地址。接…

input元素中的form属性有什么用?

在HTML中&#xff0c;input元素的form属性用于指定该输入字段所属的表单&#xff08;form元素&#xff09;。通过将input元素的form属性设置为相应的表单的id值&#xff0c;可以将输入字段与表单进行关联。 这个属性对于两个主要目的非常有用&#xff1a; 表单关联&#xff1…

【应用层】Http协议总结

文章目录 一、续->Http协议的学习 1.http请求中的get方法和post方法 2.http的状态码 3.http的报头 4.长链接 5.cookie&#xff08;会话保持&#xff09;总结 继续上一篇的内容&#xff1a; 上一篇的最后我们讲到了web根目录&#xff0c;知道…

epoll服务器创建

驱动 #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/io.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/poll.h> unsigned int major; char kbuf[128]{0}…

使用Docker部署EMQX

原文链接&#xff1a;http://www.ibearzmblog.com/#/technology/info?id9dd5bf4159d07f6a4e69a6b379ce4244 前言 在物联网中&#xff0c;大多通信协议使用的都是MQTT&#xff0c;而EMQX是基于 Erlang/OTP 平台开发的 MQTT 消息服务器&#xff0c;它的优点很多&#xff0c;我…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(12)-Fiddler设置IOS手机抓包,你知多少???

1.简介 Fiddler不但能截获各种浏览器发出的 HTTP 请求&#xff0c;也可以截获各种智能手机发出的HTTP/ HTTPS 请求。 Fiddler 能捕获Android 和 Windows Phone 等设备发出的 HTTP/HTTPS 请求。同理也可以截获iOS设备发出的请求&#xff0c;比如 iPhone、iPad 和 MacBook 等苹…

【BMC】OpenBMC使用基础(WSL2版本)

代码准备 OpenBMC是一个开源的项目&#xff0c;用于开发BMC固件。官网是https://www.openbmc.org/&#xff0c;不过里面似乎没有什么内容&#xff0c;所以还需要依赖其它的网站&#xff0c;https://github.com/openbmc&#xff0c;在这里可以下载到需要的代码和文档。其主体部…

C#,数值计算——对数正态分布(logarithmic normal distribution)的计算方法与源程序

对数正态分布&#xff08;logarithmic normal distribution&#xff09;是指一个随机变量的对数服从正态分布&#xff0c;则该随机变量服从对数正态分布。对数正态分布从短期来看&#xff0c;与正态分布非常接近。但长期来看&#xff0c;对数正态分布向上分布的数值更多一些。 …

Tailwind CSS:基础使用/vue3+ts+Tailwind

一、理解Tailwind 安装 - TailwindCSS中文文档 | TailwindCSS中文网 Installation - Tailwind CSS 1.1、词义 我们简单理解就是搭上CSS的顺风车&#xff0c;事半功倍。 1.2、Tailwind CSS有以下优势 1. 快速开发&#xff1a;Tailwind CSS 提供了一些现成的 class / 可复用…

ARM裸机-4

1、什么是交叉编译 1.1、两种开发模式 非嵌入式开发&#xff0c;A&#xff08;类&#xff09;机编写&#xff08;源代码&#xff09;、编译得到可执行程序&#xff0c;发布给A&#xff08;类&#xff09;机运行。 嵌入式开发&#xff0c;A&#xff08;类&#xff09;机编写&am…

webpack : 无法加载文件 C:\Program Files\nodejs\webpack.ps1

webpack : 无法加载文件 C:\Program Files\nodejs\webpack.ps1 1.问题2. 解决办法&#xff1a; 1.问题 使用webpack打包是报错如下&#xff1a; webpack : 无法加载文件 C:\Program Files\nodejs\webpack.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c…

Spring源码(三)Spring Bean生命周期

Bean的生命周期就是指&#xff1a;在Spring中&#xff0c;一个Bean是如何生成的&#xff0c;如何销毁的 Bean生命周期流程图 1、生成BeanDefinition Spring启动的时候会进行扫描&#xff0c;会先调用org.springframework.context.annotation.ClassPathScanningCandidateCompo…

Qt C++实现Excel表格的公式计算

用Qt的QTableViewQStandardItemModelQStyledItemDelegate实现类似Excel表格的界面&#xff0c;在parser 模块中提供解析表格单元格输入的公式。单元格编辑结束后按回车进行计算和更新显示。 效果如下&#xff1a; 支持的公式计算可以深度嵌套&#xff0c;目前parser模块中仅提…

【Java】零基础上手SpringBoot学习日记(day1)

前言 此帖为本人学习Springboot时的笔记&#xff0c;由于是个接触计算机一年左右的新手&#xff0c;也没有网站开发经验&#xff0c;所以有些地方的理解会比较浅显并且可能会出现错误&#xff0c;望大佬们多多包涵和指正。 Web应用开发 在我的理解中&#xff0c;Web应用的开发…

测试|测试分类

测试|测试分类 文章目录 测试|测试分类1.按照测试对象分类&#xff08;部分掌握&#xff09;2.是否查看代码&#xff1a;黑盒、白盒灰盒测试3.按开发阶段分&#xff1a;单元、集成、系统及验收测试4.按实施组织分&#xff1a;α、β、第三方测试5.按是否运行代码&#xff1a;静…

Mysql sql优化

目录 目的 目标 explain 优化 避免使用select * 用union all代替union 小表驱动大表&#xff08;in与exists&#xff09; 批量操作 多使用limit in中值太多 不使用%前缀模糊查询 不在where子句中进行表达式操作 避免隐式类型转换 联合索引遵守最左前缀法则 inne…

【Spring Boot 源码学习】走近 AutoConfigurationImportSelector

AutoConfigurationImportSelector 源码解析 引言主要内容1. ImportSelector 接口2. DeferredImportSelector 接口3. AutoConfigurationImportSelector 功能概述 总结 引言 上篇博文我们了解了 EnableAutoConfiguration 注解&#xff0c;其中真正实现自动配置功能的核心实现者 …