重写java.util.Properties工具类 内容有序 不丢注释

properties修改保留注解,重新加载properties到内存 最近一个Properties文件的管理的一些分享,欢迎大家来交流 阅读详情
package com.vrv.util; 


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;


/** 
 *   CommentedProperties
 *   针对Properties进行扩展的工具类
 *   
 *   扩展的两个主要功能:
 *   1.对Properties文件中注释的保存。
 *       CommentedProperties在读取和保存Properties文件时,会将其注释
 *       一起读取保存。CommentedProperties中会提供方法来根据key获取
 *       相应注释。在CommentedProperties中添加一个K-V对时,也会提供
 *       添加相应注释的方法。
 *       
 *   2.对Properties文件中Key值顺序的保证。
 *       CommentedProperties会保证Key的顺序。从一个Properties文件中
 *       读取所有K-V对,保存到另一个Properties文件时,Key的顺序不会
 *       改变。
 *       
 *
 * @author BrokenDreams
 */
public class CommentedProperties{


/**
* 内部属性表
*/
private final Properties props;


/**
* 保存key与comment的映射,
* 同时利用这个映射来保证key的顺序。
*/
private final LinkedHashMap<String, String> keyCommentMap = new LinkedHashMap<String, String>();


private static final String BLANK = "";


public CommentedProperties() {
super();
props = new Properties();
}


public CommentedProperties(Properties defaults) {
super();
props = new Properties(defaults);
}


/**
* 设置一个属性,如果key已经存在,那么将其对应value值覆盖。
* @param key
* @param value
* @return
*/
public String setProperty(String key, String value) {
return setProperty(key, value, BLANK);
}


/**
* 设置一个属性,如果key已经存在,那么将其对应value值覆盖。
* 
* @param key 键
* @param value 与键对应的值
* @param comment 对键值对的说明
* @return
*/
public synchronized String setProperty(String key, String value, String comment){
Object oldValue = props.setProperty(key, value);
if(BLANK.equals(comment)){
if(!keyCommentMap.containsKey(key)){
keyCommentMap.put(key, comment);
}
}else{
keyCommentMap.put(key, comment);
}
return (String)oldValue;
}

/**
* 根据key获取属性表中相应的value。
* 
* @param key
* @return
*/
public String getProperty(String key) {
return props.getProperty(key);
}


/**
* 根据key获取属性表中相应的value。
* 如果没找到相应的value,返回defaultValue。
* 
* @param key
* @param defaultValue
* @return
*/
public String getProperty(String key, String defaultValue) {
return props.getProperty(key, defaultValue);
}


/**
* 从一个字符流中读取属性到属性表中
* 
* @param reader
* @throws IOException
*/
public synchronized void load(Reader reader) throws IOException {
load0(new LineReader(reader));
}


/**
* 从一个字节流中读取属性到属性表中
* 
* @param inStream
* @throws IOException
*/
public synchronized void load(InputStream inStream) throws IOException {
load0(new LineReader(inStream));
}


/**
* 从一个字节流中读取属性到属性表中
* 
* @param inStream
* @param charset
* @throws IOException
*/
public synchronized void load(InputStream inStream, String charset) throws IOException {
InputStreamReader reader = new InputStreamReader(inStream, charset);
load0(new LineReader(reader));
}


/**
* 从一个文件中读取属性到属性表中
* 
* @param file 属性文件
* @param charset 字符集
* @throws IOException
*/
public synchronized void load(File file, String charset) throws IOException {
FileInputStream inputStream = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(inputStream, charset);
load0(new LineReader(reader));
}


/**
* 从一个文件中读取属性到属性表中
* 默认字符集为utf-8
* 
* @param file 属性文件
* @throws IOException
*/
public synchronized void load(File file) throws IOException {
FileInputStream inputStream = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
load0(new LineReader(reader));
}

/**
* 将属性表中的属性写到字符流里面。
* 
* @param writer
* @throws IOException
*/
public void store(Writer writer) throws IOException {
store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
: new BufferedWriter(writer),false);
}


