feat(utils): 添加ByteBuffer变长数字编解码和防抖器功能

- 在ByteBufferUtils中添加getVarLong、getVarInt、getVarShort读取变长数字功能
- 在ByteBufferUtils中添加putVarLong、putVarInt、putVarShort写入变长数字功能
- 新增Debouncer防抖器类用于防止短时间内重复执行任务
- 更新build.gradle.kts中mybatis-plus-core依赖版本至3.5.15
- 优化FileUtils中文件操作方法,增加Path和File类型的扩展函数
- 添加字节转义字符常量定义和hex字符串转换工具方法
This commit is contained in:
Armamem0t 2026-01-14 13:01:50 +08:00
parent 66ec71cbc7
commit f2ee83ca64
Signed by: minglipro
GPG Key ID: 5F355A77B22AA93B
12 changed files with 1077 additions and 349 deletions

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils * ModuleName mingli-utils
* CurrentFile build.gradle.kts * CurrentFile build.gradle.kts
* LastUpdate 2026-01-08 11:10:03 * LastUpdate 2026-01-14 13:01:44
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@ -78,7 +78,7 @@ dependencies {
compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58") compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58")
compileOnly("io.netty:netty-all:4.1.130.Final") compileOnly("io.netty:netty-all:4.1.130.Final")
compileOnly("com.baomidou:mybatis-plus-core:3.0.1") compileOnly("com.baomidou:mybatis-plus-core:3.5.15")
compileOnly("net.java.dev.jna:jna:5.17.0") compileOnly("net.java.dev.jna:jna:5.17.0")
} }

View File

@ -16,13 +16,13 @@
# ProjectName mingli-utils # ProjectName mingli-utils
# ModuleName mingli-utils # ModuleName mingli-utils
# CurrentFile gradle.properties # CurrentFile gradle.properties
# LastUpdate 2026-01-10 08:55:10 # LastUpdate 2026-01-14 13:01:41
# UpdateUser MingLiPro # UpdateUser MingLiPro
# #
JDKVERSIONS=1.8 JDKVERSIONS=1.8
GROUPSID=com.mingliqiye.utils GROUPSID=com.mingliqiye.utils
ARTIFACTID=mingli-utils ARTIFACTID=mingli-utils
VERSIONS=4.3.3 VERSIONS=4.3.5
signing.keyId=B22AA93B signing.keyId=B22AA93B
signing.password= signing.password=
signing.secretKeyRingFile=secret.gpg signing.secretKeyRingFile=secret.gpg

View File

