Skip to content

文件处理

概述

文件处理是程序开发中的常见需求。Kotlin提供了丰富的文件操作API,包括文件读写、目录操作、路径处理等。本章将详细介绍如何在Kotlin中进行各种文件操作。

文件基础操作

文件读取

kotlin
import java.io.File
import java.io.FileNotFoundException
import java.nio.charset.Charset

fun main() {
    // 创建示例文件内容
    val sampleContent = """
        第一行内容
        第二行内容
        第三行内容
        包含中文的行:你好,Kotlin!
        最后一行
    """.trimIndent()
    
    // 写入示例文件
    val file = File("sample.txt")
    file.writeText(sampleContent, Charset.forName("UTF-8"))
    
    println("=== 文件读取示例 ===")
    
    // 1. 读取整个文件内容
    try {
        val content = file.readText(Charset.forName("UTF-8"))
        println("完整文件内容:")
        println(content)
    } catch (e: FileNotFoundException) {
        println("文件未找到:${e.message}")
    }
    
    // 2. 按行读取
    println("\n按行读取:")
    file.readLines(Charset.forName("UTF-8")).forEachIndexed { index, line ->
        println("第${index + 1}行: $line")
    }
    
    // 3. 使用序列读取大文件(内存友好)
    println("\n使用序列读取:")
    file.useLines { lines ->
        lines.take(3).forEach { line ->
            println("序列读取: $line")
        }
    }
    
    // 4. 读取字节数组
    val bytes = file.readBytes()
    println("\n文件大小: ${bytes.size} 字节")
    
    // 5. 安全读取(处理异常)
    fun safeReadFile(filename: String): String? {
        return try {
            File(filename).readText()
        } catch (e: Exception) {
            println("读取文件失败: ${e.message}")
            null
        }
    }
    
    println("\n安全读取存在的文件:")
    safeReadFile("sample.txt")?.let { content ->
        println("文件长度: ${content.length}")
    }
    
    println("\n安全读取不存在的文件:")
    safeReadFile("nonexistent.txt")
    
    // 清理
    file.delete()
}

文件写入

kotlin
import java.io.File
import java.io.FileWriter
import java.io.PrintWriter
import java.nio.charset.StandardCharsets

fun main() {
    println("=== 文件写入示例 ===")
    
    // 1. 写入文本内容
    val outputFile = File("output.txt")
    val content = """
        这是写入的内容
        包含多行文本
        当前时间: ${System.currentTimeMillis()}
    """.trimIndent()
    
    outputFile.writeText(content, StandardCharsets.UTF_8)
    println("文本写入完成")
    
    // 2. 追加内容
    outputFile.appendText("\n追加的内容", StandardCharsets.UTF_8)
    println("内容追加完成")
    
    // 验证写入结果
    println("文件内容:")
    println(outputFile.readText())
    
    // 3. 写入字节数组
    val binaryFile = File("binary.dat")
    val data = byteArrayOf(0x48, 0x65, 0x6C, 0x6C, 0x6F)  // "Hello"
    binaryFile.writeBytes(data)
    println("二进制文件写入完成")
    
    // 4. 使用PrintWriter写入
    val writerFile = File("writer_output.txt")
    PrintWriter(writerFile, "UTF-8").use { writer ->
        writer.println("使用PrintWriter写入")
        writer.println("第二行")
        writer.printf("格式化输出: %d + %d = %d%n", 1, 2, 3)
    }
    println("PrintWriter写入完成")
    
    // 5. 逐行写入
    val linesFile = File("lines.txt")
    val lines = listOf(
        "第一行",
        "第二行",
        "第三行"
    )
    linesFile.writeText(lines.joinToString("\n"))
    println("逐行写入完成")
    
    // 6. 安全写入(带异常处理)
    fun safeWriteFile(filename: String, content: String): Boolean {
        return try {
            File(filename).writeText(content)
            true
        } catch (e: Exception) {
            println("写入文件失败: ${e.message}")
            false
        }
    }
    
    val success = safeWriteFile("safe_output.txt", "安全写入的内容")
    println("安全写入结果: $success")
    
    // 显示所有创建的文件
    println("\n创建的文件:")
    listOf("output.txt", "binary.dat", "writer_output.txt", "lines.txt", "safe_output.txt")
        .map { File(it) }
        .filter { it.exists() }
        .forEach { file ->
            println("${file.name}: ${file.length()} 字节")
        }
    
    // 清理文件
    listOf("output.txt", "binary.dat", "writer_output.txt", "lines.txt", "safe_output.txt")
        .forEach { File(it).delete() }
}