/**
* 将属性表中的属性写到字节流里面。
* 
* @param out
* @throws IOException
*/
public void store(OutputStream out) throws IOException {
store0(new BufferedWriter(new OutputStreamWriter(out, "utf-8")),true);
}


/**
* 如果属性表中某个key对应的value值和参数value相同
* 那么返回true,否则返回false。
* 
* @param value
* @return
*/
public boolean containsValue(String value) {
return props.containsValue(value);
}


/**
* 如果属性表中存在参数key,返回true,否则返回false。
* 
* @param key
* @return
*/
public boolean containsKey(String key) {
return props.containsKey(key);
}

/**
* 获取属性表中键值对数量
* @return
*/
public int size() {
return props.size();
}


/**
* 检查属性表是否为空
* @return
*/
public boolean isEmpty() {
return props.isEmpty();
}


/**
* 清空属性表
*/
public synchronized void clear() {
props.clear();
keyCommentMap.clear();
}


/**
* 获取属性表中所有key的集合。
* 
* @return
*/
public Set<String> propertyNames() {
return props.stringPropertyNames();
}




public synchronized String toString() {
StringBuffer buffer = new StringBuffer();
Iterator<Map.Entry<String, String>> kvIter = keyCommentMap.entrySet().iterator();
buffer.append("[");
while(kvIter.hasNext()){
buffer.append("{");
Map.Entry<String, String> entry = kvIter.next();
String key = entry.getKey();
String val = getProperty(key);
String comment = entry.getValue();
buffer.append("key="+key+",value="+val+",comment="+comment);
buffer.append("}");
}
buffer.append("]");
return buffer.toString();
}


public boolean equals(Object o) {
//不考虑注释说明是否相同
return props.equals(o);
}


public int hashCode() {
return props.hashCode();
}

private void load0(LineReader lr) throws IOException {
char[] convtBuf = new char[1024];
int limit;
int keyLen;
int valueStart;
char c;
boolean hasSep;
boolean precedingBackslash;
StringBuffer buffer = new StringBuffer();


while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0;
valueStart = limit;
hasSep = false;
//获取注释
c = lr.lineBuf[keyLen];
if(c == '#' || c == '!'){
String comment = loadConvert(lr.lineBuf, 1, limit - 1, convtBuf);
if(buffer.length() > 0){
buffer.append("\n");
}
buffer.append(comment);
continue;
}
precedingBackslash = false;
while (keyLen < limit) {
c = lr.lineBuf[keyLen];
//need check if escaped.
if ((c == '=' ||  c == ':') && !precedingBackslash) {
valueStart = keyLen + 1;
hasSep = true;
break;
} else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
valueStart = keyLen + 1;
break;
} 
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
keyLen++;
}
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
if (c != ' ' && c != '\t' &&  c != '\f') {
if (!hasSep && (c == '=' ||  c == ':')) {
hasSep = true;
} else {
break;
}
}
valueStart++;
}
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
setProperty(key, value, buffer.toString());
//reset buffer
buffer = new StringBuffer();
}
}


