版权属于: Postbird - There I am , in the world more exciting!
原文地址: http://www.ptbird.cn/scala-io-file.html
转载时必须以链接形式注明原始出处及本声明。
scala的文件操作实际上在我看来不如java好,但是相对而言比较清晰明了。
目前很多所谓的教程都是只说了Source.fromFile以及Source.fromUrl两种获取的方式,谈到scala的文件操作,这就结束了。。
其实这不是所谓的教程的锅,毕竟scala的这两个构造source用起来贼方便,顶多注意一下编码。
不过很多人读取文件的时候都遇到过java.nio.charset.MalformedInputException: Input length = 1这个令人抓狂的错误。即使按照网上说的改了编码,也没有太大的帮助。
如果非得解决这个问题,我用的办法是使用 Source.fromByte()去解决。
看了一下scala.2.11.8的源码里面的Source.scala的部分,github地址:https://github.com/scala/scala/blob/v2.11.8/src/library/scala/io/Source.scala#L1a,可以发现除了Source.fromFile和scala.fromUrl之外,针对文件还有fromInputStream、fromIterable 、fromBytes,inputStream和Bytes都是针对java来说的。
所以一种比较容易解决的中文的GBK自己长度不对的方法如下:
这样子做很明显很麻烦,不过也可以使用sorce的一些比较好的方法。另外fromInputStream我倒没有试过,应该一样的效果
val file = new File(i)
val in =new FileInputStream(file)
val bytes = new Array[Byte] (file.length().toInt)
in.read(bytes)
in.close()
Source.fromBytes(bytes).mkString
下面是我做一个小东西的时候用到的一些文件操作。
1、遍历文件夹下所有目录和文件,并存在一个txt中后面使用
val file = new File(i)
//遍历文件夹,获取所有文件
//写入文本文件以便后面使用
//里面也存了所有的目录
//跑一次就行了 之后都从文本文件去获取比较快
def getAllFilePath(dir:File): Iterator[File] ={
try{
val d=dir.listFiles.filter(_.isDirectory)
val f = dir.listFiles.toIterator
f ++ d.toIterator.flatMap(getAllFilePath _)
}
}
val tmpFiles=getAllFilePath(new File("E:rfchina"))
val resText=new PrintWriter("E:resFile.txt")
tmpFiles.foreach(resText.println(_))
resText.close()
2、获取上面txt中存储的所有的文件和目录,返回list
这个很简单没什么,因此是自己的写的并且不存在中文,就没弄那么复杂
val file = new File(i)
//从文本文件中读出所有的文件 返回一个list
def getAllFiles(file:String): List[String] ={
val souce=Source.fromFile(file,"utf-8")
souce.getLines().toList
}
3、获取里面所有的html文件,并对内容进行匹配一个字符串,如果成功记录这个字符串
这里我用了par来并行,因此序列是list并且使用了set来记录,因为set是并行序列,因此可以肆无忌惮的这样子做。
并不会有什么问题。
val file = new File(i)
//逐行处理数据 能打开则打开 打不开就跳过
//打开后需要进行正则匹配 最后能够匹配的都保存在一个set
//使用Set好处是进行并行计算的方便
def getResSet(list:List[String]):Set[String]={
val resText2=new PrintWriter("E:resFile2.txt")
var res=Set[String]()
val reg="ktg"
list.par.foreach(i=>{
val file = new File(i)
if(file.isFile &&( i.endsWith(".htm") || i.endsWith(".html") )){
val in =new FileInputStream(file)
val bytes = new Array[Byte] (file.length().toInt)
in.read(bytes)
in.close()
if(Source.fromBytes(bytes).mkString.contains(reg)) {
println(i)
resText2.println(i)
res=res+i
}
}
})
resText2.close()
res
}
3、获取所有的pdf并且匹配后缀中存在的字符串
这个很简单没什么
val file = new File(i)
//获取 所有的pdf
def getAllPdfFiles(file:String): Set[String] ={
var res=Set[String]()
val souce=Source.fromFile(file)
souce.getLines().filter(i=>{i.contains(".pdf") && (i.contains("kt") || i.contains("ic"))}).foreach(i=>res=res+i)
res
}
Url其实也没啥特别的,主要是汉字编码导致的问题还是使用byte解决会好一些!
其实Source本身就是在java.io 基础上发展来的。
4、代码
在git@osc上存了一个代码片段:https://git.oschina.net/postbird/codes/psq0i3gcv9158htafnmx241