目录操作

目录创建和遍历

kotlin
import java.io.File

fun main() {
    println("=== 目录操作示例 ===")
    
    // 1. 创建目录结构
    val baseDir = File("test_directory")
    val subDir1 = File(baseDir, "subdirectory1")
    val subDir2 = File(baseDir, "subdirectory2")
    val nestedDir = File(subDir1, "nested")
    
    // 创建目录
    nestedDir.mkdirs()  // 创建所有必要的父目录
    subDir2.mkdir()     // 创建单个目录
    
    println("目录创建完成")
    
    // 2. 创建一些测试文件
    File(baseDir, "root_file.txt").writeText("根目录文件")
    File(subDir1, "sub1_file.txt").writeText("子目录1文件")
    File(subDir2, "sub2_file.txt").writeText("子目录2文件")
    File(nestedDir, "nested_file.txt").writeText("嵌套目录文件")
    
    println("测试文件创建完成")
    
    // 3. 列出目录内容
    println("\n=== 目录内容 ===")
    fun listDirectory(dir: File, indent: String = "") {
        if (!dir.exists() || !dir.isDirectory) {
            println("${indent}目录不存在或不是目录: ${dir.name}")
            return
        }
        
        println("${indent}📁 ${dir.name}/")
        dir.listFiles()?.forEach { file ->
            if (file.isDirectory) {
                listDirectory(file, "$indent  ")
            } else {
                println("$indent  📄 ${file.name} (${file.length()} 字节)")
            }
        }
    }
    
    listDirectory(baseDir)
    
    // 4. 使用walkTopDown遍历
    println("\n=== 递归遍历 ===")
    baseDir.walkTopDown().forEach { file ->
        val type = if (file.isDirectory) "DIR" else "FILE"
        val size = if (file.isFile) " (${file.length()} 字节)" else ""
        println("$type: ${file.relativeTo(baseDir)}$size")
    }
    
    // 5. 过滤文件
    println("\n=== 文件过滤 ===")
    val txtFiles = baseDir.walkTopDown()
        .filter { it.isFile && it.extension == "txt" }
        .toList()
    
    println("找到的.txt文件:")
    txtFiles.forEach { file ->
        println("- ${file.relativeTo(baseDir)}")
    }
    
    // 6. 目录统计
    println("\n=== 目录统计 ===")
    val stats = baseDir.walkTopDown().fold(
        initial = Triple(0, 0, 0L)  // (目录数, 文件数, 总大小)
    ) { (dirs, files, size), file ->
        when {
            file.isDirectory -> Triple(dirs + 1, files, size)
            file.isFile -> Triple(dirs, files + 1, size + file.length())
            else -> Triple(dirs, files, size)
        }
    }
    
    println("目录数: ${stats.first}")
    println("文件数: ${stats.second}")
    println("总大小: ${stats.third} 字节")
    
    // 7. 查找特定文件
    println("\n=== 文件查找 ===")
    val foundFile = baseDir.walkTopDown()
        .find { it.name == "nested_file.txt" }
    
    foundFile?.let { file ->
        println("找到文件: ${file.absolutePath}")
        println("文件内容: ${file.readText()}")
    }
    
    // 清理目录
    baseDir.deleteRecursively()
    println("\n测试目录已清理")
}

文件和目录属性

kotlin
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