/* 
* 基于java.util.Properties.LineReader进行改造
* 
* Read in a "logical line" from an InputStream/Reader, skip all comment
* and blank lines and filter out those leading whitespace characters 
* (\u0020, \u0009 and \u000c) from the beginning of a "natural line". 
* Method returns the char length of the "logical line" and stores 
* the line in "lineBuf". 
*/
class LineReader {
public LineReader(InputStream inStream) {
this.inStream = inStream;
inByteBuf = new byte[8192]; 
}


public LineReader(Reader reader) {
this.reader = reader;
inCharBuf = new char[8192]; 
}


byte[] inByteBuf;
char[] inCharBuf;
char[] lineBuf = new char[1024];
int inLimit = 0;
int inOff = 0;
InputStream inStream;
Reader reader;


int readLine() throws IOException {
int len = 0;
char c = 0;


boolean skipWhiteSpace = true;
boolean isNewLine = true;
boolean appendedLineBegin = false;
boolean precedingBackslash = false;
boolean skipLF = false;


while (true) {
if (inOff >= inLimit) {
inLimit = (inStream==null)?reader.read(inCharBuf)
:inStream.read(inByteBuf);
inOff = 0;
if (inLimit <= 0) {
if (len == 0) { 
return -1; 
}
return len;
}
}     
if (inStream != null) {
//The line below is equivalent to calling a 
//ISO8859-1 decoder.
c = (char) (0xff & inByteBuf[inOff++]);
} else {
c = inCharBuf[inOff++];
}
if (skipLF) {
skipLF = false;
if (c == '\n') {
continue;
}
}
if (skipWhiteSpace) {
if (c == ' ' || c == '\t' || c == '\f') {
continue;
}
if (!appendedLineBegin && (c == '\r' || c == '\n')) {
continue;
}
skipWhiteSpace = false;
appendedLineBegin = false;
}
if (isNewLine) {
isNewLine = false;
}


if (c != '\n' && c != '\r') {
lineBuf[len++] = c;
if (len == lineBuf.length) {
int newLength = lineBuf.length * 2;
if (newLength < 0) {
newLength = Integer.MAX_VALUE;
}
char[] buf = new char[newLength];
System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
lineBuf = buf;
}
//flip the preceding backslash flag
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
}
else {
// reached EOL
if (len == 0) {
isNewLine = true;
skipWhiteSpace = true;
len = 0;
continue;
}
if (inOff >= inLimit) {
inLimit = (inStream==null)
?reader.read(inCharBuf)
:inStream.read(inByteBuf);
inOff = 0;
if (inLimit <= 0) {
return len;
}
}
if (precedingBackslash) {
len -= 1;
//skip the leading whitespace characters in following line
skipWhiteSpace = true;
appendedLineBegin = true;
precedingBackslash = false;
if (c == '\r') {
skipLF = true;
}
} else {
return len;
}
}
}
}
}


/*
* Converts encoded &#92;uxxxx to unicode chars
* and changes special saved chars to their original forms
*/
private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
if (convtBuf.length < len) {
int newLen = len * 2;
if (newLen < 0) {
newLen = Integer.MAX_VALUE;
} 
convtBuf = new char[newLen];
}
char aChar;
char[] out = convtBuf; 
int outLen = 0;
int end = off + len;


while (off < end) {
aChar = in[off++];
if (aChar == '\\') {
aChar = in[off++];   
if(aChar == 'u') {
// Read the xxxx
int value=0;
for (int i=0; i<4; i++) {
aChar = in[off++];  
switch (aChar) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value = (value << 4) + aChar - '0';
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
value = (value << 4) + 10 + aChar - 'a';
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
value = (value << 4) + 10 + aChar - 'A';
break;
default:
throw new IllegalArgumentException(
"Malformed \\uxxxx encoding.");
}
}
out[outLen++] = (char)value;
} else {
if (aChar == 't') aChar = '\t'; 
else if (aChar == 'r') aChar = '\r';
else if (aChar == 'n') aChar = '\n';
else if (aChar == 'f') aChar = '\f'; 
out[outLen++] = aChar;
}
} else {
out[outLen++] = (char)aChar;
}
}
return new String (out, 0, outLen);
}


private void store0(BufferedWriter bw, boolean escUnicode)
throws IOException{
synchronized (this) {
Iterator<Map.Entry<String, String>> kvIter = keyCommentMap.entrySet().iterator();
while(kvIter.hasNext()){
Map.Entry<String, String> entry = kvIter.next();
String key = entry.getKey();
String val = getProperty(key);
String comment = entry.getValue();
key = saveConvert(key, true, escUnicode);
/* No need to escape embedded and trailing spaces for value, hence
* pass false to flag.
*/
val = saveConvert(val, false, escUnicode);
if(!comment.equals(BLANK))
writeComments(bw, comment);
bw.write(key + "=" + val);
bw.newLine();
}
}
bw.flush();
}