@ -1,42 +0,0 @@
/*
* Copyright 2026 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Main.kt
* LastUpdate 2026-01-06 14:04:14
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils
import com.mingliqiye.utils.network.NetworkEndpoint
import com.mingliqiye.utils.uuid.UUID
import java.nio.ByteBuffer
fun main() {
val byteBuffer = ByteBuffer.allocate(320)
NetworkEndpoint
.of("0:65532")
.writeIpv4toByteBuffer(byteBuffer)
UUID.getMaxUUID().writeToByteBuffer(byteBuffer)
byteBuffer.flip()
println(NetworkEndpoint.ofIpv4(byteBuffer))
println(UUID.of(byteBuffer))
}

View File

@ -16,14 +16,16 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile ByteBufferUtils.kt * CurrentFile ByteBufferUtils.kt
* LastUpdate 2026-01-07 10:01:45 * LastUpdate 2026-01-11 09:44:19
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@file:JvmName("ByteBufferUtil") @file:JvmName("ByteBufferUtils")
package com.mingliqiye.utils.bytes package com.mingliqiye.utils.bytes
import java.io.IOException
import java.io.OutputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.charset.Charset import java.nio.charset.Charset
@ -203,3 +205,93 @@ fun ByteBuffer.putBoolean(boolean: Boolean): ByteBuffer = this.put(if (boolean)
fun ByteArray.toByteBuffer(): ByteBuffer { fun ByteArray.toByteBuffer(): ByteBuffer {
return ByteBuffer.wrap(this) return ByteBuffer.wrap(this)
} }
/**
* 从ByteBuffer中读取一个变长整数VarNumber
*
* 变长整数使用可变长度编码方式每个字节的最高位表示是否还有后续字节
* - 如果最高位为1则表示还有下一个字节
* - 如果最高位为0则表示当前字节是最后一个字节
*
* @param size 最大允许读取的字节数默认为8即Long类型的最大长度
* @return 解码后的长整型数值
* @throws IOException 当读取过程中发生IO异常时抛出
*/
fun ByteBuffer.getVarLong(size: Int = 8): Long {
var numRead = 0
var result: Long = 0
var read: Byte
do {
read = this.get()
// 将当前字节的有效7位数据左移相应位置后与结果进行按位或运算
result = result or ((read.toLong() and 127) shl (7 * numRead))
numRead++
if (numRead > size) {
throw IOException("VarNumber is too big")
}
} while ((read.toLong() and 128) != 0L)
return result
}
/**
* 从ByteBuffer中读取一个变长整数VarNumber返回Int类型
*
* @return 解码后的整型数值
*/
fun ByteBuffer.getVarInt(): Int = this.getVarLong(4).toInt()
/**
* 从ByteBuffer中读取一个变长整数VarNumber返回Short类型
*
* @return 解码后的短整型数值
*/
fun ByteBuffer.getVarShort(): Short = this.getVarLong(2).toShort()
/**
* 从输入流中读取一个变长长整数VarLong最大长度默认为8个字节
*
* @return 解码后的长整型数值
* @throws IOException 当读取过程中发生IO异常时抛出
*/
@Throws(IOException::class)
fun ByteBuffer.getVarLong(): Long = this.getVarLong(8)
/**
* 将长整型数值编码为变长格式并写入ByteBuffer
*
* 变长整数使用可变长度编码方式每个字节的最高位表示是否还有后续字节
* - 如果数值还有更多字节则最高位设为1
* - 最后一个字节最高位设为0
*
* @param value 要写入的长整型数值
* @return 当前ByteBuffer实例支持链式调用
*/
fun ByteBuffer.putVarLong(value: Long): ByteBuffer {
var v = value
while (v >= 0x80) {
this.put((v and 0x7F or 0x80).toByte())
v = v shr 7
}
this.put(v.toByte())
return this
}
/**
* 将整型数值编码为变长格式并写入ByteBuffer
*
* @param value 要写入的整型数值
* @return 当前ByteBuffer实例支持链式调用
*/
fun ByteBuffer.putVarInt(value: Int): ByteBuffer = this.putVarLong(value.toLong())
/**
* 将短整型数值编码为变长格式并写入ByteBuffer
*
* @param value 要写入的短整型数值
* @return 当前ByteBuffer实例支持链式调用
*/
fun ByteBuffer.putVarShort(value: Short): ByteBuffer = this.putVarLong(value.toLong())
fun ByteBuffer.writeStream(outputStream: OutputStream) = outputStream.write(this.toByteArray())

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2025 mingliqiye * Copyright 2026 mingliqiye
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,28 +16,74 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile ByteUtils.kt * CurrentFile ByteUtils.kt
* LastUpdate 2025-09-20 11:49:05 * LastUpdate 2026-01-14 13:01:44
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@file:JvmName("ByteUtils") @file:JvmName("ByteUtils")
package com.mingliqiye.utils.bytes package com.mingliqiye.utils.bytes
import com.mingliqiye.utils.base.BASE16
import com.mingliqiye.utils.stream.SuperStream import com.mingliqiye.utils.stream.SuperStream
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_ASC: Byte = 0x10 const val ESC_ASC: Byte = 0x10
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_DESC: Byte = 0x1B const val ESC_DESC: Byte = 0x1B
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_NONE: Byte = 0x00 const val ESC_NONE: Byte = 0x00
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_START: Byte = 0x01 const val ESC_START: Byte = 0x01
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_END: Byte = 0x02 const val ESC_END: Byte = 0x02
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_ESC: Byte = 0x03 const val ESC_ESC: Byte = 0x03
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_CONTROL: Byte = 0x04 const val ESC_CONTROL: Byte = 0x04
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_DATA: Byte = 0x05 const val ESC_DATA: Byte = 0x05
/**
* 转义字符常量定义
* 定义了用于数据传输或协议通信中的特殊控制字节值
*/
const val ESC_RESERVED: Byte = 0x06 const val ESC_RESERVED: Byte = 0x06
/** /**
* 将字节数组转换为十六进制字符串列表 * 将字节数组转换为十六进制字符串列表
* @receiver 字节数组
* @return 包含每个字节对应十六进制字符串的列表 * @return 包含每个字节对应十六进制字符串的列表
*/ */
fun ByteArray.getByteArrayString(): MutableList<String> { fun ByteArray.getByteArrayString(): MutableList<String> {
@ -46,6 +92,12 @@ fun ByteArray.getByteArrayString(): MutableList<String> {
} }
/**
* 将十六进制字符转换为对应的数值
* @receiver 十六进制字符
* @return 对应的数值0-15
* @throws NumberFormatException 当字符不是有效的十六进制字符时抛出
*/
fun Char.hexDigitToValue(): Int { fun Char.hexDigitToValue(): Int {
return when (this) { return when (this) {
in '0'..'9' -> this - '0' in '0'..'9' -> this - '0'
@ -55,6 +107,23 @@ fun Char.hexDigitToValue(): Int {
} }
} }
private fun hexStringToByteArray(string: String): ByteArray { /**
* 将十六进制字符串转换为字节数组
*
* @param string 输入的十六进制字符串
* @return 转换后的字节数组
*/
fun hexStringToByteArray(string: String): ByteArray {
return string.hexToByteArray() return string.hexToByteArray()
} }
/**
* 将字节数组转换为十六进制字符串表示
*
* @param bytes 输入的字节数组
* @return 对应的十六进制字符串
*/
fun bytesToHex(bytes: ByteArray): String {
return BASE16.encode(bytes)
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2025 mingliqiye * Copyright 2026 mingliqiye
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,17 +15,17 @@
* *
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile NumberUtils.kt * CurrentFile StreamUtils.kt
* LastUpdate 2025-09-16 15:59:45 * LastUpdate 2026-01-11 09:41:14
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@file:JvmName("StreamUtils")
@file:JvmName("NumberUtils") package com.mingliqiye.utils.bytes
package com.mingliqiye.utils.number
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream
/** /**
@ -35,25 +35,22 @@ import java.io.InputStream
* - 如果最高位为1则表示还有下一个字节 * - 如果最高位为1则表示还有下一个字节
* - 如果最高位为0则表示当前字节是最后一个字节 * - 如果最高位为0则表示当前字节是最后一个字节
* *
* @param input 输入流用于读取数据
* @param size 最大允许读取的字节数默认为8即Long类型的最大长度 * @param size 最大允许读取的字节数默认为8即Long类型的最大长度
* @return 解码后的长整型数值 * @return 解码后的长整型数值
* @throws IOException 当读取过程中发生IO异常或到达流末尾时抛出 * @throws IOException 当读取过程中发生IO异常或到达流末尾时抛出
*/ */
@Throws(IOException::class) @Throws(IOException::class)
fun readVarNumber(input: InputStream, size: Int = 10): Long { fun InputStream.readVarNumber(size: Int = 8): Long {
var numRead = 0 var numRead = 0
var result: Long = 0 var result: Long = 0
var read: Byte var read: Byte
do { do {
read = input.read().let { read = this.read().let {
if (it == -1) { if (it == -1) {
throw IOException("Reached end of stream") throw IOException("Reached end of stream")
} }
it.toByte() it.toByte()
} }
// 将当前字节的有效7位数据左移相应位数并与结果进行或运算
result = result or ((read.toLong() and 127) shl (7 * numRead)) result = result or ((read.toLong() and 127) shl (7 * numRead))
numRead++ numRead++
if (numRead > size) { if (numRead > size) {
@ -66,35 +63,84 @@ fun readVarNumber(input: InputStream, size: Int = 10): Long {
/** /**
* 从输入流中读取一个变长整数VarInt最大长度限制为4个字节 * 从输入流中读取一个变长整数VarInt最大长度限制为4个字节
* *
* @param input 输入流用于读取数据
* @return 解码后的整型数值 * @return 解码后的整型数值
* @throws IOException 当读取过程中发生IO异常时抛出 * @throws IOException 当读取过程中发生IO异常时抛出
*/ */
@Throws(IOException::class) @Throws(IOException::class)
fun readVarInt(input: InputStream): Int { fun InputStream.readVarInt(): Int = this.readVarNumber(4).toInt()
return readVarNumber(input, size = 4).toInt()
}
/** /**
* 从输入流中读取一个变长短整数VarShort最大长度限制为2个字节 * 从输入流中读取一个变长短整数VarShort最大长度限制为2个字节
* *
* @param input 输入流用于读取数据
* @return 解码后的短整型数值 * @return 解码后的短整型数值
* @throws IOException 当读取过程中发生IO异常时抛出 * @throws IOException 当读取过程中发生IO异常时抛出
*/ */
@Throws(IOException::class) @Throws(IOException::class)
fun readVarShort(input: InputStream): Short { fun InputStream.readVarShort(): Short = this.readVarNumber(2).toShort()
return readVarNumber(input, size = 2).toShort()
}
/** /**
* 从输入流中读取一个变长长整数VarLong最大长度默认为8个字节 * 从输入流中读取一个变长长整数VarLong最大长度默认为8个字节
* *
* @param input 输入流用于读取数据
* @return 解码后的长整型数值 * @return 解码后的长整型数值
* @throws IOException 当读取过程中发生IO异常时抛出 * @throws IOException 当读取过程中发生IO异常时抛出
*/ */
@Throws(IOException::class) @Throws(IOException::class)
fun readVarLong(input: InputStream): Long { fun InputStream.readVarLong(): Long = this.readVarNumber()
return readVarNumber(input)
/**
* 将长整型数值编码为变长格式并写入输出流
*
* 变长整数使用可变长度编码方式每个字节的最高位表示是否还有后续字节
* - 如果数值还有更多字节则最高位设为1
* - 最后一个字节最高位设为0
*
* @param value 要写入的长整型数值
* @param size 最大允许写入的字节数默认为8
* @throws IOException 当写入过程中发生IO异常时抛出
*/
@Throws(IOException::class)
fun OutputStream.writeVarNumber(value: Long, size: Int = 8) {
var v = value
var numWritten = 0
while (v >= 0x80 && numWritten < size - 1) {
this.write((v and 0x7F or 0x80).toInt())
v = v ushr 7
numWritten++
}
if (numWritten >= size) {
throw IOException("VarNumber is too big")
}
this.write(v.toInt())
} }
/**
* 将整型数值编码为变长格式并写入输出流
*
* @param value 要写入的整型数值
* @throws IOException 当写入过程中发生IO异常时抛出
*/
@Throws(IOException::class)
fun OutputStream.writeVarInt(value: Int): Unit = this.writeVarNumber(value.toLong(), 4)
/**
* 将短整型数值编码为变长格式并写入输出流
*
* @param value 要写入的短整型数值
* @throws IOException 当写入过程中发生IO异常时抛出
*/
@Throws(IOException::class)
fun OutputStream.writeVarShort(value: Short): Unit = this.writeVarNumber(value.toLong(), 2)
/**
* 将长整型数值编码为变长格式并写入输出流
*
* @param value 要写入的长整型数值
* @throws IOException 当写入过程中发生IO异常时抛出
*/
@Throws(IOException::class)
fun OutputStream.writeVarLong(value: Long): Unit = this.writeVarNumber(value, 8)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2025 mingliqiye * Copyright 2026 mingliqiye
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,7 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile FileUtils.kt * CurrentFile FileUtils.kt
* LastUpdate 2025-09-15 09:12:47 * LastUpdate 2026-01-11 09:20:20
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@file:JvmName("FileUtils") @file:JvmName("FileUtils")
@ -24,195 +24,188 @@
package com.mingliqiye.utils.file package com.mingliqiye.utils.file
import com.mingliqiye.utils.path.OsPath import com.mingliqiye.utils.path.OsPath
import java.io.File
import java.io.IOException import java.io.IOException
import java.nio.charset.Charset import java.nio.charset.Charset
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.nio.file.StandardOpenOption import java.nio.file.StandardOpenOption
/** /**
* 默认字符集 * 默认字符集
*/ */
var DEFAULT_CHARSET: Charset = StandardCharsets.UTF_8 var DEFAULT_CHARSET: Charset = StandardCharsets.UTF_8
/** // 读取文件内容为字符串
* 读取文件内容为字符串
*
* @param filePath 文件路径
* @return 文件内容字符串
* @throws IOException 读取文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun readFileToString(filePath: String): String { /**
return readFileToString(filePath, DEFAULT_CHARSET) * 读取文件内容为字符串使用默认字符集
*
* @return 文件内容的字符串表示
* @throws IOException 读取文件时发生错误
*/
fun String.readFileToString(): String {
return this.readFileToString(DEFAULT_CHARSET)
} }
/**
* 读取文件内容为字符串
*
* @param filePath 文件路径
* @param charset 字符集
* @return 文件内容字符串
* @throws IOException 读取文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun readFileToString(filePath: String, charset: Charset): String { /**
val path = OsPath.of(filePath) * 读取文件内容为字符串
*
* @param charset 字符编码格式
* @return 文件内容的字符串表示
* @throws IOException 读取文件时发生错误
*/
fun String.readFileToString(charset: Charset): String {
val path = OsPath.of(this)
val bytes = Files.readAllBytes(path) val bytes = Files.readAllBytes(path)
return String(bytes, charset) return String(bytes, charset)
} }
/** // 将字符串写入文件
* 将字符串写入文件
*
* @param filePath 文件路径
* @param content 要写入的内容
* @throws IOException 写入文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun writeStringToFile(filePath: String, content: String) { /**
writeStringToFile(filePath, content, DEFAULT_CHARSET) * 将字符串写入文件使用默认字符集
*
* @param content 要写入的字符串内容
* @throws IOException 写入文件时发生错误
*/
fun String.writeStringToFile(content: String) {
this.writeStringToFile(content, DEFAULT_CHARSET)
} }
/**
* 将字符串写入文件
*
* @param filePath 文件路径
* @param content 要写入的内容
* @param charset 字符集
* @throws IOException 写入文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun writeStringToFile(filePath: String, content: String, charset: Charset) { /**
val path = Paths.get(filePath) * 将字符串写入文件
*
* @param content 要写入的字符串内容
* @param charset 字符编码格式
* @throws IOException 写入文件时发生错误
*/
fun String.writeStringToFile(content: String, charset: Charset) {
val path = Paths.get(this)
path.parent?.let { Files.createDirectories(it) } path.parent?.let { Files.createDirectories(it) }
Files.write(path, content.toByteArray(charset)) Files.write(path, content.toByteArray(charset))
} }
/** // 读取文件内容为字符串列表(按行分割)
* 读取文件内容为字符串列表按行分割
*
* @param filePath 文件路径
* @return 文件内容按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun readLines(filePath: String): List<String> { /**
return readLines(filePath, DEFAULT_CHARSET) * 读取文件内容为字符串列表按行分割使用默认字符集
*
* @return 按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
fun String.readLines(): List<String> {
return this.readLines(DEFAULT_CHARSET)
} }
/**
* 读取文件内容为字符串列表按行分割
*
* @param filePath 文件路径
* @param charset 字符集
* @return 文件内容按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun readLines(filePath: String, charset: Charset): List<String> { /**
val path = Paths.get(filePath) * 读取文件内容为字符串列表按行分割
*
* @param charset 字符编码格式
* @return 按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
fun String.readLines(charset: Charset): List<String> {
val path = Paths.get(this)
return Files.readAllLines(path, charset) return Files.readAllLines(path, charset)
} }
/** // 将字符串列表写入文件(每行一个元素)
* 将字符串列表写入文件每行一个元素
*
* @param filePath 文件路径
* @param lines 要写入的行内容列表
* @throws IOException 写入文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun writeLines(filePath: String, lines: List<String>) { /**
writeLines(filePath, lines, DEFAULT_CHARSET) * 将字符串列表写入文件每行一个元素使用默认字符集
*
* @param lines 要写入的字符串列表
* @throws IOException 写入文件时发生错误
*/
fun String.writeLines(lines: List<String>) {
this.writeLines(lines, DEFAULT_CHARSET)
} }
/**
* 将字符串列表写入文件每行一个元素
*
* @param filePath 文件路径
* @param lines 要写入的行内容列表
* @param charset 字符集
* @throws IOException 写入文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun writeLines(filePath: String, lines: List<String>, charset: Charset) { /**
val path = Paths.get(filePath) * 将字符串列表写入文件每行一个元素
*
* @param lines 要写入的字符串列表
* @param charset 字符编码格式
* @throws IOException 写入文件时发生错误
*/
fun String.writeLines(lines: List<String>, charset: Charset) {
val path = Paths.get(this)
Files.createDirectories(path.parent) Files.createDirectories(path.parent)
Files.write(path, lines, charset) Files.write(path, lines, charset)
} }
/** // 复制文件
* 复制文件
*
* @param sourcePath 源文件路径
* @param targetPath 目标文件路径
* @throws IOException 复制文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun copyFile(sourcePath: String, targetPath: String) { /**
val source = Paths.get(sourcePath) * 复制文件到目标路径
*
* @param targetPath 目标文件路径
* @throws IOException 复制文件时发生错误
*/
fun String.copyFile(targetPath: String) {
val source = Paths.get(this)
val target = Paths.get(targetPath) val target = Paths.get(targetPath)
Files.createDirectories(target.parent) Files.createDirectories(target.parent)
Files.copy(source, target) Files.copy(source, target)
} }
// 删除文件
/** /**
* 删除文件 * 删除文件
* *
* @param filePath 文件路径 * @return 删除操作是否成功
* @return 如果文件删除成功返回true否则返回false
*/ */
fun deleteFile(filePath: String): Boolean { fun String.deleteFile(): Boolean {
return try { return try {
val path = Paths.get(filePath) val path = Paths.get(this)
Files.deleteIfExists(path) Files.deleteIfExists(path)
} catch (e: IOException) { } catch (e: IOException) {
false false
} }
} }
// 检查文件是否存在
/** /**
* 检查文件是否存在 * 检查文件是否存在
* *
* @param filePath 文件路径 * @return 文件是否存在
* @return 如果文件存在返回true否则返回false
*/ */
fun exists(filePath: String): Boolean { fun String.exists(): Boolean {
val path = Paths.get(filePath) val path = Paths.get(this)
return Files.exists(path) return Files.exists(path)
} }
// 获取文件大小
/** /**
* 获取文件大小 * 获取文件大小
* *
* @param filePath 文件路径 * @return 文件大小字节如果获取失败则返回-1
* @return 文件大小字节如果文件不存在返回-1
*/ */
fun String.getFileSize(): Long {
fun getFileSize(filePath: String): Long {
return try { return try {
val path = Paths.get(filePath) val path = Paths.get(this)
Files.size(path) Files.size(path)
} catch (e: IOException) { } catch (e: IOException) {
-1 -1
} }
} }
// 创建目录
/** /**
* 创建目录 * 创建目录
* *
* @param dirPath 目录路径 * @return 创建操作是否成功
* @return 如果目录创建成功返回true否则返回false
*/ */
fun String.createDirectory(): Boolean {
fun createDirectory(dirPath: String): Boolean {
return try { return try {
val path = Paths.get(dirPath) val path = Paths.get(this)
Files.createDirectories(path) Files.createDirectories(path)
true true
} catch (e: IOException) { } catch (e: IOException) {
@ -220,97 +213,61 @@ fun createDirectory(dirPath: String): Boolean {
} }
} }
/** // 读取文件内容为字节数组
* 获取文件扩展名
*
* @param fileName 文件名
* @return 文件扩展名不包含点号如果无扩展名返回空字符串
*/
fun getFileExtension(fileName: String): String {
if (fileName.isEmpty()) {
return ""
}
val lastDotIndex = fileName!!.lastIndexOf('.')
return if (lastDotIndex == -1 || lastDotIndex == fileName.length - 1) {
""
} else fileName.substring(lastDotIndex + 1)
}
/**
* 获取不带扩展名的文件名
*
* @param fileName 文件名
* @return 不带扩展名的文件名
*/
fun getFileNameWithoutExtension(fileName: String): String {
if (fileName.isEmpty()) {
return ""
}
val lastDotIndex = fileName!!.lastIndexOf('.')
return if (lastDotIndex == -1) {
fileName
} else fileName.substring(0, lastDotIndex)
}
/**
* 读取文件内容为字节数组
*
* @param filePath 文件路径
* @return 文件内容的字节数组
* @throws IOException 读取文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun readFileToByteArray(filePath: String): ByteArray { /**
val path = Paths.get(filePath) * 读取文件内容为字节数组
*
* @return 文件内容的字节数组表示
* @throws IOException 读取文件时发生错误
*/
fun String.readByteArray(): ByteArray {
val path = Paths.get(this)
return Files.readAllBytes(path) return Files.readAllBytes(path)
} }
/** // 将字节数组写入文件
* 将字节数组写入文件
*
* @param filePath 文件路径
* @param data 要写入的字节数据
* @throws IOException 写入文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun writeByteArrayToFile(filePath: String, data: ByteArray) { /**
val path = Paths.get(filePath) * 将字节数组写入文件
*
* @param data 要写入的字节数组
* @throws IOException 写入文件时发生错误
*/
fun String.writeByteArray(data: ByteArray) {
val path = Paths.get(this)
Files.createDirectories(path.parent) Files.createDirectories(path.parent)
Files.write(path, data) Files.write(path, data)
} }
/** // 将字节数组追加到文件末尾
* 将字节数组追加到文件末尾
*
* @param filePath 文件路径
* @param data 要追加的字节数据
* @throws IOException 追加数据时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun appendByteArrayToFile(filePath: String, data: ByteArray) { /**
val path = Paths.get(filePath) * 将字节数组追加到文件末尾
*
* @param data 要追加的字节数组
* @throws IOException 追加文件时发生错误
*/
fun String.appendByteArray(data: ByteArray) {
val path = Paths.get(this)
Files.createDirectories(path.parent) Files.createDirectories(path.parent)
Files.write( Files.write(
path, data, StandardOpenOption.CREATE, StandardOpenOption.APPEND path, data, StandardOpenOption.CREATE, StandardOpenOption.APPEND
) )
} }
/** // 分块读取大文件为字节数组列表
* 分块读取大文件为字节数组列表
*
* @param filePath 文件路径
* @param chunkSize 每块大小字节
* @return 文件内容按指定大小分割的字节数组列表
* @throws IOException 读取文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun readFileToByteArrayChunks(filePath: String, chunkSize: Int): List<ByteArray> { /**
* 分块读取大文件为字节数组列表
*
* @param chunkSize 每个块的大小
* @return 字节数组列表
* @throws IOException 读取文件时发生错误
*/
fun String.readByteArrayChunks(chunkSize: Int): List<ByteArray> {
val chunks = mutableListOf<ByteArray>() val chunks = mutableListOf<ByteArray>()
val path = Paths.get(filePath) val path = Paths.get(this)
Files.newInputStream(path).use { inputStream -> Files.newInputStream(path).use { inputStream ->
val buffer = ByteArray(chunkSize) val buffer = ByteArray(chunkSize)
@ -325,17 +282,16 @@ fun readFileToByteArrayChunks(filePath: String, chunkSize: Int): List<ByteArray>
return chunks return chunks
} }
/** // 将字节数组列表写入文件
* 将字节数组列表写入文件
*
* @param filePath 文件路径
* @param chunks 字节数组列表
* @throws IOException 写入文件时发生错误
*/
@Throws(IOException::class) @Throws(IOException::class)
fun writeByteArrayChunksToFile(filePath: String, chunks: List<ByteArray>) { /**
val path = Paths.get(filePath) * 将字节数组列表写入文件
*
* @param chunks 字节数组列表
* @throws IOException 写入文件时发生错误
*/
fun String.writeByteArrayChunks(chunks: List<ByteArray>) {
val path = Paths.get(this)
Files.createDirectories(path.parent) Files.createDirectories(path.parent)
Files.newOutputStream(path).use { outputStream -> Files.newOutputStream(path).use { outputStream ->
@ -344,3 +300,466 @@ fun writeByteArrayChunksToFile(filePath: String, chunks: List<ByteArray>) {
} }
} }
} }
// 读取文件内容为字符串
@Throws(IOException::class)
/**
* 读取文件内容为字符串使用默认字符集
*
* @return 文件内容的字符串表示
* @throws IOException 读取文件时发生错误
*/
fun Path.readFileToString(): String {
return this.readFileToString(DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 读取文件内容为字符串
*
* @param charset 字符编码格式
* @return 文件内容的字符串表示
* @throws IOException 读取文件时发生错误
*/
fun Path.readFileToString(charset: Charset): String {
val bytes = Files.readAllBytes(this)
return String(bytes, charset)
}
// 将字符串写入文件
@Throws(IOException::class)
/**
* 将字符串写入文件使用默认字符集
*
* @param content 要写入的字符串内容
* @throws IOException 写入文件时发生错误
*/
fun Path.writeStringToFile(content: String) {
this.writeStringToFile(content, DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 将字符串写入文件
*
* @param content 要写入的字符串内容
* @param charset 字符编码格式
* @throws IOException 写入文件时发生错误
*/
fun Path.writeStringToFile(content: String, charset: Charset) {
this.parent?.let { Files.createDirectories(it) }
Files.write(this, content.toByteArray(charset))
}
// 读取文件内容为字符串列表
@Throws(IOException::class)
/**
* 读取文件内容为字符串列表使用默认字符集
*
* @return 按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
fun Path.readLines(): List<String> {
return this.readLines(DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 读取文件内容为字符串列表
*
* @param charset 字符编码格式
* @return 按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
fun Path.readLines(charset: Charset): List<String> {
return Files.readAllLines(this, charset)
}
// 将字符串列表写入文件
@Throws(IOException::class)
/**
* 将字符串列表写入文件使用默认字符集
*
* @param lines 要写入的字符串列表
* @throws IOException 写入文件时发生错误
*/
fun Path.writeLines(lines: List<String>) {
this.writeLines(lines, DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 将字符串列表写入文件
*
* @param lines 要写入的字符串列表
* @param charset 字符编码格式
* @throws IOException 写入文件时发生错误
*/
fun Path.writeLines(lines: List<String>, charset: Charset) {
Files.createDirectories(this.parent)
Files.write(this, lines, charset)
}
// 复制文件
@Throws(IOException::class)
/**
* 复制文件到目标路径
*
* @param target 目标文件路径
* @throws IOException 复制文件时发生错误
*/
fun Path.copyTo(target: Path) {
Files.createDirectories(target.parent)
Files.copy(this, target)
}
// 删除文件
/**
* 删除文件
*
* @return 删除操作是否成功
*/
fun Path.delete(): Boolean {
return try {
Files.deleteIfExists(this)
} catch (e: IOException) {
false
}
}
// 检查文件是否存在
/**
* 检查文件是否存在
*
* @return 文件是否存在
*/
fun Path.exists(): Boolean {
return Files.exists(this)
}
// 获取文件大小
/**
* 获取文件大小
*
* @return 文件大小字节如果获取失败则返回-1
*/
fun Path.getFileSize(): Long {
return try {
Files.size(this)
} catch (e: IOException) {
-1
}
}
// 读取文件内容为字节数组
@Throws(IOException::class)
/**
* 读取文件内容为字节数组
*
* @return 文件内容的字节数组表示
* @throws IOException 读取文件时发生错误
*/
fun Path.readByteArray(): ByteArray {
return Files.readAllBytes(this)
}
// 将字节数组写入文件
@Throws(IOException::class)
/**
* 将字节数组写入文件
*
* @param data 要写入的字节数组
* @throws IOException 写入文件时发生错误
*/
fun Path.writeByteArray(data: ByteArray) {
Files.createDirectories(this.parent)
Files.write(this, data)
}
// 将字节数组追加到文件末尾
@Throws(IOException::class)
/**
* 将字节数组追加到文件末尾
*
* @param data 要追加的字节数组
* @throws IOException 追加文件时发生错误
*/
fun Path.appendByteArray(data: ByteArray) {
Files.createDirectories(this.parent)
Files.write(this, data, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
}
// 分块读取大文件为字节数组列表
@Throws(IOException::class)
/**
* 分块读取大文件为字节数组列表
*
* @param chunkSize 每个块的大小
* @return 字节数组列表
* @throws IOException 读取文件时发生错误
*/
fun Path.readByteArrayChunks(chunkSize: Int): List<ByteArray> {
val chunks = mutableListOf<ByteArray>()
Files.newInputStream(this).use { inputStream ->
val buffer = ByteArray(chunkSize)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
val chunk = ByteArray(bytesRead)
System.arraycopy(buffer, 0, chunk, 0, bytesRead)
chunks.add(chunk)
}
}
return chunks
}
// 将字节数组列表写入文件
@Throws(IOException::class)
/**
* 将字节数组列表写入文件
*
* @param chunks 字节数组列表
* @throws IOException 写入文件时发生错误
*/
fun Path.writeByteArrayChunks(chunks: List<ByteArray>) {
Files.createDirectories(this.parent)
Files.newOutputStream(this).use { outputStream ->
for (chunk in chunks) {
outputStream.write(chunk)
}
}
}
// 读取文件内容为字符串
@Throws(IOException::class)
/**
* 读取文件内容为字符串使用默认字符集
*
* @return 文件内容的字符串表示
* @throws IOException 读取文件时发生错误
*/
fun File.readFileToString(): String {
return this.readFileToString(DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 读取文件内容为字符串
*
* @param charset 字符编码格式
* @return 文件内容的字符串表示
* @throws IOException 读取文件时发生错误
*/
fun File.readFileToString(charset: Charset): String {
return String(this.readBytes(), charset)
}
// 将字符串写入文件
@Throws(IOException::class)
/**
* 将字符串写入文件使用默认字符集
*
* @param content 要写入的字符串内容
* @throws IOException 写入文件时发生错误
*/
fun File.writeStringToFile(content: String) {
this.writeStringToFile(content, DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 将字符串写入文件
*
* @param content 要写入的字符串内容
* @param charset 字符编码格式
* @throws IOException 写入文件时发生错误
*/
fun File.writeStringToFile(content: String, charset: Charset) {
this.parentFile?.mkdirs()
this.writeText(content, charset)
}
// 读取文件内容为字符串列表
@Throws(IOException::class)
/**
* 读取文件内容为字符串列表使用默认字符集
*
* @return 按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
fun File.readLines(): List<String> {
return this.readLines(DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 读取文件内容为字符串列表
*
* @param charset 字符编码格式
* @return 按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
fun File.readLines(charset: Charset): List<String> {
return this.readLines(charset)
}
// 将字符串列表写入文件
@Throws(IOException::class)
/**
* 将字符串列表写入文件使用默认字符集
*
* @param lines 要写入的字符串列表
* @throws IOException 写入文件时发生错误
*/
fun File.writeLines(lines: List<String>) {
this.writeLines(lines, DEFAULT_CHARSET)
}
@Throws(IOException::class)
/**
* 将字符串列表写入文件
*
* @param lines 要写入的字符串列表
* @param charset 字符编码格式
* @throws IOException 写入文件时发生错误
*/
fun File.writeLines(lines: List<String>, charset: Charset) {
this.parentFile?.mkdirs()
this.writeLines(lines, charset)
}
// 复制文件
@Throws(IOException::class)
/**
* 复制文件到目标文件
*
* @param target 目标文件
* @throws IOException 复制文件时发生错误
*/
fun File.copyTo(target: File) {
target.parentFile?.mkdirs()
this.copyTo(target, overwrite = true)
}
// 删除文件
/**
* 删除文件
*
* @return 删除操作是否成功
*/
fun File.delete(): Boolean {
return this.delete()
}
// 检查文件是否存在
/**
* 检查文件是否存在
*
* @return 文件是否存在
*/
fun File.exists(): Boolean {
return this.exists()
}
// 获取文件大小
/**
* 获取文件大小
*
* @return 文件大小字节如果文件不存在则返回-1L
*/
fun File.getFileSize(): Long {
return if (this.exists()) this.length() else -1L
}
// 创建目录
/**
* 创建目录
*
* @return 创建操作是否成功
*/
fun File.createDirectory(): Boolean {
return this.mkdirs()
}
// 读取文件内容为字节数组
@Throws(IOException::class)
/**
* 读取文件内容为字节数组
*
* @return 文件内容的字节数组表示
* @throws IOException 读取文件时发生错误
*/
fun File.readByteArray(): ByteArray {
return this.readBytes()
}
// 将字节数组写入文件
@Throws(IOException::class)
/**
* 将字节数组写入文件
*
* @param data 要写入的字节数组
* @throws IOException 写入文件时发生错误
*/
fun File.writeByteArray(data: ByteArray) {
this.parentFile?.mkdirs()
this.writeBytes(data)
}
// 将字节数组追加到文件末尾
@Throws(IOException::class)
/**
* 将字节数组追加到文件末尾
*
* @param data 要追加的字节数组
* @throws IOException 追加文件时发生错误
*/
fun File.appendByteArray(data: ByteArray) {
this.parentFile?.mkdirs()
this.appendBytes(data)
}
// 分块读取大文件为字节数组列表
@Throws(IOException::class)
/**
* 分块读取大文件为字节数组列表
*
* @param chunkSize 每个块的大小
* @return 字节数组列表
* @throws IOException 读取文件时发生错误
*/
fun File.readByteArrayChunks(chunkSize: Int): List<ByteArray> {
val chunks = mutableListOf<ByteArray>()
this.inputStream().use { inputStream ->
val buffer = ByteArray(chunkSize)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
val chunk = ByteArray(bytesRead)
System.arraycopy(buffer, 0, chunk, 0, bytesRead)
chunks.add(chunk)
}
}
return chunks
}
// 将字节数组列表写入文件
@Throws(IOException::class)
/**
* 将字节数组列表写入文件
*
* @param chunks 字节数组列表
* @throws IOException 写入文件时发生错误
*/
fun File.writeByteArrayChunks(chunks: List<ByteArray>) {
this.parentFile?.mkdirs()
this.outputStream().use { outputStream ->
for (chunk in chunks) {
outputStream.write(chunk)
}
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2026 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Debouncer.kt
* LastUpdate 2026-01-11 09:10:30
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions
import java.util.concurrent.*
/**
* 防抖器类用于实现防抖功能防止在短时间内重复执行相同任务
*
* @author MingLiPro
*/
class Debouncer(private val delay: Long, unit: TimeUnit) {
private val scheduler: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
private val delayedMap: ConcurrentHashMap<Any, Future<*>> = ConcurrentHashMap()
private val delayMillis: Long = unit.toMillis(delay)
/**
* 执行防抖操作如果在指定延迟时间内再次调用相同key的任务则取消之前的任务并重新计时
*
* @param key 任务的唯一标识符用于区分不同任务
* @param task 要执行的任务
*/
fun debounce(key: Any, task: Runnable) {
// 提交新任务并获取之前可能存在的任务
val prev = delayedMap.put(
key,
scheduler.schedule(
{
try {
task.run()
} finally {
// 任务执行完成后从映射中移除
delayedMap.remove(key)
}
},
delayMillis,
TimeUnit.MILLISECONDS
)
)
// 如果之前存在任务,则取消它
if (prev != null) {
prev.cancel(true)
}
}
/**
* 关闭防抖器取消所有待执行的任务并关闭调度器
*/
fun shutdown() {
// 先取消所有延迟任务
for (future in delayedMap.values) {
future.cancel(true)
}
delayedMap.clear()
// 再关闭调度器
scheduler.shutdownNow()
}
}

View File

@ -16,70 +16,14 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile Functions.kt * CurrentFile Functions.kt
* LastUpdate 2026-01-09 08:12:01 * LastUpdate 2026-01-11 09:10:48
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@file:JvmName("Functions")
package com.mingliqiye.utils.functions package com.mingliqiye.utils.functions
import java.util.concurrent.*
/**
* 防抖器类用于实现防抖功能防止在短时间内重复执行相同任务
*
* @author MingLiPro
*/
class Debouncer(private val delay: Long, unit: TimeUnit) {
private val scheduler: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
private val delayedMap: ConcurrentHashMap<Any, Future<*>> = ConcurrentHashMap()
private val delayMillis: Long = unit.toMillis(delay)
/**
* 执行防抖操作如果在指定延迟时间内再次调用相同key的任务则取消之前的任务并重新计时
*
* @param key 任务的唯一标识符用于区分不同任务
* @param task 要执行的任务
*/
fun debounce(key: Any, task: Runnable) {
// 提交新任务并获取之前可能存在的任务
val prev = delayedMap.put(
key,
scheduler.schedule(
{
try {
task.run()
} finally {
// 任务执行完成后从映射中移除
delayedMap.remove(key)
}
},
delayMillis,
TimeUnit.MILLISECONDS
)
)
// 如果之前存在任务,则取消它
if (prev != null) {
prev.cancel(true)
}
}
/**
* 关闭防抖器取消所有待执行的任务并关闭调度器
*/
fun shutdown() {
// 先取消所有延迟任务
for (future in delayedMap.values) {
future.cancel(true)
}
delayedMap.clear()
// 再关闭调度器
scheduler.shutdownNow()
}
}
@FunctionalInterface @FunctionalInterface
fun interface P1Function<P> { fun interface P1Function<P> {
fun call(p: P) fun call(p: P)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2025 mingliqiye * Copyright 2026 mingliqiye
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,7 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile HashUtils.kt * CurrentFile HashUtils.kt
* LastUpdate 2025-09-19 20:24:33 * LastUpdate 2026-01-11 09:09:52
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@file:JvmName("HashUtils") @file:JvmName("HashUtils")
@ -24,9 +24,9 @@
package com.mingliqiye.utils.hash package com.mingliqiye.utils.hash
import com.mingliqiye.utils.base.BASE16
import com.mingliqiye.utils.bcrypt.checkpw import com.mingliqiye.utils.bcrypt.checkpw
import com.mingliqiye.utils.bcrypt.hashpw import com.mingliqiye.utils.bcrypt.hashpw
import com.mingliqiye.utils.bytes.bytesToHex
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.IOException import java.io.IOException
@ -64,16 +64,6 @@ fun calculateFileHash(file: File, algorithm: String): String {
return bytesToHex(digest.digest()) return bytesToHex(digest.digest())
} }
/**
* 将字节数组转换为十六进制字符串表示
*
* @param bytes 输入的字节数组
* @return 对应的十六进制字符串
*/
private fun bytesToHex(bytes: ByteArray): String {
return BASE16.encode(bytes)
}
/** /**
* 使用 BCrypt 算法对字符串进行加密 * 使用 BCrypt 算法对字符串进行加密
* *

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2025 mingliqiye * Copyright 2026 mingliqiye
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,13 +16,16 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile QueryWrapper.kt * CurrentFile QueryWrapper.kt
* LastUpdate 2025-09-20 14:21:44 * LastUpdate 2026-01-14 13:00:31
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
package com.mingliqiye.utils.mybatisplus package com.mingliqiye.utils.mybatisplus
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper import com.baomidou.mybatisplus.core.mapper.BaseMapper
/** /**
@ -39,4 +42,31 @@ interface BaseMapperQuery<T> : BaseMapper<T> {
fun queryWrapper(): QueryWrapper<T> { fun queryWrapper(): QueryWrapper<T> {
return QueryWrapper<T>() return QueryWrapper<T>()
} }
/**
* 创建并返回一个新的UpdateWrapper实例
*
* @return UpdateWrapper<T> 返回类型化的更新包装器实例
*/
fun updateWrapper(): UpdateWrapper<T> {
return UpdateWrapper<T>()
}
/**
* 创建并返回一个新的LambdaQueryWrapper实例
*
* @return LambdaQueryWrapper<T> 返回类型化的Lambda查询包装器实例
*/
fun lambdaQueryWrapper(): LambdaQueryWrapper<T> {
return LambdaQueryWrapper<T>()
}
/**
* 创建并返回一个新的LambdaUpdateWrapper实例
*
* @return LambdaUpdateWrapper<T> 返回类型化的Lambda更新包装器实例
*/
fun lambdaUpdateWrapper(): LambdaUpdateWrapper<T> {
return LambdaUpdateWrapper<T>()
}
} }

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile Require.kt * CurrentFile Require.kt
* LastUpdate 2026-01-10 08:53:26 * LastUpdate 2026-01-10 09:01:03
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@ -25,14 +25,56 @@ package com.mingliqiye.utils.request
import com.mingliqiye.utils.functions.P1RFunction import com.mingliqiye.utils.functions.P1RFunction
import com.mingliqiye.utils.functions.RFunction import com.mingliqiye.utils.functions.RFunction
/**
* 扩展函数基于布尔值创建Require对象并指定异常消息和异常构造器
* @param message 异常消息
* @param exception 异常构造器函数
* @return Require对象
*/
fun Boolean.require(message: String, exception: P1RFunction<String, out Exception>): Require {
return Require(this, message, exception)
}
/**
* 扩展函数基于布尔值创建Require对象并指定异常消息和异常类型
* @param message 异常消息
* @param exception 异常类型默认为IllegalArgumentException
* @return Require对象
*/
fun Boolean.require(
message: String,
exception: Class<out Exception> = IllegalArgumentException::class.java
): Require {
return Require(this, message, exception)
}
/**
* 条件检查工具类用于验证条件并抛出相应异常
* @param must 需要验证的布尔条件
*/
class Require(private val must: Boolean) { class Require(private val must: Boolean) {
/**
* 构造函数通过函数调用结果初始化条件检查器
* @param funs 返回布尔值的函数
*/
constructor(funs: RFunction<Boolean>) : this(funs.call()) constructor(funs: RFunction<Boolean>) : this(funs.call())
/**
* 构造函数通过函数调用结果初始化条件检查器并立即执行检查
* @param must 返回布尔值的函数
* @param message 检查失败时的异常消息
*/
constructor(must: RFunction<Boolean>, message: String) : this(must) { constructor(must: RFunction<Boolean>, message: String) : this(must) {
throws(message) throws(message)
} }
/**
* 构造函数通过函数调用结果初始化条件检查器并立即执行检查
* @param must 返回布尔值的函数
* @param message 检查失败时的异常消息
* @param exception 检查失败时抛出的异常类型默认为IllegalArgumentException
*/
constructor( constructor(
must: RFunction<Boolean>, must: RFunction<Boolean>,
message: String, message: String,
@ -41,16 +83,33 @@ class Require(private val must: Boolean) {
throws(message, exception) throws(message, exception)
} }
/**
* 构造函数通过布尔值初始化条件检查器并立即执行检查
* @param must 需要验证的布尔条件
* @param message 检查失败时的异常消息
*/
constructor(must: Boolean, message: String) : this(must) { constructor(must: Boolean, message: String) : this(must) {
throws(message) throws(message)
} }
/**
* 构造函数通过布尔值初始化条件检查器并立即执行检查
* @param must 需要验证的布尔条件
* @param message 检查失败时的异常消息
* @param exception 检查失败时抛出的异常类型默认为IllegalArgumentException
*/
constructor( constructor(
must: Boolean, message: String, exception: Class<out Exception> = IllegalArgumentException::class.java must: Boolean, message: String, exception: Class<out Exception> = IllegalArgumentException::class.java
) : this(must) { ) : this(must) {
throws(message, exception) throws(message, exception)
} }
/**
* 构造函数通过布尔值初始化条件检查器并立即执行检查
* @param must 需要验证的布尔条件
* @param message 检查失败时的异常消息
* @param exception 检查失败时抛出的异常构造器函数
*/
constructor( constructor(
must: Boolean, message: String, exception: P1RFunction<String, out Exception> must: Boolean, message: String, exception: P1RFunction<String, out Exception>
) : this(must) { ) : this(must) {
@ -58,17 +117,14 @@ class Require(private val must: Boolean) {
} }
companion object { companion object {
fun Boolean.require(message: String, exception: P1RFunction<String, out Exception>): Require {
return Require(this, message, exception)
}
fun Boolean.require(
message: String,
exception: Class<out Exception> = IllegalArgumentException::class.java
): Require {
return Require(this, message, exception)
}
/**
* 工厂方法创建Require对象并指定异常消息和异常类型
* @param must 需要验证的布尔条件
* @param message 检查失败时的异常消息
* @param exception 检查失败时抛出的异常类型默认为IllegalArgumentException
* @return Require对象
*/
@JvmStatic @JvmStatic
fun require( fun require(
must: Boolean, message: String, exception: Class<out Exception> = IllegalArgumentException::class.java must: Boolean, message: String, exception: Class<out Exception> = IllegalArgumentException::class.java
@ -76,16 +132,34 @@ class Require(private val must: Boolean) {
return Require(must, message, exception) return Require(must, message, exception)
} }
/**
* 工厂方法创建Require对象并指定异常消息
* @param must 需要验证的布尔条件
* @param message 检查失败时的异常消息
* @return Require对象
*/
@JvmStatic @JvmStatic
fun require(must: Boolean, message: String): Require { fun require(must: Boolean, message: String): Require {
return Require(must, message) return Require(must, message)
} }
/**
* 工厂方法创建Require对象
* @param must 需要验证的布尔条件
* @return Require对象
*/
@JvmStatic @JvmStatic
fun require(must: Boolean): Require { fun require(must: Boolean): Require {
return Require(must) return Require(must)
} }
/**
* 工厂方法创建Require对象并指定异常消息和异常类型
* @param must 返回布尔值的函数
* @param message 检查失败时的异常消息
* @param exception 检查失败时抛出的异常类型默认为IllegalArgumentException
* @return Require对象
*/
@JvmStatic @JvmStatic
fun require( fun require(
must: RFunction<Boolean>, must: RFunction<Boolean>,
@ -95,29 +169,54 @@ class Require(private val must: Boolean) {
return Require(must, message, exception) return Require(must, message, exception)
} }
/**
* 工厂方法创建Require对象并指定异常消息
* @param must 返回布尔值的函数
* @param message 检查失败时的异常消息
* @return Require对象
*/
@JvmStatic @JvmStatic
fun require(must: RFunction<Boolean>, message: String): Require { fun require(must: RFunction<Boolean>, message: String): Require {
return Require(must, message) return Require(must, message)
} }
/**
* 工厂方法创建Require对象
* @param must 返回布尔值的函数
* @return Require对象
*/
@JvmStatic @JvmStatic
fun require(must: RFunction<Boolean>): Require { fun require(must: RFunction<Boolean>): Require {
return Require(must) return Require(must)
} }
} }
/**
* 执行条件检查如果条件为false则抛出IllegalArgumentException
* @param message 检查失败时的异常消息
*/
fun throws(message: String) { fun throws(message: String) {
if (!must) { if (!must) {
throw IllegalArgumentException(message) throw IllegalArgumentException(message)
} }
} }
/**
* 执行条件检查如果条件为false则抛出指定类型的异常
* @param string 检查失败时的异常消息
* @param exception 检查失败时抛出的异常类型
*/
fun throws(string: String, exception: Class<out Exception>) { fun throws(string: String, exception: Class<out Exception>) {
if (!must) { if (!must) {
throw exception.getConstructor(String::class.java).newInstance(string) throw exception.getConstructor(String::class.java).newInstance(string)
} }
} }
/**
* 执行条件检查如果条件为false则抛出由函数构造的异常
* @param string 检查失败时的异常消息
* @param exception 检查失败时抛出的异常构造器函数
*/
fun throws(string: String, exception: P1RFunction<String, out Exception>) { fun throws(string: String, exception: P1RFunction<String, out Exception>) {
if (!must) { if (!must) {
throw exception.call(string) throw exception.call(string)