0%

scala文件操作

Scala 文件操作:读写与系统命令交互

Scala 提供了简洁的 API 用于文件读写和系统命令执行,既可以利用 Java 的 IO 类库,也可以使用 Scala 标准库中的工具(如 scala.io.Source)。此外,Scala 对系统命令的支持尤为便捷,能轻松实现命令执行、管道和重定向。本文将详细介绍 Scala 的文件操作和系统命令交互方式。

文件读取:scala.io.Source

Scala 标准库的 scala.io.Source 是读取文本文件的首选工具,支持从文件、URL、输入流等多种来源读取数据。

读取文件的所有行

使用 Source.fromFile 打开文件,getLines 方法获取所有行(返回 Iterator[String]):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import scala.io.Source
import java.io.File

object FileReader {
def main(args: Array[String]): Unit = {
// 打开文件(指定路径和编码)
val source: Source = Source.fromFile(new File("data.txt"), "UTF-8")

try {
// 读取所有行(返回迭代器)
val lines: Iterator[String] = source.getLines()

// 遍历行并打印
println("文件内容:")
lines.foreach(println)
} finally {
// 关闭资源(避免内存泄漏)
source.close()
}
}
}

关键说明

  • Source.fromFile 的第一个参数可以是文件路径字符串("data.txt")或 java.io.File 对象。
  • 第二个参数指定编码(如 "UTF-8"),默认使用系统编码。
  • 必须在 finally 块中调用 source.close(),确保资源释放。

读取整个文件为字符串

使用 mkString 方法直接将文件内容转换为单个字符串:

1
2
3
4
5
6
7
val source = Source.fromFile("data.txt")
try {
val content: String = source.mkString // 整个文件内容作为字符串
println("完整内容:\n" + content)
} finally {
source.close()
}

适合读取小型文件,大型文件使用 getLines 逐行处理更高效(减少内存占用)。

读取其他来源

Source 还支持从 URL、输入流等读取数据:

1
2
3
4
5
6
7
8
9
10
11
// 从 URL 读取
val urlSource = Source.fromURL("https://www.scala-lang.org", "UTF-8")
println("URL 内容:\n" + urlSource.mkString)
urlSource.close()

// 从标准输入读取
val stdinSource = Source.stdin
println("请输入内容:")
val input = stdinSource.getLines().next() // 读取一行输入
println(s"你输入了:$input")
stdinSource.close()

文件写入:利用 Java IO 类库

Scala 本身没有提供专门的文件写入 API,通常直接使用 Java 的 java.io 类库(如 FileWriterBufferedWriter):

基本写入(覆盖模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.{File, FileWriter, BufferedWriter}

object FileWriter {
def main(args: Array[String]): Unit = {
val file = new File("output.txt")
val writer = new BufferedWriter(new FileWriter(file)) // 覆盖模式(默认)

try {
writer.write("Hello, Scala File Writing!") // 写入字符串
writer.newLine() // 换行
writer.write("这是第二行内容")
} finally {
writer.close() // 关闭资源,确保内容刷新到文件
}
}
}

追加写入

FileWriter 构造函数中添加 true 参数,启用追加模式:

1
2
3
4
5
6
7
8
// 追加模式(第二个参数为 true)
val appendWriter = new BufferedWriter(new FileWriter("output.txt", true))
try {
appendWriter.newLine()
appendWriter.write("这是追加的内容")
} finally {
appendWriter.close()
}

使用 PrintWriter 简化写入

PrintWriter 提供了更简洁的方法(如 println):

1
2
3
4
5
6
7
8
9
import java.io.PrintWriter

val printWriter = new PrintWriter("output.txt")
try {
printWriter.println("第一行(自动换行)")
printWriter.println("第二行")
} finally {
printWriter.close()
}

执行系统命令:sys.process

Scala 的 sys.process 包提供了强大的系统命令交互能力,支持命令执行、管道、重定向等操作,语法简洁直观。

执行基本命令

通过导入 sys.process._,字符串可以直接转换为命令并执行:

1
2
3
4
5
6
7
import sys.process._

// 执行命令:! 表示执行并返回退出码(0 表示成功)
val exitCode: Int = "ls -al".! // 列出当前目录所有文件(Linux/macOS)
// val exitCode: Int = "dir".! // Windows 系统使用 dir

println(s"命令退出码:$exitCode") // 成功时输出 0
  • !:执行命令并返回退出码(0 表示成功,非 0 表示失败)。
  • !!:执行命令并返回输出结果(字符串类型):
1
2
3
// 获取命令输出结果
val result: String = "echo 'Hello from shell'".!!
println("命令输出:" + result) // 输出:Hello from shell

管道操作(#|

使用 #| 连接多个命令,实现管道功能(类似 shell 中的 |):

1
2
3
// 查找当前目录中包含 "scala" 的文件名(ls | grep scala)
val pipeResult: String = "ls -al" #| "grep scala" !!
println("包含 'scala' 的文件:\n" + pipeResult)
  • 左侧命令的输出作为右侧命令的输入。

重定向操作

使用 #>#>>#< 实现输入输出重定向:

操作符 功能 示例
#> 输出重定向到文件(覆盖) "ls" #> new File("list.txt")
#>> 输出重定向到文件(追加) "echo 'new line'" #>> new File("log.txt")
#< 从文件读取输入 "grep 'error'" #< new File("log.txt")

示例:输出重定向

1
2
3
4
5
6
7
import java.io.File

// 将命令输出写入文件(覆盖)
"ls -al" #> new File("file_list.txt") !

// 追加到文件
"echo '追加的一行'" #>> new File("file_list.txt") !

示例:输入重定向

1
2
3
// 从文件中查找包含 "scala" 的行
val grepResult: String = "grep 'scala'" #< new File("file_list.txt") !!
println("查找结果:\n" + grepResult)
组合命令

可以将多个命令组合成复杂的流程:

1
2
// 先列出文件,过滤出 .scala 文件,再写入 result.txt
("ls -al" #| "grep .scala") #> new File("scala_files.txt") !

最佳实践

  1. 资源管理:读取文件时务必关闭 Source,写入时关闭 Writer,建议使用 try-finally 或 Scala 2.13+ 的 Using 语句自动管理资源:

    1
    2
    3
    4
    5
    6
    import scala.util.Using

    // 自动关闭资源(Scala 2.13+)
    Using(Source.fromFile("data.txt")) { source =>
    source.getLines().foreach(println)
    }.getOrElse(println("文件读取失败"))
  1. 跨平台兼容性:系统命令(如 lsdir)具有平台依赖性,编写跨平台代码时需注意判断操作系统。

  2. 大型文件处理:读取大型文件时,使用 getLines 逐行处理,避免 mkString 一次性加载全部内容导致内存溢出。

  3. 错误处理:执行系统命令时,检查退出码(! 的返回值)或捕获异常,确保命令执行失败时能妥善处理。

欢迎关注我的其它发布渠道