private static void writeComments(BufferedWriter bw, String comments) 
throws IOException {
bw.write("#");
int len = comments.length();  
int current = 0;
int last = 0;
while (current < len) {
char c = comments.charAt(current);
if (c > '\u00ff' || c == '\n' || c == '\r') {
if (last != current) 
bw.write(comments.substring(last, current));
if (c > '\u00ff') {
bw.write(c);
} else {
bw.newLine();
if (c == '\r' && 
current != len - 1 && 
comments.charAt(current + 1) == '\n') {
current++;
}
if (current == len - 1 ||
(comments.charAt(current + 1) != '#' &&
comments.charAt(current + 1) != '!'))
bw.write("#");
}
last = current + 1;
} 
current++;
}
if (last != current) 
bw.write(comments.substring(last, current));
bw.newLine();
}


/*
* Converts unicodes to encoded &#92;uxxxx and escapes
* special characters with a preceding slash
*/
private String saveConvert(String theString,
boolean escapeSpace,
boolean escapeUnicode) {
int len = theString.length();
int bufLen = len * 2;
if (bufLen < 0) {
bufLen = Integer.MAX_VALUE;
}
StringBuffer outBuffer = new StringBuffer(bufLen);


for(int x=0; x<len; x++) {
char aChar = theString.charAt(x);
// Handle common case first, selecting largest block that
// avoids the specials below
if ((aChar > 61) && (aChar < 127)) {
if (aChar == '\\') {
outBuffer.append('\\'); outBuffer.append('\\');
continue;
}
outBuffer.append(aChar);
continue;
}
switch(aChar) {
case ' ':
if (x == 0 || escapeSpace) 
outBuffer.append('\\');
outBuffer.append(' ');
break;
case '\t':outBuffer.append('\\'); outBuffer.append('t');
break;
case '\n':outBuffer.append('\\'); outBuffer.append('n');
break;
case '\r':outBuffer.append('\\'); outBuffer.append('r');
break;
case '\f':outBuffer.append('\\'); outBuffer.append('f');
break;
case '=': // Fall through
case ':': // Fall through
case '#': // Fall through
case '!':
outBuffer.append('\\'); outBuffer.append(aChar);
break;
default:
if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
outBuffer.append('\\');
outBuffer.append('u');
outBuffer.append(toHex((aChar >> 12) & 0xF));
outBuffer.append(toHex((aChar >>  8) & 0xF));
outBuffer.append(toHex((aChar >>  4) & 0xF));
outBuffer.append(toHex( aChar        & 0xF));
} else {
outBuffer.append(aChar);
}
}
}
return outBuffer.toString();
}


/**
* Convert a nibble to a hex character
* @param nibble the nibble to convert.
*/
private static char toHex(int nibble) {
return hexDigit[(nibble & 0xF)];
}


/** A table of hex digits */
private static final char[] hexDigit = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};


}
Python解析Java properties文件的完整指南 .properties是一种源自Java生态的键值对配置格式,其语法包含空格敏感性、反斜杠行续接、ISO-8859-1编码及Unicode转义等核心规则。理解这些原理是实现跨语言配置互通的技术基础。Python标准库不原生支持该格式,需借助jproperties等专用库或手写解析器,兼顾语法兼容性与生产安全性。典型应用场景包括Java-Python混合系统配置校验、Spring Boot环境同步、遗留系统自动化运维等。本文聚焦properties语法黑盒拆解与Python稳健解析实践,覆盖编码处理、多行值、 阅读详情

相关推荐

Java国际化i18n实战:ResourceBundle与Locale深层原理

