2012-01-19 12 views
5

मैं स्कैला में नए java.nio.file.Files.walkFileTree का उपयोग करना चाहता हूं। और मैं भी सफल रहा:स्कैला में java.nio.file.Files.walkFileTree का उपयोग कैसे करें

class Visitor 
    extends 
     java.nio.file.SimpleFileVisitor [java.nio.file.Path] 
    { 
    override def visitFile(
     File : java.nio.file.Path, 
     Attrs : java.nio.file.attribute.BasicFileAttributes) : java.nio.file.FileVisitResult = 
    { 
     if (! File.toString.contains(".svn")) 
     { 
     System.out.println(File); 
     } // if 

     java.nio.file.FileVisitResult.CONTINUE; 
    } // visitFile 
} // Visitor 

java.nio.file.Files.walkFileTree (Project_Home, new Visitor) 

लेकिन यह कोड ठीक काम करता है, लेकिन मुझे लगता है कि जावा पैराडाइम्स को स्कैला में ले जाना थोड़ा सा लगता है। तो सच स्केल गुरुओं के लिए एक सवाल: क्या कुछ भी मैं सुधार सकता हूं या यह सिर्फ यह है?

उत्तर

6

एक आगंतुक वास्तव में कार्यों के लाभ के बिना foreach है, तो चलिए foreach बनाते हैं। विधि स्थिर है, लेकिन यह पहला तर्क एक Path के रूप में लेता है, तो हम एक foreach विधि है, जो कुछ इस तरह से किया जाता है के साथ Path को बेहतर बनाने के होगी:

import java.nio.file._ 
import java.nio.file.attribute.BasicFileAttributes 

implicit def fromNioPath(path: Path): TraverseFiles = new TraversePath(path) 

और बाकी सब TraversePath वर्ग, अंदर है जो कुछ हद तक इस तरह दिखता है:

class TraversePath(path: Path) { 
    def foreach(f: (Path, BasicFileAttributes) => Unit) { 
    // ... 
    } 
} 

यह पर्याप्त है तो आप इस लिखने के लिए:

ProjectHome foreach ((file, _) => if (!file.toString.contains(".svn")) println(File)) 

बेशक, यह वास्तव में कुछ भी करेंगे नहीं, तो चलो यह कुछ करने के लिए मिलता है:

class TraversePath(path: Path) { 
    def foreach(f: (Path, BasicFileAttributes) => Unit) { 
    class Visitor extends SimpleFileVisitor[Path] { 
     override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = try { 
     f(file, attrs) 
     FileVisitResult.CONTINUE 
     } catch { 
     case _ => FileVisitResult.TERMINATE 
     } 
    } 
    Files.walkFileTree(path, new Visitor) 
    } 
} 

वहाँ, अब है कि रेखा के रूप में अपने कोड किया एक ही बात करना होगा! हालांकि, हम इसे और बेहतर कर सकते हैं। ऐसा होता है कि foreachTraversable की एकमात्र विधि है, इसलिए हम उस वर्ग को बढ़ा सकते हैं, और स्कैला संग्रह के सभी तरीकों को प्राप्त कर सकते हैं!

एकमात्र समस्या यह है कि Traversable.foreach फ़ंक्शन केवल एक तर्क लेता है, और यहां हम दो ले रहे हैं। हालांकि, हम इसे एक tuple प्राप्त करने में बदल सकते हैं।

import java.nio.file._ 
import java.nio.file.attribute.BasicFileAttributes 
import scala.collection.Traversable 

// Make it extend Traversable 
class TraversePath(path: Path) extends Traversable[(Path, BasicFileAttributes)] { 

    // Make foreach receive a function from Tuple2 to Unit 
    def foreach(f: ((Path, BasicFileAttributes)) => Unit) { 
    class Visitor extends SimpleFileVisitor[Path] { 
     override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = try { 
     // Pass a tuple to f 
     f(file -> attrs) 
     FileVisitResult.CONTINUE 
     } catch { 
     case _ => FileVisitResult.TERMINATE 
     } 
    } 
    Files.walkFileTree(path, new Visitor) 
    } 
} 

ProjectHome foreach { 
    // use case to seamlessly deconstruct the tuple 
    case (file, _) => if (!file.toString.contains(".svn")) println(File) 
} 

अस्वीकरण:: यहाँ पूरा कोड है मैं, इस कोड में से कोई भी परीक्षण किया है क्योंकि मैं जावा 7 स्थापित नहीं है। शायद कुछ कीड़े हैं।

2

आप अपना कोड थोड़ा और सुंदर बना सकते हैं, लेकिन दिन के अंत में यह अभी भी सादे पुराने विज़िटर पैटर्न की तरह दिखाई देगा।

2

यहाँ डैनियल स्क्रिप्ट बनाया compilable है:

import java.nio.file._ 
import java.nio.file.attribute.BasicFileAttributes 
import scala.collection.Traversable 

// Make it extend Traversable 
class TraversePath(path: Path) extends Traversable[(Path, BasicFileAttributes)] { 

    // Make foreach receive a function from Tuple2 to Unit 
    def foreach[U](f: ((Path, BasicFileAttributes)) => U) { 
    class Visitor extends SimpleFileVisitor[Path] { 
     override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = try { 
     // Pass a tuple to f 
     f(file -> attrs) 
     FileVisitResult.CONTINUE 
     } catch { 
     case _ => FileVisitResult.TERMINATE 
     } 
    } 
    Files.walkFileTree(path, new Visitor) 
    } 
} 
val projectHome = new TraversePath(Paths.get(".")) 

projectHome foreach { 
    // use case to seamlessly deconstruct the tuple 
    case (file:Path, attr:BasicFileAttributes) => if (!file.toString.contains(".svn")) println(file) 
} 
2

चूतड़ के रूप में Daniel's answer ले रहा है, मैं एक छोटे से सुविधाजनक implicits साथ Path सुलभ बनाने के लिए काम किया है के रूप में आप संग्रह में उपयोग किया जाता है। ध्यान दें कि सभी कार्यों को शामिल नहीं किया गया है।

class TraversePath(path: Path) { 
    def foreach(f: (Path, BasicFileAttributes) => Unit) { 
     Files.walkFileTree(path, new SimpleFileVisitor[Path] { 
      override def visitFile(file: Path, attrs: BasicFileAttributes) = { 
       f(file, attrs) 
       FileVisitResult.CONTINUE 
      } 
     }) 
    } 

    /** 
    * foreach that takes FileVisitResult instead of Unit 
    */ 
    def foreach2(f: (Path, BasicFileAttributes) => FileVisitResult) { 
     Files.walkFileTree(path, new SimpleFileVisitor[Path] { 
      override def visitFile(file: Path, attrs: BasicFileAttributes) = f(file, attrs) 
     }) 
    } 

    def foldLeft[T](t: T)(f: (T, Path) => T) = { 
     var current = t 
     foreach((p, _) => current = f(current, p)) 
     current 
    } 

    def forall(f: Path => Boolean) = { 
     var ret = true 
     foreach2((p, _) => 
      if (!f(path)) { 
       ret = false 
       FileVisitResult.TERMINATE 
      } 
      else 
       FileVisitResult.CONTINUE 
     ) 
     ret 
    } 

    def exists(f: Path => Boolean) = { 
     var ret = false 
     foreach2((p, _) => 
      if (f(path)) { 
       ret = true 
       FileVisitResult.TERMINATE 
      } 
      else 
       FileVisitResult.CONTINUE 
     ) 
    } 

    /** 
    * Directly modifies the underlying path. 
    */ 
    def mapReal(f: Path => Path) = foreach((p, _) => Files.move(p, f(p))) 

    /** 
    * @param f map function 
    * @return a left-folded list with the map function applied to each element 
    */ 
    def map(f: Path => Path) = foldLeft(Nil: List[Path]) { 
     case (xs, p) => xs ::: f(p) :: Nil 
    } 

    def find(f: Path => Boolean) = { 
     var k = None: Option[Path] 
     foreach2((p, _) => 
      if (f(p)) { 
       k = Some(p) 
       FileVisitResult.TERMINATE 
      } else FileVisitResult.CONTINUE 
     ) 
     k 
    } 
} 

implicit def fromNioPath(path: Path) = new TraversePath(path) 

java.nio एपीआई बहुत स्काला साथ प्रयोग के लिए sufficing अत्यंत शक्तिशाली है और है, IMHO,। इन implicits (और अधिक, यदि आप कुछ कार्यों को लिखना चाहते हैं) के साथ, यह भी कठिन कार्यों को पूरा करने के लिए बहुत आसान है।

आप इस अब कुछ इस तरह लिख कर इस्तेमाल कर सकते हैं:

val path1 = Paths.get(sys.props("user.home"), "workspace") 

val path2 = Paths.get(sys.props("user.home"), "workspace2") 

val list1 = path1.foldLeft(Nil: List[Path]) { 
    (xs, p) => xs ::: path1.relativize(p) :: Nil 
} 
val list2 = path2.foldLeft(Nil: List[Path]) { 
    (xs, p) => xs ::: path2.relativize(p) :: Nil 
} 
(list1 diff list2) foreach println 

सादर,
Danyel

0

FIles.walkFileTree उदाहरण दो निर्देशिका तुलना करने के लिए/फ़ाइल अंतर के दो निर्देशिका सिंक्रनाइज़ करने

