文件处理
概述
文件处理是程序开发中的常见需求。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中的继承和多态概念。
下一章: 继承和多态
练习题
- 创建一个文件同步工具,比较两个目录并同步差异
- 实现一个简单的文本编辑器,支持文件的打开、编辑和保存
- 编写一个日志分析工具,统计不同级别日志的数量和趋势
- 设计一个文件压缩工具,支持多种压缩格式
- 创建一个配置文件管理系统,支持多种格式(JSON、XML、Properties等)