fun main() {
    println("=== 文件属性示例 ===")
    
    // 创建测试文件和目录
    val testFile = File("test_file.txt")
    val testDir = File("test_dir")
    
    testFile.writeText("这是测试文件内容\n包含多行文本")
    testDir.mkdir()
    
    // 1. 基本属性
    println("=== 基本属性 ===")
    listOf(testFile, testDir).forEach { file ->
        println("名称: ${file.name}")
        println("路径: ${file.path}")
        println("绝对路径: ${file.absolutePath}")
        println("规范路径: ${file.canonicalPath}")
        println("父目录: ${file.parent}")
        println("是否存在: ${file.exists()}")
        println("是否为文件: ${file.isFile}")
        println("是否为目录: ${file.isDirectory}")
        println("是否隐藏: ${file.isHidden}")
        println()
    }
    
    // 2. 文件大小和时间
    println("=== 文件大小和时间 ===")
    val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    
    println("文件: ${testFile.name}")
    println("大小: ${testFile.length()} 字节")
    println("最后修改时间: ${dateFormat.format(Date(testFile.lastModified()))}")
    
    // 修改文件时间
    val newTime = System.currentTimeMillis() - 24 * 60 * 60 * 1000  // 24小时前
    testFile.setLastModified(newTime)
    println("修改后的时间: ${dateFormat.format(Date(testFile.lastModified()))}")
    
    // 3. 权限检查
    println("\n=== 权限检查 ===")
    println("可读: ${testFile.canRead()}")
    println("可写: ${testFile.canWrite()}")
    println("可执行: ${testFile.canExecute()}")
    
    // 4. 文件扩展名和名称处理
    println("\n=== 文件名处理 ===")
    val files = listOf(
        "document.txt",
        "image.jpg",
        "archive.tar.gz",
        "script",
        ".hidden"
    )
    
    files.forEach { filename ->
        val file = File(filename)
        println("文件名: $filename")
        println("  基本名称: ${file.nameWithoutExtension}")
        println("  扩展名: ${file.extension}")
        println()
    }
    
    // 5. 路径操作
    println("=== 路径操作 ===")
    val path1 = File("parent/child/file.txt")
    val path2 = File("parent")
    
    println("相对路径: ${path1.relativeTo(path2)}")
    println("解析路径: ${File(path2, "child/file.txt")}")
    
    // 6. 磁盘空间信息
    println("=== 磁盘空间 ===")
    val currentDir = File(".")
    println("总空间: ${currentDir.totalSpace / (1024 * 1024 * 1024)} GB")
    println("可用空间: ${currentDir.freeSpace / (1024 * 1024 * 1024)} GB")
    println("可用空间: ${currentDir.usableSpace / (1024 * 1024 * 1024)} GB")
    
    // 清理
    testFile.delete()
    testDir.delete()
    println("\n测试文件已清理")
}

高级文件操作

文件复制和移动

kotlin
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.nio.file.StandardCopyOption

