2016-01-20 61 views
0

從«學習Scala的併發編程»一個例子:爲什麼此代碼無法刪除文件?

package org.learningconcurrency 

import java.io.File 
import java.util.concurrent.atomic.AtomicReference 
import java.util.concurrent.{ConcurrentHashMap, ForkJoinPool, LinkedBlockingQueue} 

import org.apache.commons.io.FileUtils 

import scala.annotation.tailrec 

/** 
    * Created by kaiyin on 1/19/16. 
    */ 
import org.learningconcurrency.ch3.Ch3.execute 
import scala.collection.convert.decorateAsScala._ 

object Issue { 

    sealed trait State 

    class Idle extends State 

    class Creating extends State 

    class Copying(val n: Int) extends State 

    class Deleting extends State 

    class Entry(val isDir: Boolean) { 
    val state = new AtomicReference[State](new Idle) 

    } 

    class FileSystem(val root: String) { 
    val rootDir = new File(root) 
    val files: collection.concurrent.Map[String, Entry] = new ConcurrentHashMap[String, Entry]().asScala 
    for (f <- FileUtils.iterateFiles(rootDir, null, false).asScala) 
     files.put(f.getName, new Entry(false)) 

    def deleteFile(filename: String): Unit = { 
     files.get(filename) match { 
     case None => 
      log(s"Path '$filename' does not exist!") 
     case Some(entry) if entry.isDir => 
      log(s"Path '$filename' is a directory!") 
     case Some(entry) => execute { 
      if (prepareForDelete(entry)) 
      if (FileUtils.deleteQuietly(new File(filename))) 
       files.remove(filename) 
     } 
     } 
    } 
    } 

    @tailrec private def prepareForDelete(entry: Entry): Boolean = { 
    val s0 = entry.state.get 
    s0 match { 
     case i: Idle => 
     if (entry.state.compareAndSet(s0, new Deleting)) true 
     else prepareForDelete(entry) 
     case c: Creating => 
     log("File is being created, cannot delete") 
     false 
     case c: Copying => 
     log("File is being created, cannot delete") 
     false 
     case d: Deleting => 
     false 
    } 
    } 
    def main(args: Array[String]) { 
    val fs = new FileSystem("/tmp") 
    fs.files.foreach(println _) 
    // Thread.sleep(500) 
    fs.deleteFile("test") 
    } 
} 

它只是檢查一個文件的狀態,然後將其刪除,並且代碼看起來像它應該工作,但它運行後,這個文件我已創建touch /tmp/test仍在那裏。

回答

0

該問題與FileUtils.deleteQuietly(new File(filename))相關。根據docs,deleteQuietly的作用與File.delete()相同,但不是引發異常,而是在文件被刪除時返回true,如果不是,則返回false

添加調試日誌將表明deleteQuietly不工作:

if (FileUtils.deleteQuietly(new File(filename))) { 
    println("File was deleted!") 
    files.remove(filename)  
} else { 
    println("File was NOT deleted!") 
} 

它應該打印File was NOT deleted

那麼,怎麼了?讓我們來檢查你傳遞給deleteQuietly參數:

println((new File(filename)).exists()) // returns false 

似乎File沒有找到您的文件。什麼不見​​了?

由於您只提供了相對路徑test,你也需要提供父目錄:

case Some(entry) => execute { 
     if (prepareForDelete(entry)) 
     if (FileUtils.deleteQuietly(new File(rootDir, filename))) 
      files.remove(filename) 
    } 
相關問題