Java国际化(i18n)本质是运行时环境协商机制,而非简单的字符串替换。其核心依托Locale作为JVM级上下文标识符,驱动日期格式、数字分隔、货币符号及排序规则;ResourceBundle则基于候选Locale匹配、类加载器绑定与缓存策略实现动态资源加载。该机制深刻影响Spring Boot多语言支持、REST API本地化响应、跨时区时间格式化等关键场景。理解Locale.getDefault()的三重来源(JVM参数/系统属性/OS设置)、ResourceBundle的层级继承逻辑(zh_CN →

weixin_33924770的博客 691

JAVA 【基础】 properties配置文件的读取和修改 (不会删除注释)

网上找了很久都找不到想要的工具类,索性自己写了一个。原理就是吧 每行中的第一个等于号=,换成特殊字符串,然后进行分割,读取。遇到#符号停止读取,转到下一行读取。 直接上案例 下面是测试的文件test.txt ##注释## #注释 time=2020/7/25 name= KL-Skeleton array= 1,2,3,4,五,六,七,8,9,0 #注释#### age= 20 height= 199.999 blog_name=JAVA 【基础】 properties配置文件的读取

言小溪 的博客 3016

Java equals与hashCode契约:对象身份识别的底层原理与工程实践

在Java中,equals()和hashCode()共同构成对象身份识别的核心契约,其本质是支撑哈希表结构(如HashMap、HashSet)高效运行的数学基础——前者定义业务语义上的等价关系(满足自反性、对称性、传递性),后者提供稳定、均匀分布的整型索引。该机制直接决定缓存命中率、集合去重准确性及分布式Key一致性等关键工程指标。深入理解其与JVM对象头存储、字节码虚方法调用及哈希碰撞处理的协同逻辑,能有效规避线上因重写失配导致的静默故障。本文结合OpenJDK实现、HotSpot内存布局与真实生产案例,

weixin_30521161的博客 369

使用java代码获取yml及properties文件中的内容,获取值

获取properties文件中的内容 最近做项目一些值需要放在配置文件中,一开始使用的是properties文件,我这里没有使用注解@Value获取。 获取yml文件中的内容

世上哪有什么岁月静好,不过是有人替你负重前行 3170

Java技术变现新路径:基于JVM生态的工程化赚钱模型

Java作为一门成熟语言,其核心价值已从语法特性升维为JVM生态所承载的稳定性、向后兼容性与企业级信任背书。在等保合规、遗留系统现代化和垂直领域工具链等刚性需求驱动下,Java凭借字节码增强、Java Agent、ClassLoader热加载等原生能力,成为构建合规即服务(Compliance-as-a-Service)、遗留系统缝合层及微型SaaS的关键技术底座。它不追求性能极限,而以‘可审计、可验证、零改造集成’满足法务签字、运维背书与终端用户习惯三重决策节点。本文聚焦Java在2025年中小企业技术变

weixin_30378623的博客 406

前端转AI全栈:Java后端学习路径与Spring Boot实践指南

面向对象编程(OOP)是一种以对象为核心的程序设计范式,通过封装、继承和多态三大特性构建模块化、可复用的代码结构。其核心原理在于将数据与操作数据的方法绑定为对象,从而模拟现实世界实体。在工程实践中,OOP极大地提升了代码的可维护性和扩展性,是构建大型复杂系统的基石。在Java生态中,这一理念与Spring Boot框架深度结合,使得开发者能够快速搭建稳健的企业级后端服务。随着AI应用开发热潮的兴起,掌握Java后端技术成为实现AI全栈能力的关键一环,开发者可以运用Spring Boot高效构建RESTful

weixin_34293141的博客 1044

java顺序读取properties配置文件

首先我们需要重写properties类中stringPropertyNames方法,因为该方法底层实现基于hashTable是无序的所以生成的hashcode不一样。需要用LinkedHashSet替换其实现。new FileInputStream("src/main/resources/properties/" + 文件名), "UTF-8"));/** LinkedHashSet有序,可以保证读取出来顺序不变 */* 顺序读取key集合。// 读取properties类。2.调用实现顺序读取文件。

SweetChoco的博客 884

Java基础知识面试题(2026版)

序列号 内容 链接 1 Java基础知识面试题(2022版) 待续… 2 Java集合容器面试题(2022版) 待续… 3 Java异常面试题(2022版) 待续… 4 并发编程面试题 (2022版) 待续… 5 JVM面试题(2022版) 待续… 6 Spring面试题(2022版) 待续… 7 Spring MVC面试题(2022版) 待续… 8 Spring Boot面试题(2022版) 待续… 9 Spring Cloud面试题(2022版) 待续… ....