private static void compareDirectories(String srcPath, String destPath) throws IOException, InterruptedException { 
    System.out.println("sync. started...."); 
    final Path mainDir = Paths.get(srcPath); 
    final Path otherDir = Paths.get(destPath); 

    // Walk thru mainDir directory 
    Files.walkFileTree(mainDir, new FileVisitor<Path>() { 
     @Override 
     public FileVisitResult preVisitDirectory(Path path, 
       BasicFileAttributes atts) throws IOException { 
      return visitFile(path, atts); 
     } 

     @Override 
     public FileVisitResult visitFile(Path path, BasicFileAttributes mainAtts) 
       throws IOException { 
      // I've seen two implementations on windows and MacOSX. One has passed the relative path, one the absolute path. 
      // This works in both cases 
      Path relativePath = mainDir.relativize(mainDir.resolve(path)); 
      File tmpFile = new File(otherDir+"/"+relativePath); 

       if(tmpFile.exists()) { 
        BasicFileAttributes otherAtts = Files.readAttributes(otherDir.resolve(relativePath), BasicFileAttributes.class); 
        // Do your comparison logic here: we are skipping directories as all directories are traversed automatically 
        if(!new File(path.toString()).isDirectory()) { 
                //write your logic for comparing files 
         compareEntries(mainDir, otherDir, relativePath, mainAtts, otherAtts); 
        } 
        else { 
         File src = new File(path.toString()); 

                //write your logic here for comparing directories 
                compareDirectories(src,tmpFile.toPath().toString()+"/"+s); 
        } 
       } 
       else { 
              //this function will copy missing files in destPath from srcPath recursive function till depth of directory structure 
        copyFolderOrFiles(new File(path.toString()), tmpFile); 
       } 
      return FileVisitResult.CONTINUE; 
     } 

     @Override 
     public FileVisitResult postVisitDirectory(Path path, 
       IOException exc) throws IOException { 
      return FileVisitResult.CONTINUE; 
     } 

     @Override 
     public FileVisitResult visitFileFailed(Path path, IOException exc) 
       throws IOException { 
      exc.printStackTrace(); 
      // If the root directory has failed it makes no sense to continue 
      return (path.equals(mainDir))? FileVisitResult.TERMINATE:FileVisitResult.CONTINUE; 
     } 
    }); 
} 
0

अन्य पदों के विचारों को विस्तारित करना। मुझे समाधान पसंद है जहां हम कक्षा वर्गों से मिल सकते हैं। निम्नलिखित कोड विज़िटर को विभिन्न घटनाओं के लिए स्ट्रिंग का संग्रह देता है जो आगंतुक को बुलाया जाता था।

FileWalker(java.nio.file.Paths.get(" your dir ")).map({ 
    case PreVisitDirectory(dir, atts) => s"about to visit dir ${dir}" 
    case PostVisitDirectory(dir, exc) => s"have visited dir ${dir}" 
    case VisitFile(file, attrs) => s"visiting file ${file}" 
    case VisitFileFailed(file, exc) => s"failed to visit ${file}" 
}) 

FileWalker के कार्यान्वयन है:

import java.io.IOException 
import java.nio.file.{FileVisitResult, Files, Path, SimpleFileVisitor} 
import java.nio.file.attribute.BasicFileAttributes 

trait FileVisitEvent 
case class PreVisitDirectory(path: Path, atts: BasicFileAttributes) extends FileVisitEvent 
case class PostVisitDirectory(dir: Path, exc: IOException) extends FileVisitEvent 
case class VisitFile(file: Path, attrs: BasicFileAttributes) extends FileVisitEvent 
case class VisitFileFailed(file: Path, exc: IOException) extends FileVisitEvent 

/** 
    * Scala style walker for a directory tree 
    * 
    * Is a treversable over the tree which traverses different event types extending {{FileVisitEvent}} 
    * 
    * @param from 
    */ 
class FileWalker(from: Path) extends Traversable[FileVisitEvent] { 
    // just to simplify error handling 
    def wrapper(x: => Unit): FileVisitResult = try { 
    x 
    FileVisitResult.CONTINUE 
    } 
    catch { 
    case _ : Throwable => FileVisitResult.TERMINATE 
    } 

    override def foreach[U](f: (FileVisitEvent) => U): Unit = { 
    Files.walkFileTree(from, new SimpleFileVisitor[Path] { 
     override def preVisitDirectory(dir: Path, atts: BasicFileAttributes): FileVisitResult = 
     wrapper(f(PreVisitDirectory(dir, atts))) 

     override def postVisitDirectory(dir: Path, exc: IOException): FileVisitResult = 
     wrapper(f(PostVisitDirectory(dir, exc))) 

     override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = 
     wrapper(f(VisitFile(file, attrs))) 

     override def visitFileFailed(file: Path, exc: IOException): FileVisitResult = 
     wrapper(f(VisitFileFailed(file, exc))) 
    }) 
    } 
} 

object FileWalker { 
    def apply(from : Path) = new FileWalker(from) 
} 
संबंधित मुद्दे