generated from mingliqiye/lib-tem
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:
parent
66ec71cbc7
commit
f2ee83ca64
@ -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")
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
|
||||
}
|
||||
@ -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())
|
||||
|
||||
@ -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<String> {
|
||||
@ -46,6 +92,12 @@ fun ByteArray.getByteArrayString(): MutableList<String> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将十六进制字符转换为对应的数值
|
||||
* @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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
@ -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
|
||||
|
||||
/**
|
||||
* 读取文件内容为字符串
|
||||
// 读取文件内容为字符串
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 读取文件内容为字符串,使用默认字符集
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 文件内容字符串
|
||||
* @return 文件内容的字符串表示
|
||||
* @throws IOException 读取文件时发生错误
|
||||
*/
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun readFileToString(filePath: String): String {
|
||||
return readFileToString(filePath, DEFAULT_CHARSET)
|
||||
fun String.readFileToString(): String {
|
||||
return this.readFileToString(DEFAULT_CHARSET)
|
||||
}
|
||||
|
||||
/**
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 读取文件内容为字符串
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param charset 字符集
|
||||
* @return 文件内容字符串
|
||||
* @param charset 字符编码格式
|
||||
* @return 文件内容的字符串表示
|
||||
* @throws IOException 读取文件时发生错误
|
||||
*/
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun readFileToString(filePath: String, charset: Charset): String {
|
||||
val path = OsPath.of(filePath)
|
||||
fun String.readFileToString(charset: Charset): String {
|
||||
val path = OsPath.of(this)
|
||||
val bytes = Files.readAllBytes(path)
|
||||
return String(bytes, charset)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串写入文件
|
||||
// 将字符串写入文件
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字符串写入文件,使用默认字符集
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param content 要写入的内容
|
||||
* @param content 要写入的字符串内容
|
||||
* @throws IOException 写入文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun writeStringToFile(filePath: String, content: String) {
|
||||
writeStringToFile(filePath, content, DEFAULT_CHARSET)
|
||||
fun String.writeStringToFile(content: String) {
|
||||
this.writeStringToFile(content, DEFAULT_CHARSET)
|
||||
}
|
||||
|
||||
/**
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字符串写入文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param content 要写入的内容
|
||||
* @param charset 字符集
|
||||
* @param content 要写入的字符串内容
|
||||
* @param charset 字符编码格式
|
||||
* @throws IOException 写入文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun writeStringToFile(filePath: String, content: String, charset: Charset) {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.writeStringToFile(content: String, charset: Charset) {
|
||||
val path = Paths.get(this)
|
||||
path.parent?.let { Files.createDirectories(it) }
|
||||
Files.write(path, content.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容为字符串列表(按行分割)
|
||||
// 读取文件内容为字符串列表(按行分割)
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 读取文件内容为字符串列表(按行分割),使用默认字符集
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 文件内容按行分割的字符串列表
|
||||
* @return 按行分割的字符串列表
|
||||
* @throws IOException 读取文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun readLines(filePath: String): List<String> {
|
||||
return readLines(filePath, DEFAULT_CHARSET)
|
||||
fun String.readLines(): List<String> {
|
||||
return this.readLines(DEFAULT_CHARSET)
|
||||
}
|
||||
|
||||
/**
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 读取文件内容为字符串列表(按行分割)
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param charset 字符集
|
||||
* @return 文件内容按行分割的字符串列表
|
||||
* @param charset 字符编码格式
|
||||
* @return 按行分割的字符串列表
|
||||
* @throws IOException 读取文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun readLines(filePath: String, charset: Charset): List<String> {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.readLines(charset: Charset): List<String> {
|
||||
val path = Paths.get(this)
|
||||
return Files.readAllLines(path, charset)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串列表写入文件(每行一个元素)
|
||||
// 将字符串列表写入文件(每行一个元素)
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字符串列表写入文件(每行一个元素),使用默认字符集
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param lines 要写入的行内容列表
|
||||
* @param lines 要写入的字符串列表
|
||||
* @throws IOException 写入文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun writeLines(filePath: String, lines: List<String>) {
|
||||
writeLines(filePath, lines, DEFAULT_CHARSET)
|
||||
fun String.writeLines(lines: List<String>) {
|
||||
this.writeLines(lines, DEFAULT_CHARSET)
|
||||
}
|
||||
|
||||
/**
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字符串列表写入文件(每行一个元素)
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param lines 要写入的行内容列表
|
||||
* @param charset 字符集
|
||||
* @param lines 要写入的字符串列表
|
||||
* @param charset 字符编码格式
|
||||
* @throws IOException 写入文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun writeLines(filePath: String, lines: List<String>, charset: Charset) {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.writeLines(lines: List<String>, charset: Charset) {
|
||||
val path = Paths.get(this)
|
||||
Files.createDirectories(path.parent)
|
||||
Files.write(path, lines, charset)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文件
|
||||
// 复制文件
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 复制文件到目标路径
|
||||
*
|
||||
* @param sourcePath 源文件路径
|
||||
* @param targetPath 目标文件路径
|
||||
* @throws IOException 复制文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun copyFile(sourcePath: String, targetPath: String) {
|
||||
val source = Paths.get(sourcePath)
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
// 读取文件内容为字节数组
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 读取文件内容为字节数组
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 文件内容的字节数组
|
||||
* @return 文件内容的字节数组表示
|
||||
* @throws IOException 读取文件时发生错误
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun readFileToByteArray(filePath: String): ByteArray {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.readByteArray(): ByteArray {
|
||||
val path = Paths.get(this)
|
||||
return Files.readAllBytes(path)
|
||||
}
|
||||
|
||||
/**
|
||||
// 将字节数组写入文件
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字节数组写入文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param data 要写入的字节数据
|
||||
* @param data 要写入的字节数组
|
||||
* @throws IOException 写入文件时发生错误
|
||||
*/
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeByteArrayToFile(filePath: String, data: ByteArray) {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.writeByteArray(data: ByteArray) {
|
||||
val path = Paths.get(this)
|
||||
Files.createDirectories(path.parent)
|
||||
Files.write(path, data)
|
||||
}
|
||||
|
||||
/**
|
||||
// 将字节数组追加到文件末尾
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字节数组追加到文件末尾
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param data 要追加的字节数据
|
||||
* @throws IOException 追加数据时发生错误
|
||||
* @param data 要追加的字节数组
|
||||
* @throws IOException 追加文件时发生错误
|
||||
*/
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun appendByteArrayToFile(filePath: String, data: ByteArray) {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.appendByteArray(data: ByteArray) {
|
||||
val path = Paths.get(this)
|
||||
Files.createDirectories(path.parent)
|
||||
Files.write(
|
||||
path, data, StandardOpenOption.CREATE, StandardOpenOption.APPEND
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
// 分块读取大文件为字节数组列表
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 分块读取大文件为字节数组列表
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param chunkSize 每块大小(字节)
|
||||
* @return 文件内容按指定大小分割的字节数组列表
|
||||
* @param chunkSize 每个块的大小
|
||||
* @return 字节数组列表
|
||||
* @throws IOException 读取文件时发生错误
|
||||
*/
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun readFileToByteArrayChunks(filePath: String, chunkSize: Int): List<ByteArray> {
|
||||
fun String.readByteArrayChunks(chunkSize: Int): List<ByteArray> {
|
||||
val chunks = mutableListOf<ByteArray>()
|
||||
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<ByteArray>
|
||||
return chunks
|
||||
}
|
||||
|
||||
/**
|
||||
// 将字节数组列表写入文件
|
||||
@Throws(IOException::class)
|
||||
/**
|
||||
* 将字节数组列表写入文件
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param chunks 字节数组列表
|
||||
* @throws IOException 写入文件时发生错误
|
||||
*/
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeByteArrayChunksToFile(filePath: String, chunks: List<ByteArray>) {
|
||||
val path = Paths.get(filePath)
|
||||
fun String.writeByteArrayChunks(chunks: List<ByteArray>) {
|
||||
val path = Paths.get(this)
|
||||
Files.createDirectories(path.parent)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
81
src/main/kotlin/com/mingliqiye/utils/functions/Debouncer.kt
Normal file
81
src/main/kotlin/com/mingliqiye/utils/functions/Debouncer.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
@ -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<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
|
||||
fun interface P1Function<P> {
|
||||
fun call(p: P)
|
||||
|
||||
@ -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 算法对字符串进行加密。
|
||||
*
|
||||
|
||||
@ -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<T> : BaseMapper<T> {
|
||||
fun queryWrapper(): 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>()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<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) {
|
||||
|
||||
/**
|
||||
* 构造函数:通过函数调用结果初始化条件检查器
|
||||
* @param funs 返回布尔值的函数
|
||||
*/
|
||||
constructor(funs: RFunction<Boolean>) : this(funs.call())
|
||||
|
||||
/**
|
||||
* 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查
|
||||
* @param must 返回布尔值的函数
|
||||
* @param message 检查失败时的异常消息
|
||||
*/
|
||||
constructor(must: RFunction<Boolean>, message: String) : this(must) {
|
||||
throws(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查
|
||||
* @param must 返回布尔值的函数
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException
|
||||
*/
|
||||
constructor(
|
||||
must: RFunction<Boolean>,
|
||||
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<out Exception> = IllegalArgumentException::class.java
|
||||
) : this(must) {
|
||||
throws(message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数:通过布尔值初始化条件检查器,并立即执行检查
|
||||
* @param must 需要验证的布尔条件
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常构造器函数
|
||||
*/
|
||||
constructor(
|
||||
must: Boolean, message: String, exception: P1RFunction<String, out Exception>
|
||||
) : this(must) {
|
||||
@ -58,17 +117,14 @@ class Require(private val must: Boolean) {
|
||||
}
|
||||
|
||||
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
|
||||
fun require(
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建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<Boolean>,
|
||||
@ -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<Boolean>, message: String): Require {
|
||||
return Require(must, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象
|
||||
* @param must 返回布尔值的函数
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(must: RFunction<Boolean>): 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<out Exception>) {
|
||||
if (!must) {
|
||||
throw exception.getConstructor(String::class.java).newInstance(string)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行条件检查,如果条件为false则抛出由函数构造的异常
|
||||
* @param string 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常构造器函数
|
||||
*/
|
||||
fun throws(string: String, exception: P1RFunction<String, out Exception>) {
|
||||
if (!must) {
|
||||
throw exception.call(string)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user