拉格朗日的学习笔记 3万+

计算机学习笔记 Object类、泛型、包装类与反射机制全景解析(含代码解析)

本次课程重点涵盖Java核心基础与反射机制。Object类中equals与hashCode必须同步重写,泛型存在类型擦除特性,禁止直接new T[],包装类Integer缓存范围为-128至127,拆箱时需防范空指针异常。反射部分核心是通过Class.forName("全类名")动态获取Class<?>对象,其中<?>是编译期类型未知的标准泛型写法。操作成员时遵循三要素:getDeclaredXxx获取私有成员、setAccessible(true)突破访问限制、invoke/get/set执行具体操作。P

既然你都点开这里了,那可以给我点个关注吗?可以吗?可以吗? 169

Java集合容器面试题(2026版)

序列号 内容 链接 1 Java基础知识面试题(2022版) https://blog.csdn.net/qq_43061290/article/details/124023797 2 Java集合容器面试题(2022版) 待续… https://editor.csdn.net/md?spm=1001.2101.3001.5352&articleId=124043363 3 Java异常面试题(2022版) 待续… 4 并发编程面试题 (2022版) 待续… 5 JV....

拉格朗日的学习笔记 1万+

能保存Properties文件注释的Properties工具类

CommentedProperties代码 博文链接:https://brokendreams.iteye.com/blog/1932875

狂命爆肝99天,共52K字的JAVA学习笔记奉上,JAVA从入门到精通一文搞定,一文在手JAVA无忧

本文介绍了Java编程的基础知识、开发环境设置、JVM内存划分以及常用关键字。Java分为JavaSE、JavaEE和JavaME三个版本,分别用于桌面、企业和嵌入式系统开发。编译使用javac,运行使用java,JDK是开发工具包,JRE是运行环境,JVM是虚拟机。JVM内存分为堆、方法区和栈,分别存储实例变量、静态变量和局部变量。常用关键字包括public、static、final、this和super,分别用于定义类、静态成员、常量、当前对象引用和父类特征。开发环境IDEA的快捷键和组织方式也进行了总

渣渣盟的博客 4万+

java properties文件操作工具类,可追加修改

此工具类只用于Java后端在操作Properties文件的时候写的工具类,方便properties文件的存取操作

集合框架 (六)

Java集合框架是存储和操作数据的核心工具,分为单列集合Collection和双列集合Map两大体系。Collection包括List(有序可重复)、Set(无序不重复)和Queue(队列);Map存储键值对,Key唯一。常用实现类有ArrayList、LinkedList、HashSet、HashMap等,各有特点:ArrayList基于动态数组查询快,LinkedList基于链表增删快,HashSet去重,HashMap键值映射高效。集合提供了丰富的API和遍历方式,支持泛型保证类型安全。开发中需注意线

专注 Java 后端开发,分享基础语法、JVM、并发、Spring 全家桶、微服务、分布式、性能优化等实战干货。坚持输出高质量技术笔记,用简单语言讲清复杂原理,助力每一位 Java 开发者稳步进阶。 239

properties 工具类 PropertiesUtil java

下载了就可以直接用。默认路径在项目随意source目录下,获取时直接PropertiesUtil.getInstance().getPropertyValue("xx.properties", "value");

立创·庐山派-K230-CanMV(嘉楠勘智)开发板通过ATK-ESP8266实现图像识别数据无线传输至原子云

本文详细介绍了如何使用立创·庐山派-K230-CanMV开发板,通过ATK-ESP8266 WIFI模块实现图像识别数据的无线传输至原子云平台。内容包括硬件连接、软件环境搭建、AT指令控制、原子云连接及数据上传的全过程,并提供了实用的调试技巧和常见问题解决方案,为物联网应用开发提供了完整实践指南。

potato的博客 743

Java Webshell免杀技术:从静态混淆到动态加载的攻防实践