fun main() {
    println("=== 文件复制和移动示例 ===")
    
    // 创建源文件
    val sourceFile = File("source.txt")
    val content = """
        这是源文件内容
        包含多行文本
        用于测试复制和移动操作
        当前时间: ${System.currentTimeMillis()}
    """.trimIndent()
    
    sourceFile.writeText(content)
    println("源文件创建完成: ${sourceFile.name} (${sourceFile.length()} 字节)")
    
    // 1. 使用Kotlin扩展函数复制
    println("\n=== 使用copyTo复制 ===")
    val copy1 = File("copy1.txt")
    sourceFile.copyTo(copy1, overwrite = true)
    println("复制完成: ${copy1.name}")
    println("内容验证: ${copy1.readText() == sourceFile.readText()}")
    
    // 2. 使用Java NIO复制
    println("\n=== 使用NIO复制 ===")
    val copy2 = File("copy2.txt")
    Files.copy(sourceFile.toPath(), copy2.toPath(), StandardCopyOption.REPLACE_EXISTING)
    println("NIO复制完成: ${copy2.name}")
    
    // 3. 手动复制(适用于大文件)
    println("\n=== 手动复制 ===")
    fun copyFileManually(source: File, target: File, bufferSize: Int = 8192) {
        FileInputStream(source).use { input ->
            FileOutputStream(target).use { output ->
                val buffer = ByteArray(bufferSize)
                var bytesRead: Int
                var totalBytes = 0L
                
                while (input.read(buffer).also { bytesRead = it } != -1) {
                    output.write(buffer, 0, bytesRead)
                    totalBytes += bytesRead
                }
                
                println("手动复制完成: $totalBytes 字节")
            }
        }
    }
    
    val copy3 = File("copy3.txt")
    copyFileManually(sourceFile, copy3)
    
    // 4. 文件移动
    println("\n=== 文件移动 ===")
    val moveTarget = File("moved.txt")
    
    // 创建要移动的文件
    val toMove = File("to_move.txt")
    toMove.writeText("这个文件将被移动")
    
    // 移动文件
    val moveSuccess = toMove.renameTo(moveTarget)
    println("移动操作: ${if (moveSuccess) "成功" else "失败"}")
    println("原文件存在: ${toMove.exists()}")
    println("目标文件存在: ${moveTarget.exists()}")
    
    // 5. 目录复制
    println("\n=== 目录复制 ===")
    
    // 创建源目录结构
    val sourceDir = File("source_dir")
    val subDir = File(sourceDir, "subdir")
    subDir.mkdirs()
    
    File(sourceDir, "file1.txt").writeText("文件1内容")
    File(sourceDir, "file2.txt").writeText("文件2内容")
    File(subDir, "file3.txt").writeText("子目录文件内容")
    
    // 复制目录
    fun copyDirectory(source: File, target: File) {
        if (source.isDirectory) {
            if (!target.exists()) {
                target.mkdirs()
            }
            
            source.listFiles()?.forEach { file ->
                val targetFile = File(target, file.name)
                if (file.isDirectory) {
                    copyDirectory(file, targetFile)
                } else {
                    file.copyTo(targetFile, overwrite = true)
                }
            }
        }
    }
    
    val targetDir = File("target_dir")
    copyDirectory(sourceDir, targetDir)
    println("目录复制完成")
    
    // 验证目录复制
    fun countFiles(dir: File): Int {
        return dir.walkTopDown().count { it.isFile }
    }
    
    println("源目录文件数: ${countFiles(sourceDir)}")
    println("目标目录文件数: ${countFiles(targetDir)}")
    
    // 6. 批量操作
    println("\n=== 批量文件操作 ===")
    val batchDir = File("batch_files")
    batchDir.mkdir()
    
    // 创建多个文件
    repeat(5) { i ->
        File(batchDir, "batch_$i.txt").writeText("批量文件 $i 的内容")
    }
    
    // 批量重命名
    batchDir.listFiles()?.forEach { file ->
        if (file.isFile && file.name.startsWith("batch_")) {
            val newName = file.name.replace("batch_", "renamed_")
            val newFile = File(file.parent, newName)
            file.renameTo(newFile)
        }
    }
    
    println("批量重命名完成")
    batchDir.listFiles()?.forEach { file ->
        println("- ${file.name}")
    }
    
    // 清理所有测试文件
    println("\n=== 清理文件 ===")
    listOf(sourceFile, copy1, copy2, copy3, moveTarget, sourceDir, targetDir, batchDir)
        .forEach { file ->
            if (file.exists()) {
                if (file.isDirectory) {
                    file.deleteRecursively()
                } else {
                    file.delete()
                }
                println("已删除: ${file.name}")
            }
        }
}

文件监控和临时文件

kotlin
import java.io.File
import java.nio.file.*
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread

fun main() {
    println("=== 文件监控和临时文件示例 ===")
    
    // 1. 临时文件操作
    println("=== 临时文件 ===")
    
    // 创建临时文件
    val tempFile = File.createTempFile("kotlin_temp", ".txt")
    println("临时文件创建: ${tempFile.absolutePath}")
    
    // 写入临时文件
    tempFile.writeText("这是临时文件内容\n时间戳: ${System.currentTimeMillis()}")
    println("临时文件大小: ${tempFile.length()} 字节")
    
    // 设置程序退出时删除
    tempFile.deleteOnExit()
    
    // 创建临时目录
    val tempDir = Files.createTempDirectory("kotlin_temp_dir").toFile()
    println("临时目录创建: ${tempDir.absolutePath}")
    
    // 在临时目录中创建文件
    val tempFileInDir = File(tempDir, "temp_file.txt")
    tempFileInDir.writeText("临时目录中的文件")
    
    // 2. 文件监控(简化版本)
    println("\n=== 文件监控 ===")
    
    val watchDir = File("watch_directory")
    watchDir.mkdir()
    
    // 创建监控线程
    val watchThread = thread {
        try {
            val watchService = FileSystems.getDefault().newWatchService()
            val watchKey = watchDir.toPath().register(
                watchService,
                StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_DELETE,
                StandardWatchEventKinds.ENTRY_MODIFY
            )
            
            println("开始监控目录: ${watchDir.absolutePath}")
            
            while (!Thread.currentThread().isInterrupted) {
                val key = watchService.poll(1, TimeUnit.SECONDS)
                if (key != null) {
                    for (event in key.pollEvents()) {
                        val kind = event.kind()
                        val filename = event.context()
                        
                        when (kind) {
                            StandardWatchEventKinds.ENTRY_CREATE -> 
                                println("文件创建: $filename")
                            StandardWatchEventKinds.ENTRY_DELETE -> 
                                println("文件删除: $filename")
                            StandardWatchEventKinds.ENTRY_MODIFY -> 
                                println("文件修改: $filename")
                        }
                    }
                    key.reset()
                }
            }
        } catch (e: Exception) {
            println("监控异常: ${e.message}")
        }
    }
    
    // 模拟文件操作
    Thread.sleep(1000)
    
    println("创建测试文件...")
    val testFile1 = File(watchDir, "test1.txt")
    testFile1.writeText("测试文件1")
    
    Thread.sleep(1000)
    
    println("修改测试文件...")
    testFile1.appendText("\n追加内容")
    
    Thread.sleep(1000)
    
    println("创建第二个文件...")
    val testFile2 = File(watchDir, "test2.txt")
    testFile2.writeText("测试文件2")
    
    Thread.sleep(1000)
    
    println("删除文件...")
    testFile1.delete()
    
    Thread.sleep(2000)
    
    // 停止监控
    watchThread.interrupt()
    watchThread.join(5000)
    
    // 3. 文件锁定(模拟)
    println("\n=== 文件锁定示例 ===")
    
    val lockFile = File("locked_file.txt")
    lockFile.writeText("这是被锁定的文件")
    
    // 模拟文件锁定检查
    fun isFileLocked(file: File): Boolean {
        return try {
            val channel = FileOutputStream(file, true).channel
            val lock = channel.tryLock()
            if (lock != null) {
                lock.release()
                channel.close()
                false
            } else {
                true
            }
        } catch (e: Exception) {
            true
        }
    }
    
    println("文件锁定状态: ${isFileLocked(lockFile)}")
    
    // 4. 文件比较
    println("\n=== 文件比较 ===")
    
    val file1 = File("compare1.txt")
    val file2 = File("compare2.txt")
    val file3 = File("compare3.txt")
    
    val content1 = "相同的内容"
    val content2 = "相同的内容"
    val content3 = "不同的内容"
    
    file1.writeText(content1)
    file2.writeText(content2)
    file3.writeText(content3)
    
    fun filesEqual(file1: File, file2: File): Boolean {
        if (file1.length() != file2.length()) return false
        return file1.readBytes().contentEquals(file2.readBytes())
    }
    
    println("file1 == file2: ${filesEqual(file1, file2)}")
    println("file1 == file3: ${filesEqual(file1, file3)}")
    
    // 5. 文件校验和
    println("\n=== 文件校验和 ===")
    
    fun calculateChecksum(file: File): String {
        val bytes = file.readBytes()
        return bytes.fold(0) { acc, byte -> acc + byte.toInt() }.toString(16)
    }
    
    println("file1 校验和: ${calculateChecksum(file1)}")
    println("file2 校验和: ${calculateChecksum(file2)}")
    println("file3 校验和: ${calculateChecksum(file3)}")
    
    // 清理文件
    println("\n=== 清理文件 ===")
    listOf(tempFile, tempDir, watchDir, lockFile, file1, file2, file3, testFile2)
        .forEach { file ->
            if (file.exists()) {
                if (file.isDirectory) {
                    file.deleteRecursively()
                } else {
                    file.delete()
                }
                println("已删除: ${file.name}")
            }
        }
}

