1. 基本文件读写
读取文件
import scala.io.Source
import java.io.{File, PrintWriter}
import scala.collection.mutable
// 方法1: 使用Source读取整个文件
val source = Source.fromFile("input.txt")
val content = source.mkString // 读取全部内容
source.close()
// 方法2: 逐行读取(推荐,节省内存)
val lines = Source.fromFile("input.txt").getLines().toList
// 方法3: 使用try-with-resources风格
val content2 = using(Source.fromFile("input.txt")) { source =>
source.mkString
}
// 辅助函数:资源管理
def using[A <: { def close(): Unit }, B](resource: A)(f: A => B): B = {
try {
f(resource)
} finally {
resource.close()
}
}
写入文件
// 方法1: 使用PrintWriter
val writer = new PrintWriter(new File("output.txt"))
writer.write("Hello, World!")
writer.close()
// 方法2: 使用Java NIO(更现代的方式)
import java.nio.file.{Files, Paths, StandardOpenOption}
val data = "Hello, World!".getBytes
Files.write(Paths.get("output.txt"), data)
// 方法3: 使用scala.util.Using(Scala 2.13+)
import scala.util.Using
Using(new PrintWriter(new File("output.txt"))) { writer =>
writer.write("Hello, World!")
}
2. 完整单词统计示例
方案1:基本版本
import scala.io.Source
import scala.collection.mutable.Map
object WordCountBasic {
def main(args: Array[String]): Unit = {
// 读取文件
val source = Source.fromFile("input.txt")
val lines = try {
source.getLines().toList
} finally {
source.close()
}
// 单词统计
val wordCount = mutable.Map[String, Int]().withDefaultValue(0)
for {
line <- lines
word <- line.split("\\W+") // 按非单词字符分割
if word.nonEmpty
} {
val normalizedWord = word.toLowerCase()
wordCount(normalizedWord) += 1
}
// 输出结果
wordCount.toSeq
.sortBy(-_._2) // 按频率降序排序
.foreach { case (word, count) =>
println(s"$word: $count")
}
}
}
方案2:函数式编程风格
import scala.io.Source
import scala.util.Using
object WordCountFunctional {
def countWords(filePath: String): Map[String, Int] = {
Using.resource(Source.fromFile(filePath)) { source =>
source.getLines()
.flatMap(_.split("\\W+")) // 分割单词
.filter(_.nonEmpty) // 过滤空字符串
.map(_.toLowerCase) // 转为小写
.toList // 转为List
.groupBy(identity) // 按单词分组
.view
.mapValues(_.size) // 计算每组数量
.toMap
}
}
def main(args: Array[String]): Unit = {
val wordCount = countWords("input.txt")
// 排序并输出
wordCount.toSeq
.sortWith { case ((w1, c1), (w2, c2)) =>
c1 > c2 || (c1 == c2 && w1 < w2)
}
.foreach { case (word, count) =>
println(f"$word%-15s $count%d")
}
// 统计总数
val totalWords = wordCount.values.sum
println(s"\nTotal unique words: ${wordCount.size}")
println(s"Total words: $totalWords")
}
}
方案3:使用Spark(处理大文件)
import org.apache.spark.sql.SparkSession
object WordCountSpark {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.appName("WordCount")
.master("local[*]") // 本地模式
.getOrCreate()
import spark.implicits._
// 读取文件
val textFile = spark.read.textFile("input.txt")
// 单词统计
val wordCounts = textFile
.flatMap(_.split("\\W+"))
.filter(_.nonEmpty)
.map(_.toLowerCase)
.groupBy("value")
.count()
.orderBy($"count".desc)
// 显示结果
wordCounts.show(20, truncate = false)
// 保存结果到文件
wordCounts
.coalesce(1) // 合并为一个文件
.write
.csv("word_count_output")
spark.stop()
}
}
3. 高级功能示例
支持多种文件编码
import scala.io.{Codec, Source}
// 指定编码读取文件
val source = Source.fromFile("input.txt")(Codec.UTF8)
val content = source.mkString
source.close()
// 读取多个文件
def countWordsInDirectory(dirPath: String): Map[String, Int] = {
import java.io.File
val dir = new File(dirPath)
val files = dir.listFiles().filter(_.isFile).filter(_.getName.endsWith(".txt"))
files.foldLeft(Map.empty[String, Int]) { (acc, file) =>
val fileWordCount = countWords(file.getPath)
// 合并两个Map
(acc.keySet ++ fileWordCount.keySet).map { key =>
key -> (acc.getOrElse(key, 0) + fileWordCount.getOrElse(key, 0))
}.toMap
}
}
带标点符号处理的单词统计
import scala.io.Source
object AdvancedWordCount {
def cleanWord(word: String): String = {
// 移除开头和结尾的标点符号
word
.replaceAll("^[^a-zA-Z0-9]+", "") // 开头非字母数字
.replaceAll("[^a-zA-Z0-9]+$", "") // 结尾非字母数字
.toLowerCase
}
def countWordsWithContext(filePath: String): Map[String, (Int, List[String])] = {
Using.resource(Source.fromFile(filePath)) { source =>
val lines = source.getLines().toList
lines.zipWithIndex
.flatMap { case (line, lineNum) =>
line.split("\\s+").zipWithIndex.map { case (word, wordPos) =>
(cleanWord(word), (lineNum + 1, wordPos + 1, line.trim))
}
}
.filter(_._1.nonEmpty)
.groupBy(_._1) // 按单词分组
.map { case (word, contexts) =>
val count = contexts.size
// 获取前3个出现位置作为示例
val examples = contexts.take(3).map { case (_, (line, pos, text)) =>
s"Line $line, Position $pos: ...${text.take(50)}..."
}
word -> (count, examples)
}
}
}
}
4. 测试示例文件
创建 input.txt:
Hello World! This is a test file.
Hello again, world. Testing, testing, 1, 2, 3.
Scala is great for data processing.
Hello Scala World!
运行结果示例:
hello: 3
world: 2
testing: 2
scala: 2
is: 2
a: 1
again: 1
data: 1
file: 1
for: 1
great: 1
processing: 1
test: 1
this: 1
1: 1
2: 1
3: 1
5. 性能优化建议
- 大文件处理:使用流式处理,避免一次性加载整个文件
- 内存管理:及时关闭文件资源
- 并行处理:对于大文件,可以使用并行集合
- 缓存中间结果:如果多次统计,缓存清洗后的数据
// 并行处理版本
def parallelWordCount(filePath: String): Map[String, Int] = {
Using.resource(Source.fromFile(filePath)) { source =>
source.getLines()
.toVector // 转为Vector支持并行
.par // 转为并行集合
.flatMap(_.split("\\W+"))
.filter(_.nonEmpty)
.map(_.toLowerCase)
.groupBy(identity)
.mapValues(_.size)
.seq // 转回顺序集合
.toMap
}
}