From f2ee83ca642cbc7266b9bdf9a7e4a8d0c9155df5 Mon Sep 17 00:00:00 2001 From: minglipro Date: Wed, 14 Jan 2026 13:01:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(utils):=20=E6=B7=BB=E5=8A=A0ByteBuffer?= =?UTF-8?q?=E5=8F=98=E9=95=BF=E6=95=B0=E5=AD=97=E7=BC=96=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=E5=92=8C=E9=98=B2=E6=8A=96=E5=99=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在ByteBufferUtils中添加getVarLong、getVarInt、getVarShort读取变长数字功能 - 在ByteBufferUtils中添加putVarLong、putVarInt、putVarShort写入变长数字功能 - 新增Debouncer防抖器类用于防止短时间内重复执行任务 - 更新build.gradle.kts中mybatis-plus-core依赖版本至3.5.15 - 优化FileUtils中文件操作方法,增加Path和File类型的扩展函数 - 添加字节转义字符常量定义和hex字符串转换工具方法 --- build.gradle.kts | 4 +- gradle.properties | 4 +- src/main/kotlin/com/mingliqiye/utils/Main.kt | 42 - .../mingliqiye/utils/bytes/ByteBufferUtils.kt | 96 ++- .../com/mingliqiye/utils/bytes/ByteUtils.kt | 75 +- .../NumberUtils.kt => bytes/StreamUtils.kt} | 90 +- .../com/mingliqiye/utils/file/FileUtils.kt | 801 +++++++++++++----- .../mingliqiye/utils/functions/Debouncer.kt | 81 ++ .../mingliqiye/utils/functions/Functions.kt | 62 +- .../com/mingliqiye/utils/hash/HashUtils.kt | 16 +- .../utils/mybatisplus/QueryWrapper.kt | 34 +- .../com/mingliqiye/utils/request/Require.kt | 121 ++- 12 files changed, 1077 insertions(+), 349 deletions(-) delete mode 100644 src/main/kotlin/com/mingliqiye/utils/Main.kt rename src/main/kotlin/com/mingliqiye/utils/{number/NumberUtils.kt => bytes/StreamUtils.kt} (52%) create mode 100644 src/main/kotlin/com/mingliqiye/utils/functions/Debouncer.kt diff --git a/build.gradle.kts b/build.gradle.kts index 30d148f..22830a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils * CurrentFile build.gradle.kts - * LastUpdate 2026-01-08 11:10:03 + * LastUpdate 2026-01-14 13:01:44 * UpdateUser MingLiPro */ @@ -78,7 +78,7 @@ dependencies { compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58") 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") } diff --git a/gradle.properties b/gradle.properties index c7ca03a..fdcb12e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,13 +16,13 @@ # ProjectName mingli-utils # ModuleName mingli-utils # CurrentFile gradle.properties -# LastUpdate 2026-01-10 08:55:10 +# LastUpdate 2026-01-14 13:01:41 # UpdateUser MingLiPro # JDKVERSIONS=1.8 GROUPSID=com.mingliqiye.utils ARTIFACTID=mingli-utils -VERSIONS=4.3.3 +VERSIONS=4.3.5 signing.keyId=B22AA93B signing.password= signing.secretKeyRingFile=secret.gpg diff --git a/src/main/kotlin/com/mingliqiye/utils/Main.kt b/src/main/kotlin/com/mingliqiye/utils/Main.kt deleted file mode 100644 index 93a4798..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/Main.kt +++ /dev/null @@ -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)) - -} diff --git a/src/main/kotlin/com/mingliqiye/utils/bytes/ByteBufferUtils.kt b/src/main/kotlin/com/mingliqiye/utils/bytes/ByteBufferUtils.kt index 14ed4fb..551e3e8 100644 --- a/src/main/kotlin/com/mingliqiye/utils/bytes/ByteBufferUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/bytes/ByteBufferUtils.kt @@ -16,14 +16,16 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile ByteBufferUtils.kt - * LastUpdate 2026-01-07 10:01:45 + * LastUpdate 2026-01-11 09:44:19 * UpdateUser MingLiPro */ -@file:JvmName("ByteBufferUtil") +@file:JvmName("ByteBufferUtils") package com.mingliqiye.utils.bytes +import java.io.IOException +import java.io.OutputStream import java.nio.ByteBuffer import java.nio.charset.Charset @@ -203,3 +205,93 @@ fun ByteBuffer.putBoolean(boolean: Boolean): ByteBuffer = this.put(if (boolean) fun ByteArray.toByteBuffer(): ByteBuffer { 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()) diff --git a/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtils.kt b/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtils.kt index b189cc0..8a9c844 100644 --- a/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * 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. @@ -16,28 +16,74 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile ByteUtils.kt - * LastUpdate 2025-09-20 11:49:05 + * LastUpdate 2026-01-14 13:01:44 * UpdateUser MingLiPro */ @file:JvmName("ByteUtils") package com.mingliqiye.utils.bytes +import com.mingliqiye.utils.base.BASE16 import com.mingliqiye.utils.stream.SuperStream +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_ASC: Byte = 0x10 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_DESC: Byte = 0x1B + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_NONE: Byte = 0x00 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_START: Byte = 0x01 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_END: Byte = 0x02 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_ESC: Byte = 0x03 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_CONTROL: Byte = 0x04 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_DATA: Byte = 0x05 + +/** + * 转义字符常量定义 + * 定义了用于数据传输或协议通信中的特殊控制字节值 + */ const val ESC_RESERVED: Byte = 0x06 /** * 将字节数组转换为十六进制字符串列表 + * @receiver 字节数组 * @return 包含每个字节对应十六进制字符串的列表 */ fun ByteArray.getByteArrayString(): MutableList { @@ -46,6 +92,12 @@ fun ByteArray.getByteArrayString(): MutableList { } +/** + * 将十六进制字符转换为对应的数值 + * @receiver 十六进制字符 + * @return 对应的数值(0-15) + * @throws NumberFormatException 当字符不是有效的十六进制字符时抛出 + */ fun Char.hexDigitToValue(): Int { return when (this) { 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() } + + +/** + * 将字节数组转换为十六进制字符串表示。 + * + * @param bytes 输入的字节数组 + * @return 对应的十六进制字符串 + */ +fun bytesToHex(bytes: ByteArray): String { + return BASE16.encode(bytes) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/number/NumberUtils.kt b/src/main/kotlin/com/mingliqiye/utils/bytes/StreamUtils.kt similarity index 52% rename from src/main/kotlin/com/mingliqiye/utils/number/NumberUtils.kt rename to src/main/kotlin/com/mingliqiye/utils/bytes/StreamUtils.kt index c638dfe..dad6dc0 100644 --- a/src/main/kotlin/com/mingliqiye/utils/number/NumberUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/bytes/StreamUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * 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. @@ -15,17 +15,17 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile NumberUtils.kt - * LastUpdate 2025-09-16 15:59:45 + * CurrentFile StreamUtils.kt + * LastUpdate 2026-01-11 09:41:14 * UpdateUser MingLiPro */ +@file:JvmName("StreamUtils") -@file:JvmName("NumberUtils") - -package com.mingliqiye.utils.number +package com.mingliqiye.utils.bytes import java.io.IOException import java.io.InputStream +import java.io.OutputStream /** @@ -35,25 +35,22 @@ import java.io.InputStream * - 如果最高位为1,则表示还有下一个字节; * - 如果最高位为0,则表示当前字节是最后一个字节。 * - * @param input 输入流,用于读取数据。 * @param size 最大允许读取的字节数,默认为8(即Long类型的最大长度)。 * @return 解码后的长整型数值。 * @throws IOException 当读取过程中发生IO异常或到达流末尾时抛出。 */ @Throws(IOException::class) -fun readVarNumber(input: InputStream, size: Int = 10): Long { +fun InputStream.readVarNumber(size: Int = 8): Long { var numRead = 0 var result: Long = 0 var read: Byte do { - read = input.read().let { + read = this.read().let { if (it == -1) { throw IOException("Reached end of stream") } it.toByte() } - - // 将当前字节的有效7位数据左移相应位数,并与结果进行或运算 result = result or ((read.toLong() and 127) shl (7 * numRead)) numRead++ if (numRead > size) { @@ -66,35 +63,84 @@ fun readVarNumber(input: InputStream, size: Int = 10): Long { /** * 从输入流中读取一个变长整数(VarInt),最大长度限制为4个字节。 * - * @param input 输入流,用于读取数据。 * @return 解码后的整型数值。 * @throws IOException 当读取过程中发生IO异常时抛出。 */ @Throws(IOException::class) -fun readVarInt(input: InputStream): Int { - return readVarNumber(input, size = 4).toInt() -} +fun InputStream.readVarInt(): Int = this.readVarNumber(4).toInt() + /** * 从输入流中读取一个变长短整数(VarShort),最大长度限制为2个字节。 * - * @param input 输入流,用于读取数据。 * @return 解码后的短整型数值。 * @throws IOException 当读取过程中发生IO异常时抛出。 */ @Throws(IOException::class) -fun readVarShort(input: InputStream): Short { - return readVarNumber(input, size = 2).toShort() -} +fun InputStream.readVarShort(): Short = this.readVarNumber(2).toShort() + /** * 从输入流中读取一个变长长整数(VarLong),最大长度默认为8个字节。 * - * @param input 输入流,用于读取数据。 * @return 解码后的长整型数值。 * @throws IOException 当读取过程中发生IO异常时抛出。 */ @Throws(IOException::class) -fun readVarLong(input: InputStream): Long { - return readVarNumber(input) +fun InputStream.readVarLong(): Long = this.readVarNumber() + +/** + * 将长整型数值编码为变长格式并写入输出流 + * + * 变长整数使用可变长度编码方式,每个字节的最高位表示是否还有后续字节: + * - 如果数值还有更多字节,则最高位设为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) diff --git a/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt b/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt index 3d02b31..56d8375 100644 --- a/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * 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. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile FileUtils.kt - * LastUpdate 2025-09-15 09:12:47 + * LastUpdate 2026-01-11 09:20:20 * UpdateUser MingLiPro */ @file:JvmName("FileUtils") @@ -24,195 +24,188 @@ package com.mingliqiye.utils.file import com.mingliqiye.utils.path.OsPath +import java.io.File import java.io.IOException import java.nio.charset.Charset import java.nio.charset.StandardCharsets import java.nio.file.Files +import java.nio.file.Path import java.nio.file.Paths import java.nio.file.StandardOpenOption /** * 默认字符集 */ - var DEFAULT_CHARSET: Charset = StandardCharsets.UTF_8 -/** - * 读取文件内容为字符串 - * - * @param filePath 文件路径 - * @return 文件内容字符串 - * @throws IOException 读取文件时发生错误 - */ - +// 读取文件内容为字符串 @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) -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) return String(bytes, charset) } -/** - * 将字符串写入文件 - * - * @param filePath 文件路径 - * @param content 要写入的内容 - * @throws IOException 写入文件时发生错误 - */ +// 将字符串写入文件 @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) -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) } Files.write(path, content.toByteArray(charset)) } -/** - * 读取文件内容为字符串列表(按行分割) - * - * @param filePath 文件路径 - * @return 文件内容按行分割的字符串列表 - * @throws IOException 读取文件时发生错误 - */ +// 读取文件内容为字符串列表(按行分割) @Throws(IOException::class) -fun readLines(filePath: String): List { - return readLines(filePath, DEFAULT_CHARSET) + /** + * 读取文件内容为字符串列表(按行分割),使用默认字符集 + * + * @return 按行分割的字符串列表 + * @throws IOException 读取文件时发生错误 + */ +fun String.readLines(): List { + return this.readLines(DEFAULT_CHARSET) } -/** - * 读取文件内容为字符串列表(按行分割) - * - * @param filePath 文件路径 - * @param charset 字符集 - * @return 文件内容按行分割的字符串列表 - * @throws IOException 读取文件时发生错误 - */ @Throws(IOException::class) -fun readLines(filePath: String, charset: Charset): List { - val path = Paths.get(filePath) + /** + * 读取文件内容为字符串列表(按行分割) + * + * @param charset 字符编码格式 + * @return 按行分割的字符串列表 + * @throws IOException 读取文件时发生错误 + */ +fun String.readLines(charset: Charset): List { + val path = Paths.get(this) return Files.readAllLines(path, charset) } -/** - * 将字符串列表写入文件(每行一个元素) - * - * @param filePath 文件路径 - * @param lines 要写入的行内容列表 - * @throws IOException 写入文件时发生错误 - */ +// 将字符串列表写入文件(每行一个元素) @Throws(IOException::class) -fun writeLines(filePath: String, lines: List) { - writeLines(filePath, lines, DEFAULT_CHARSET) + /** + * 将字符串列表写入文件(每行一个元素),使用默认字符集 + * + * @param lines 要写入的字符串列表 + * @throws IOException 写入文件时发生错误 + */ +fun String.writeLines(lines: List) { + this.writeLines(lines, DEFAULT_CHARSET) } -/** - * 将字符串列表写入文件(每行一个元素) - * - * @param filePath 文件路径 - * @param lines 要写入的行内容列表 - * @param charset 字符集 - * @throws IOException 写入文件时发生错误 - */ @Throws(IOException::class) -fun writeLines(filePath: String, lines: List, charset: Charset) { - val path = Paths.get(filePath) + /** + * 将字符串列表写入文件(每行一个元素) + * + * @param lines 要写入的字符串列表 + * @param charset 字符编码格式 + * @throws IOException 写入文件时发生错误 + */ +fun String.writeLines(lines: List, charset: Charset) { + val path = Paths.get(this) Files.createDirectories(path.parent) Files.write(path, lines, charset) } -/** - * 复制文件 - * - * @param sourcePath 源文件路径 - * @param targetPath 目标文件路径 - * @throws IOException 复制文件时发生错误 - */ +// 复制文件 @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) Files.createDirectories(target.parent) Files.copy(source, target) } +// 删除文件 /** * 删除文件 * - * @param filePath 文件路径 - * @return 如果文件删除成功返回true,否则返回false + * @return 删除操作是否成功 */ -fun deleteFile(filePath: String): Boolean { +fun String.deleteFile(): Boolean { return try { - val path = Paths.get(filePath) + val path = Paths.get(this) Files.deleteIfExists(path) } catch (e: IOException) { false } } +// 检查文件是否存在 /** * 检查文件是否存在 * - * @param filePath 文件路径 - * @return 如果文件存在返回true,否则返回false + * @return 文件是否存在 */ -fun exists(filePath: String): Boolean { - val path = Paths.get(filePath) +fun String.exists(): Boolean { + val path = Paths.get(this) return Files.exists(path) } +// 获取文件大小 /** * 获取文件大小 * - * @param filePath 文件路径 - * @return 文件大小(字节),如果文件不存在返回-1 + * @return 文件大小(字节),如果获取失败则返回-1 */ - -fun getFileSize(filePath: String): Long { +fun String.getFileSize(): Long { return try { - val path = Paths.get(filePath) + val path = Paths.get(this) Files.size(path) } catch (e: IOException) { -1 } } +// 创建目录 /** * 创建目录 * - * @param dirPath 目录路径 - * @return 如果目录创建成功返回true,否则返回false + * @return 创建操作是否成功 */ - -fun createDirectory(dirPath: String): Boolean { +fun String.createDirectory(): Boolean { return try { - val path = Paths.get(dirPath) + val path = Paths.get(this) Files.createDirectories(path) true } 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) -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) } -/** - * 将字节数组写入文件 - * - * @param filePath 文件路径 - * @param data 要写入的字节数据 - * @throws IOException 写入文件时发生错误 - */ - +// 将字节数组写入文件 @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.write(path, data) } -/** - * 将字节数组追加到文件末尾 - * - * @param filePath 文件路径 - * @param data 要追加的字节数据 - * @throws IOException 追加数据时发生错误 - */ - +// 将字节数组追加到文件末尾 @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.write( path, data, StandardOpenOption.CREATE, StandardOpenOption.APPEND ) } -/** - * 分块读取大文件为字节数组列表 - * - * @param filePath 文件路径 - * @param chunkSize 每块大小(字节) - * @return 文件内容按指定大小分割的字节数组列表 - * @throws IOException 读取文件时发生错误 - */ - +// 分块读取大文件为字节数组列表 @Throws(IOException::class) -fun readFileToByteArrayChunks(filePath: String, chunkSize: Int): List { + /** + * 分块读取大文件为字节数组列表 + * + * @param chunkSize 每个块的大小 + * @return 字节数组列表 + * @throws IOException 读取文件时发生错误 + */ +fun String.readByteArrayChunks(chunkSize: Int): List { val chunks = mutableListOf() - val path = Paths.get(filePath) + val path = Paths.get(this) Files.newInputStream(path).use { inputStream -> val buffer = ByteArray(chunkSize) @@ -325,17 +282,16 @@ fun readFileToByteArrayChunks(filePath: String, chunkSize: Int): List return chunks } -/** - * 将字节数组列表写入文件 - * - * @param filePath 文件路径 - * @param chunks 字节数组列表 - * @throws IOException 写入文件时发生错误 - */ - +// 将字节数组列表写入文件 @Throws(IOException::class) -fun writeByteArrayChunksToFile(filePath: String, chunks: List) { - val path = Paths.get(filePath) + /** + * 将字节数组列表写入文件 + * + * @param chunks 字节数组列表 + * @throws IOException 写入文件时发生错误 + */ +fun String.writeByteArrayChunks(chunks: List) { + val path = Paths.get(this) Files.createDirectories(path.parent) Files.newOutputStream(path).use { outputStream -> @@ -344,3 +300,466 @@ fun writeByteArrayChunksToFile(filePath: String, chunks: List) { } } } + +// 读取文件内容为字符串 +@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 { + return this.readLines(DEFAULT_CHARSET) +} + +@Throws(IOException::class) + /** + * 读取文件内容为字符串列表 + * + * @param charset 字符编码格式 + * @return 按行分割的字符串列表 + * @throws IOException 读取文件时发生错误 + */ +fun Path.readLines(charset: Charset): List { + return Files.readAllLines(this, charset) +} + +// 将字符串列表写入文件 +@Throws(IOException::class) + /** + * 将字符串列表写入文件,使用默认字符集 + * + * @param lines 要写入的字符串列表 + * @throws IOException 写入文件时发生错误 + */ +fun Path.writeLines(lines: List) { + this.writeLines(lines, DEFAULT_CHARSET) +} + +@Throws(IOException::class) + /** + * 将字符串列表写入文件 + * + * @param lines 要写入的字符串列表 + * @param charset 字符编码格式 + * @throws IOException 写入文件时发生错误 + */ +fun Path.writeLines(lines: List, 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 { + val chunks = mutableListOf() + + 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) { + 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 { + return this.readLines(DEFAULT_CHARSET) +} + +@Throws(IOException::class) + /** + * 读取文件内容为字符串列表 + * + * @param charset 字符编码格式 + * @return 按行分割的字符串列表 + * @throws IOException 读取文件时发生错误 + */ +fun File.readLines(charset: Charset): List { + return this.readLines(charset) +} + +// 将字符串列表写入文件 +@Throws(IOException::class) + /** + * 将字符串列表写入文件,使用默认字符集 + * + * @param lines 要写入的字符串列表 + * @throws IOException 写入文件时发生错误 + */ +fun File.writeLines(lines: List) { + this.writeLines(lines, DEFAULT_CHARSET) +} + +@Throws(IOException::class) + /** + * 将字符串列表写入文件 + * + * @param lines 要写入的字符串列表 + * @param charset 字符编码格式 + * @throws IOException 写入文件时发生错误 + */ +fun File.writeLines(lines: List, 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 { + val chunks = mutableListOf() + + 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) { + this.parentFile?.mkdirs() + + this.outputStream().use { outputStream -> + for (chunk in chunks) { + outputStream.write(chunk) + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/functions/Debouncer.kt b/src/main/kotlin/com/mingliqiye/utils/functions/Debouncer.kt new file mode 100644 index 0000000..a9aecd4 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/functions/Debouncer.kt @@ -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> = 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() + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt b/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt index 5a5cdd2..ece9ab7 100644 --- a/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt +++ b/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt @@ -16,70 +16,14 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Functions.kt - * LastUpdate 2026-01-09 08:12:01 + * LastUpdate 2026-01-11 09:10:48 * UpdateUser MingLiPro */ +@file:JvmName("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> = 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 fun interface P1Function