实际应用示例

日志文件管理系统

kotlin
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock

class LogManager(
    private val logDirectory: String = "logs",
    private val maxFileSize: Long = 10 * 1024 * 1024,  // 10MB
    private val maxFiles: Int = 10
) {
    private val lock = ReentrantLock()
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd")
    private val timeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    
    init {
        File(logDirectory).mkdirs()
    }
    
    enum class LogLevel { DEBUG, INFO, WARN, ERROR }
    
    fun log(level: LogLevel, message: String, throwable: Throwable? = null) {
        lock.withLock {
            val logFile = getCurrentLogFile()
            val timestamp = timeFormat.format(Date())
            val logEntry = buildString {
                append("[$timestamp] [${level.name}] $message")
                throwable?.let { 
                    append("\n")
                    append(it.stackTraceToString())
                }
                append("\n")
            }
            
            logFile.appendText(logEntry)
            
            // 检查文件大小,必要时轮转
            if (logFile.length() > maxFileSize) {
                rotateLogFiles()
            }
        }
    }
    
    private fun getCurrentLogFile(): File {
        val today = dateFormat.format(Date())
        return File(logDirectory, "app-$today.log")
    }
    
    private fun rotateLogFiles() {
        val logFiles = File(logDirectory)
            .listFiles { file -> file.name.matches(Regex("app-\\d{4}-\\d{2}-\\d{2}\\.log")) }
            ?.sortedByDescending { it.lastModified() }
            ?: return
        
        // 删除超出数量限制的旧文件
        if (logFiles.size >= maxFiles) {
            logFiles.drop(maxFiles - 1).forEach { file ->
                file.delete()
                println("删除旧日志文件: ${file.name}")
            }
        }
    }
    
    fun getLogFiles(): List<File> {
        return File(logDirectory)
            .listFiles { file -> file.name.endsWith(".log") }
            ?.sortedByDescending { it.lastModified() }
            ?: emptyList()
    }
    
    fun searchLogs(keyword: String, level: LogLevel? = null): List<String> {
        val results = mutableListOf<String>()
        
        getLogFiles().forEach { file ->
            file.useLines { lines ->
                lines.forEach { line ->
                    val matchesKeyword = line.contains(keyword, ignoreCase = true)
                    val matchesLevel = level?.let { line.contains("[${it.name}]") } ?: true
                    
                    if (matchesKeyword && matchesLevel) {
                        results.add("${file.name}: $line")
                    }
                }
            }
        }
        
        return results
    }
    
    fun getLogStatistics(): Map<String, Any> {
        val stats = mutableMapOf<String, Any>()
        val levelCounts = mutableMapOf<LogLevel, Int>()
        var totalLines = 0
        var totalSize = 0L
        
        getLogFiles().forEach { file ->
            totalSize += file.length()
            
            file.useLines { lines ->
                lines.forEach { line ->
                    totalLines++
                    LogLevel.values().forEach { level ->
                        if (line.contains("[${level.name}]")) {
                            levelCounts[level] = levelCounts.getOrDefault(level, 0) + 1
                        }
                    }
                }
            }
        }
        
        stats["totalFiles"] = getLogFiles().size
        stats["totalLines"] = totalLines
        stats["totalSize"] = totalSize
        stats["levelCounts"] = levelCounts
        
        return stats
    }
    
    fun cleanup() {
        File(logDirectory).deleteRecursively()
    }
}