在Java应用安全领域,Webshell检测与防护是持续对抗的核心议题。其原理基于对JVM运行时特性、类加载机制及容器安全策略的深度利用,通过混淆恶意代码特征、拆解行为链来规避安全检测。技术价值在于提升攻击的隐蔽性和持久性,对防御方则考验着多维度检测能力。应用场景广泛涉及渗透测试、红蓝对抗及安全评估。本文聚焦Java Webshell的免杀技术,涵盖JSP脚本混淆、URL类加载远程分离等高级手法,探讨如何通过动态加载与内存马技术实现对抗RASP监控和静态特征检测,为构建纵深防御体系提供关键思路。

weixin_34235457的博客 401

抄表程序员的DLMS/COSEM协议实战:从抓包到解析,手把手教你读懂IEC62056报文

本文深入解析DLMS/COSEM协议在智能电表通信中的应用,从报文捕获到数据解析的全流程实战指南。涵盖HDLC帧解析、应用层连接建立、数据请求/响应解码等核心内容,并提供Wireshark配置、OBIS代码速查表等实用工具,帮助开发者快速掌握IEC62056标准下的电能表通信技术。

weixin_29178069的博客 299

html自定义属性冒号,如何在属性文件中冒号冒号(:)?

我遇到了同样的问题。正向斜杠/也被store()方法在Properties中转义。我创造我自己的CustomProperties类(扩展java.util.Properties)和customStore0()方法注释掉调用saveConvert()解决了这个问题。这里是我CustomProperties类:import java.io.BufferedWriter;import java.io.I...

weixin_29197699的博客 791

脑电数据预处理八:基于 ICA 的伪迹去除

摘要: 脑电图(EEG)数据分析中,伪迹(如眼电、心电、肌电)与脑电信号频谱重叠时,独立成分分析(ICA)成为有效工具。ICA通过盲源分离将混合信号分解为统计独立的成分,识别并移除伪迹后重建干净信号。MNE-Python实现步骤包括:数据预处理(滤波、坏导处理)、ICA分解、人工与自动结合识别伪迹成分、剔除后重建数据。实践建议强调人工检查的重要性,避免过度使用ICA,并保存模型以提高效率。该方法显著提升数据质量,为后续分析奠定基础。

qq_32516809的博客 1659

风控IV、AUC、KS python计算代码

df_temp:数据集,Y:是否逾期标签,feas_list:需要计算IV的 变量。2、 按月和不同Y 下的 IV计算。

暮雨听轩的专栏 1618

前端开发者转型Java全栈:高效学习路径与AI工程化实践

面向对象编程(OOP)是一种以对象为核心,通过封装、继承和多态三大特性来组织代码的编程范式,它模拟现实世界,将数据和行为封装在对象中,从而提升代码的可重用性、可维护性和可扩展性。其核心原理在于通过类定义对象的蓝图,通过实例化创建具体对象,并通过消息传递实现对象间的交互。这一范式在构建复杂、模块化的企业级应用和系统时展现出巨大技术价值,尤其在需要高内聚、低耦合架构的后端服务开发中不可或缺。随着AI工程化和全栈开发的兴起,Java作为企业级应用的主流语言,其严谨的OOP体系与强大的Spring Boot生态,成

weixin_34056162的博客 340

Trae中配置和使用MCP 服务保姆级教程

您好,我是程序员夏叶,深度AI编程使用者,专注于分享AI编程方面的使用技巧和经验,有兴趣的可以关注我的公众号,一起学习,共同进步。从21号开始,Trae开始陆陆续续的灰度推送了一次新版本,有的用户是21号收到的更新,有的用户是22号收到的更新,本次更新我愿称之为王炸级更新,具体更新内容可以去看我的上一篇文章。本次更新其中的一个内容就是支持了MCP 服务,那么什么是MCP呢,它的全称是。

cpp加油站的专栏 8204
上一篇: Solr6.0集成IK-Analyzer分词器
下一篇: springboot框架集成neo4j+d3.js
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值