{ fun call(p: P) diff --git a/src/main/kotlin/com/mingliqiye/utils/hash/HashUtils.kt b/src/main/kotlin/com/mingliqiye/utils/hash/HashUtils.kt index 77e52cd..177e319 100644 --- a/src/main/kotlin/com/mingliqiye/utils/hash/HashUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/hash/HashUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * 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. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile HashUtils.kt - * LastUpdate 2025-09-19 20:24:33 + * LastUpdate 2026-01-11 09:09:52 * UpdateUser MingLiPro */ @file:JvmName("HashUtils") @@ -24,9 +24,9 @@ package com.mingliqiye.utils.hash -import com.mingliqiye.utils.base.BASE16 import com.mingliqiye.utils.bcrypt.checkpw import com.mingliqiye.utils.bcrypt.hashpw +import com.mingliqiye.utils.bytes.bytesToHex import java.io.File import java.io.FileInputStream import java.io.IOException @@ -64,16 +64,6 @@ fun calculateFileHash(file: File, algorithm: String): String { return bytesToHex(digest.digest()) } -/** - * 将字节数组转换为十六进制字符串表示。 - * - * @param bytes 输入的字节数组 - * @return 对应的十六进制字符串 - */ -private fun bytesToHex(bytes: ByteArray): String { - return BASE16.encode(bytes) -} - /** * 使用 BCrypt 算法对字符串进行加密。 * diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt b/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt index 3c3dbf0..7403add 100644 --- a/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt +++ b/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * 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. @@ -16,13 +16,16 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile QueryWrapper.kt - * LastUpdate 2025-09-20 14:21:44 + * LastUpdate 2026-01-14 13:00:31 * UpdateUser MingLiPro */ 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.update.LambdaUpdateWrapper +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper import com.baomidou.mybatisplus.core.mapper.BaseMapper /** @@ -39,4 +42,31 @@ interface BaseMapperQuery : BaseMapper { fun queryWrapper(): QueryWrapper { return QueryWrapper() } + + /** + * 创建并返回一个新的UpdateWrapper实例 + * + * @return UpdateWrapper 返回类型化的更新包装器实例 + */ + fun updateWrapper(): UpdateWrapper { + return UpdateWrapper() + } + + /** + * 创建并返回一个新的LambdaQueryWrapper实例 + * + * @return LambdaQueryWrapper 返回类型化的Lambda查询包装器实例 + */ + fun lambdaQueryWrapper(): LambdaQueryWrapper { + return LambdaQueryWrapper() + } + + /** + * 创建并返回一个新的LambdaUpdateWrapper实例 + * + * @return LambdaUpdateWrapper 返回类型化的Lambda更新包装器实例 + */ + fun lambdaUpdateWrapper(): LambdaUpdateWrapper { + return LambdaUpdateWrapper() + } } diff --git a/src/main/kotlin/com/mingliqiye/utils/request/Require.kt b/src/main/kotlin/com/mingliqiye/utils/request/Require.kt index bcc76a6..0e687f9 100644 --- a/src/main/kotlin/com/mingliqiye/utils/request/Require.kt +++ b/src/main/kotlin/com/mingliqiye/utils/request/Require.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Require.kt - * LastUpdate 2026-01-10 08:53:26 + * LastUpdate 2026-01-10 09:01:03 * UpdateUser MingLiPro */ @@ -25,14 +25,56 @@ package com.mingliqiye.utils.request import com.mingliqiye.utils.functions.P1RFunction import com.mingliqiye.utils.functions.RFunction +/** + * 扩展函数:基于布尔值创建Require对象,并指定异常消息和异常构造器 + * @param message 异常消息 + * @param exception 异常构造器函数 + * @return Require对象 + */ +fun Boolean.require(message: String, exception: P1RFunction): Require { + return Require(this, message, exception) +} + +/** + * 扩展函数:基于布尔值创建Require对象,并指定异常消息和异常类型 + * @param message 异常消息 + * @param exception 异常类型,默认为IllegalArgumentException + * @return Require对象 + */ +fun Boolean.require( + message: String, + exception: Class = IllegalArgumentException::class.java +): Require { + return Require(this, message, exception) +} + +/** + * 条件检查工具类,用于验证条件并抛出相应异常 + * @param must 需要验证的布尔条件 + */ class Require(private val must: Boolean) { + /** + * 构造函数:通过函数调用结果初始化条件检查器 + * @param funs 返回布尔值的函数 + */ constructor(funs: RFunction) : this(funs.call()) + /** + * 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查 + * @param must 返回布尔值的函数 + * @param message 检查失败时的异常消息 + */ constructor(must: RFunction, message: String) : this(must) { throws(message) } + /** + * 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查 + * @param must 返回布尔值的函数 + * @param message 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException + */ constructor( must: RFunction, message: String, @@ -41,16 +83,33 @@ class Require(private val must: Boolean) { throws(message, exception) } + /** + * 构造函数:通过布尔值初始化条件检查器,并立即执行检查 + * @param must 需要验证的布尔条件 + * @param message 检查失败时的异常消息 + */ constructor(must: Boolean, message: String) : this(must) { throws(message) } + /** + * 构造函数:通过布尔值初始化条件检查器,并立即执行检查 + * @param must 需要验证的布尔条件 + * @param message 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException + */ constructor( must: Boolean, message: String, exception: Class = IllegalArgumentException::class.java ) : this(must) { throws(message, exception) } + /** + * 构造函数:通过布尔值初始化条件检查器,并立即执行检查 + * @param must 需要验证的布尔条件 + * @param message 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常构造器函数 + */ constructor( must: Boolean, message: String, exception: P1RFunction ) : this(must) { @@ -58,17 +117,14 @@ class Require(private val must: Boolean) { } companion object { - fun Boolean.require(message: String, exception: P1RFunction): Require { - return Require(this, message, exception) - } - - fun Boolean.require( - message: String, - exception: Class = IllegalArgumentException::class.java - ): Require { - return Require(this, message, exception) - } + /** + * 工厂方法:创建Require对象并指定异常消息和异常类型 + * @param must 需要验证的布尔条件 + * @param message 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException + * @return Require对象 + */ @JvmStatic fun require( must: Boolean, message: String, exception: Class = IllegalArgumentException::class.java @@ -76,16 +132,34 @@ class Require(private val must: Boolean) { return Require(must, message, exception) } + /** + * 工厂方法:创建Require对象并指定异常消息 + * @param must 需要验证的布尔条件 + * @param message 检查失败时的异常消息 + * @return Require对象 + */ @JvmStatic fun require(must: Boolean, message: String): Require { return Require(must, message) } + /** + * 工厂方法:创建Require对象 + * @param must 需要验证的布尔条件 + * @return Require对象 + */ @JvmStatic fun require(must: Boolean): Require { return Require(must) } + /** + * 工厂方法:创建Require对象并指定异常消息和异常类型 + * @param must 返回布尔值的函数 + * @param message 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException + * @return Require对象 + */ @JvmStatic fun require( must: RFunction, @@ -95,29 +169,54 @@ class Require(private val must: Boolean) { return Require(must, message, exception) } + /** + * 工厂方法:创建Require对象并指定异常消息 + * @param must 返回布尔值的函数 + * @param message 检查失败时的异常消息 + * @return Require对象 + */ @JvmStatic fun require(must: RFunction, message: String): Require { return Require(must, message) } + /** + * 工厂方法:创建Require对象 + * @param must 返回布尔值的函数 + * @return Require对象 + */ @JvmStatic fun require(must: RFunction): Require { return Require(must) } } + /** + * 执行条件检查,如果条件为false则抛出IllegalArgumentException + * @param message 检查失败时的异常消息 + */ fun throws(message: String) { if (!must) { throw IllegalArgumentException(message) } } + /** + * 执行条件检查,如果条件为false则抛出指定类型的异常 + * @param string 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常类型 + */ fun throws(string: String, exception: Class) { if (!must) { throw exception.getConstructor(String::class.java).newInstance(string) } } + /** + * 执行条件检查,如果条件为false则抛出由函数构造的异常 + * @param string 检查失败时的异常消息 + * @param exception 检查失败时抛出的异常构造器函数 + */ fun throws(string: String, exception: P1RFunction) { if (!must) { throw exception.call(string)