// 配置文件管理器
class ConfigManager(private val configFile: String = "app.properties") {
    private val properties = mutableMapOf<String, String>()
    
    init {
        loadConfig()
    }
    
    private fun loadConfig() {
        val file = File(configFile)
        if (file.exists()) {
            file.readLines().forEach { line ->
                if (line.contains("=") && !line.startsWith("#")) {
                    val parts = line.split("=", limit = 2)
                    if (parts.size == 2) {
                        properties[parts[0].trim()] = parts[1].trim()
                    }
                }
            }
        }
    }
    
    fun get(key: String, defaultValue: String = ""): String {
        return properties[key] ?: defaultValue
    }
    
    fun getInt(key: String, defaultValue: Int = 0): Int {
        return properties[key]?.toIntOrNull() ?: defaultValue
    }
    
    fun getBoolean(key: String, defaultValue: Boolean = false): Boolean {
        return properties[key]?.toBoolean() ?: defaultValue
    }
    
    fun set(key: String, value: String) {
        properties[key] = value
    }
    
    fun save() {
        val content = buildString {
            appendLine("# 应用配置文件")
            appendLine("# 生成时间: ${Date()}")
            appendLine()
            
            properties.forEach { (key, value) ->
                appendLine("$key=$value")
            }
        }
        
        File(configFile).writeText(content)
    }
    
    fun reload() {
        properties.clear()
        loadConfig()
    }
}

fun main() {
    println("=== 日志文件管理系统示例 ===")
    
    // 1. 日志管理器测试
    val logManager = LogManager()
    
    // 记录不同级别的日志
    logManager.log(LogLevel.INFO, "应用程序启动")
    logManager.log(LogLevel.DEBUG, "调试信息:用户ID = 12345")
    logManager.log(LogLevel.WARN, "警告:内存使用率较高")
    logManager.log(LogLevel.ERROR, "错误:数据库连接失败", RuntimeException("连接超时"))
    
    // 模拟大量日志以触发轮转
    repeat(100) { i ->
        logManager.log(LogLevel.INFO, "批量日志消息 #$i")
    }
    
    println("日志记录完成")
    
    // 查看日志文件
    println("\n当前日志文件:")
    logManager.getLogFiles().forEach { file ->
        println("- ${file.name}: ${file.length()} 字节")
    }
    
    // 搜索日志
    println("\n搜索包含'错误'的日志:")
    val errorLogs = logManager.searchLogs("错误")
    errorLogs.take(3).forEach { println("  $it") }
    
    // 日志统计
    println("\n日志统计:")
    val stats = logManager.getLogStatistics()
    stats.forEach { (key, value) ->
        println("  $key: $value")
    }
    
    // 2. 配置管理器测试
    println("\n=== 配置管理器测试 ===")
    
    val configManager = ConfigManager()
    
    // 设置配置
    configManager.set("app.name", "Kotlin文件处理示例")
    configManager.set("app.version", "1.0.0")
    configManager.set("debug.enabled", "true")
    configManager.set("max.connections", "100")
    
    // 保存配置
    configManager.save()
    println("配置已保存")
    
    // 读取配置
    println("应用名称: ${configManager.get("app.name")}")
    println("版本: ${configManager.get("app.version")}")
    println("调试模式: ${configManager.getBoolean("debug.enabled")}")
    println("最大连接数: ${configManager.getInt("max.connections")}")
    
    // 3. 文件备份示例
    println("\n=== 文件备份示例 ===")
    
    fun backupFile(sourceFile: File, backupDir: File = File("backups")): File? {
        if (!sourceFile.exists()) return null
        
        backupDir.mkdirs()
        val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val backupName = "${sourceFile.nameWithoutExtension}_$timestamp.${sourceFile.extension}"
        val backupFile = File(backupDir, backupName)
        
        return try {
            sourceFile.copyTo(backupFile)
            println("备份创建: ${backupFile.name}")
            backupFile
        } catch (e: Exception) {
            println("备份失败: ${e.message}")
            null
        }
    }
    
    // 备份配置文件
    val configFile = File("app.properties")
    if (configFile.exists()) {
        backupFile(configFile)
    }
    
    // 清理
    println("\n=== 清理资源 ===")
    logManager.cleanup()
    File("app.properties").delete()
    File("backups").deleteRecursively()
    println("清理完成")
}

