使用 Kotlin 拆分大文本文件

发布于:2025-03-07 ⋅ 阅读:(16) ⋅ 点赞:(0)

在实际开发过程中,我们经常会遇到需要处理大文本文件的场景,比如日志文件、小说文本等。当文件过大时,直接打开可能会导致程序卡顿甚至崩溃。为了解决这个问题,我们可以将大文本文件按指定大小拆分成多个小文件,方便处理和查看。

本文介绍如何使用 Kotlin 实现文本文件拆分的功能,并提供完整代码示例。

功能需求

  • 读取一个大文本文件。
  • 按照指定的字符数(如 190000 字符)拆分文件。
  • 处理不同的文件编码(支持 UTF-8、GBK、UTF-16)。
  • 将拆分后的文件存放到一个与原文件同名的文件夹中。
  • 保留原始文件的扩展名,文件名格式为 文件名_1.txt文件名_2.txt

代码实现

我们编写一个 splitTxtFile 函数来实现该功能,并确保能够处理不同的编码。

import java.io.*
import java.nio.charset.Charset

/**
 * 按指定字符数拆分大文本文件,并存放到与原文件同名的文件夹中。
 * 支持 UTF-8 / GBK / UTF-16 编码自动切换,防止编码不兼容问题。
 *
 * @param filePath 要拆分的文件路径
 * @param maxChars 每个分割文件的最大字符数
 * @param encodingList 尝试使用的字符编码列表
 */
fun splitTxtFile(filePath: String, maxChars: Int, encodingList: List<String> = listOf("UTF-8", "GBK", "UTF-16")) {
    val file = File(filePath)
    if (!file.exists()) {
        println("文件不存在,请检查路径")
        return
    }

    // 尝试不同编码方式打开文件,防止编码错误
    var reader: BufferedReader? = null
    for (encoding in encodingList) {
        try {
            reader = file.bufferedReader(Charset.forName(encoding))
            break  // 成功读取则跳出循环
        } catch (e: UnsupportedEncodingException) {
            continue
        } catch (e: IOException) {
            continue
        }
    }

    if (reader == null) {
        println("无法解析文件编码")
        return
    }

    // 获取文件所在目录、文件名(无后缀)和扩展名
    val parentDir = file.parent ?: "."
    val fileName = file.nameWithoutExtension
    val fileExt = file.extension

    // 创建新文件夹存放分割后的文件
    val newFolder = File(parentDir, fileName)
    if (!newFolder.exists()) newFolder.mkdirs()

    var partContent = StringBuilder()
    var partNum = 1

    // 逐行读取文件内容,防止一次性读取导致内存溢出
    reader.useLines { lines ->
        lines.forEach { line ->
            if (partContent.length + line.length > maxChars) {
                savePartFile(newFolder, fileName, fileExt, partNum, partContent.toString())
                partContent.clear()
                partNum++
            }
            partContent.append(line).append("\n")
        }
    }

    // 处理最后一部分
    if (partContent.isNotEmpty()) {
        savePartFile(newFolder, fileName, fileExt, partNum, partContent.toString())
    }

    println("文件拆分完成,共生成 $partNum 个文件。")
}

/**
 * 保存拆分后的文件到新目录
 * @param folder 存放文件的文件夹
 * @param baseName 原始文件名(无扩展名)
 * @param ext 原始文件扩展名
 * @param partNum 拆分的文件序号
 * @param content 文件内容
 */
fun savePartFile(folder: File, baseName: String, ext: String, partNum: Int, content: String) {
    val newFile = File(folder, "${baseName}_$partNum.$ext")
    newFile.writeText(content, Charsets.UTF_8)
}

fun main() {
    val filePath = "C:/abc.txt"
    val maxChars = 10240000 // 每个文件10MB
    splitTxtFile(filePath, maxChars)
}

代码解析

1. 处理文件编码

不同的文本文件可能使用不同的编码格式,如 UTF-8、GBK、UTF-16。为了避免编码错误,我们提供了一个编码列表,代码会尝试使用不同编码打开文件,直到成功读取。

var reader: BufferedReader? = null
for (encoding in encodingList) {
    try {
        reader = file.bufferedReader(Charset.forName(encoding))
        break
    } catch (e: UnsupportedEncodingException) {
        continue
    } catch (e: IOException) {
        continue
    }
}

2. 创建存放分割文件的目录

我们获取原始文件所在的目录,并创建一个与原文件同名的文件夹,用于存放拆分后的文件。

val parentDir = file.parent ?: "."
val fileName = file.nameWithoutExtension
val fileExt = file.extension
val newFolder = File(parentDir, fileName)
if (!newFolder.exists()) newFolder.mkdirs()

3. 按指定大小拆分文件

为了避免一次性读取整个文件导致内存溢出,我们使用 useLines 逐行读取文件内容,并在达到 maxChars 限制时将当前内容写入新的文件。

reader.useLines { lines ->
    lines.forEach { line ->
        if (partContent.length + line.length > maxChars) {
            savePartFile(newFolder, fileName, fileExt, partNum, partContent.toString())
            partContent.clear()
            partNum++
        }
        partContent.append(line).append("\n")
    }
}

4. 保存拆分后的文件

拆分后的内容会存放在新建的文件夹中,文件名格式为 文件名_1.txt文件名_2.txt,依此类推。

fun savePartFile(folder: File, baseName: String, ext: String, partNum: Int, content: String) {
    val newFile = File(folder, "${baseName}_$partNum.$ext")
    newFile.writeText(content, Charsets.UTF_8)
}

运行示例

假设 C:/abc.txt 是一个大文本文件,我们可以调用 splitTxtFile 进行拆分。

fun main() {
    val filePath = "C:/abc.txt"
    val maxChars = 10240000 // 每个文件10MB
    splitTxtFile(filePath, maxChars)
}

运行后,程序会在 C:/abc/ 目录下生成多个拆分后的文件。

总结

本文介绍了如何使用 Kotlin 拆分大文本文件,支持自动检测编码,并将拆分后的文件存放在指定目录。代码采用逐行读取方式,避免内存溢出,适用于大文件处理场景。希望对你有所帮助!