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