最佳实践

1. 异常处理和资源管理

kotlin
import java.io.*

// 安全的文件操作
class SafeFileOperations {
    
    fun safeReadFile(filename: String): Result<String> {
        return try {
            val content = File(filename).readText()
            Result.success(content)
        } catch (e: FileNotFoundException) {
            Result.failure(Exception("文件不存在: $filename", e))
        } catch (e: IOException) {
            Result.failure(Exception("读取文件失败: ${e.message}", e))
        } catch (e: Exception) {
            Result.failure(Exception("未知错误: ${e.message}", e))
        }
    }
    
    fun safeWriteFile(filename: String, content: String): Result<Unit> {
        return try {
            File(filename).writeText(content)
            Result.success(Unit)
        } catch (e: IOException) {
            Result.failure(Exception("写入文件失败: ${e.message}", e))
        } catch (e: Exception) {
            Result.failure(Exception("未知错误: ${e.message}", e))
        }
    }
    
    // 使用use确保资源正确关闭
    fun copyFileWithStreams(source: File, target: File): Result<Unit> {
        return try {
            FileInputStream(source).use { input ->
                FileOutputStream(target).use { output ->
                    input.copyTo(output)
                }
            }
            Result.success(Unit)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

2. 性能优化

kotlin
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths

class FilePerformanceOptimization {
    
    // 对于大文件,使用序列而不是一次性读取所有行
    fun processLargeFile(filename: String, processor: (String) -> Unit) {
        File(filename).useLines { lines ->
            lines.forEach(processor)
        }
    }
    
    // 批量文件操作
    fun batchProcessFiles(directory: File, batchSize: Int = 100) {
        directory.walkTopDown()
            .filter { it.isFile }
            .chunked(batchSize)
            .forEach { batch ->
                // 批量处理文件
                batch.forEach { file ->
                    // 处理单个文件
                }
            }
    }
    
    // 使用NIO进行高效的文件操作
    fun efficientFileCopy(source: String, target: String) {
        Files.copy(Paths.get(source), Paths.get(target))
    }
}

3. 跨平台兼容性

kotlin
import java.io.File

class CrossPlatformFileOperations {
    
    // 使用File.separator确保路径分隔符正确
    fun createPath(vararg parts: String): String {
        return parts.joinToString(File.separator)
    }
    
    // 规范化路径
    fun normalizePath(path: String): String {
        return File(path).canonicalPath
    }
    
    // 检查文件名是否有效
    fun isValidFilename(filename: String): Boolean {
        val invalidChars = when {
            System.getProperty("os.name").lowercase().contains("windows") -> 
                charArrayOf('<', '>', ':', '"', '|', '?', '*')
            else -> charArrayOf('/')
        }
        
        return filename.none { it in invalidChars }
    }
}

下一步

掌握了文件处理后,让我们学习Kotlin中的继承和多态概念。

下一章: 继承和多态

练习题

  1. 创建一个文件同步工具,比较两个目录并同步差异
  2. 实现一个简单的文本编辑器,支持文件的打开、编辑和保存
  3. 编写一个日志分析工具,统计不同级别日志的数量和趋势
  4. 设计一个文件压缩工具,支持多种压缩格式
  5. 创建一个配置文件管理系统,支持多种格式(JSON、XML、Properties等)

本站内容仅供学习和研究使用。