ডিরেক্টরিতে পুনরাবৃত্তভাবে ফাইল তালিকাভুক্ত করার জন্য কি খুব ভাল "স্কেলা-এস্কু" (আমার ধারণা আমি কার্যকরী বলতে চাই)? একটি নির্দিষ্ট প্যাটার্ন মেলে কি?
উদাহরণস্বরূপ যাও recursively মিলে সব ফাইল "a*.foo"মধ্যে c:\temp।
ডিরেক্টরিতে পুনরাবৃত্তভাবে ফাইল তালিকাভুক্ত করার জন্য কি খুব ভাল "স্কেলা-এস্কু" (আমার ধারণা আমি কার্যকরী বলতে চাই)? একটি নির্দিষ্ট প্যাটার্ন মেলে কি?
উদাহরণস্বরূপ যাও recursively মিলে সব ফাইল "a*.foo"মধ্যে c:\temp।
উত্তর:
স্কেল কোড সাধারণত পাঠ্য ডিরেক্টরি সহ আই / ও এর সাথে ডিল করার জন্য জাভা ক্লাস ব্যবহার করে। সুতরাং আপনাকে কিছু করতে হবে:
import java.io.File
def recursiveListFiles(f: File): Array[File] = {
val these = f.listFiles
these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles)
}
আপনি সমস্ত ফাইল সংগ্রহ করতে পারেন এবং তারপরে একটি রেজেক্স ব্যবহার করে ফিল্টার করতে পারেন:
myBigFileArray.filter(f => """.*\.html$""".r.findFirstIn(f.getName).isDefined)
অথবা আপনি পুনরাবৃত্ত অনুসন্ধানে রেজেজকে অন্তর্ভুক্ত করতে পারেন:
import scala.util.matching.Regex
def recursiveListFiles(f: File, r: Regex): Array[File] = {
val these = f.listFiles
val good = these.filter(f => r.findFirstIn(f.getName).isDefined)
good ++ these.filter(_.isDirectory).flatMap(recursiveListFiles(_,r))
}
listFilesআয় nullযদি fএকটি ডিরেক্টরি দিকে নির্দেশ করে না অথবা একটা আই ত্রুটি (অন্তত জাভা বৈশিষ্ট অনুযায়ী) পারেন। নাল চেক যোগ করা উত্পাদন ব্যবহারের জন্য সম্ভবত বুদ্ধিমান।
f.isDirectoryসত্য ফিরে কিন্তু f.listFilesফিরে যাওয়ার null। উদাহরণস্বরূপ, আপনার কাছে ফাইলগুলি পড়ার অনুমতি না থাকলে আপনি একটি পাবেন null। উভয় চেকের পরিবর্তে, আমি কেবল একটি নাল চেক যুক্ত করব।
f.listFilesনাল ফেরৎ যখন !f.isDirectory।
আমি স্ট্রিমগুলির সাথে সমাধানটি পছন্দ করব কারণ আপনি অসীম ফাইল সিস্টেমের মাধ্যমে পুনরাবৃত্তি করতে পারেন (স্ট্রিমগুলি অলস মূল্যায়িত সংগ্রহগুলি)
import scala.collection.JavaConversions._
def getFileTree(f: File): Stream[File] =
f #:: (if (f.isDirectory) f.listFiles().toStream.flatMap(getFileTree)
else Stream.empty)
অনুসন্ধানের জন্য উদাহরণ
getFileTree(new File("c:\\main_dir")).filter(_.getName.endsWith(".scala")).foreach(println)
def getFileTree(f: File): Stream[File] = f #:: Option(f.listFiles()).toStream.flatten.flatMap(getFileTree)
জাভা 1.7 হিসাবে আপনারা সবাই java.nio ব্যবহার করা উচিত। এটি কাছাকাছি দেশি পারফরম্যান্স সরবরাহ করে (java.io খুব ধীর) এবং কিছু সহায়ক সহায়ক রয়েছে
তবে জাভা 1.8 আপনাকে ঠিক কী হিসাবে সন্ধান করছে তা সূচনা করে:
import java.nio.file.{FileSystems, Files}
import scala.collection.JavaConverters._
val dir = FileSystems.getDefault.getPath("/some/path/here")
Files.walk(dir).iterator().asScala.filter(Files.isRegularFile(_)).foreach(println)
আপনি ফাইলের মিলও চেয়েছিলেন। চেষ্টা করুন java.nio.file.Files.findএবং এছাড়াওjava.nio.file.Files.newDirectoryStream
ডকুমেন্টেশন এখানে দেখুন: http://docs.oracle.com/javase/tutorial/essential/io/walk.html
for (file <- new File("c:\\").listFiles) { processFile(file) }
স্কালা একটি বহুমাত্রিক ভাষা। ডিরেক্টরিকে পুনরাবৃত্তি করার একটি ভাল "স্কালা-এস্কু" উপায়টি একটি বিদ্যমান কোডটি পুনরায় ব্যবহার করা হবে!
আমি কমন্স-আইও -কে কোনও ডিরেক্টরিকে পুনরাবৃত্তি করার একদম স্কেল-এস্কো পদ্ধতি ব্যবহার করার বিষয়টি বিবেচনা করব । এটিকে সহজ করার জন্য আপনি কিছু অন্তর্নিহিত রূপান্তর ব্যবহার করতে পারেন। লাইক
import org.apache.commons.io.filefilter.IOFileFilter
implicit def newIOFileFilter (filter: File=>Boolean) = new IOFileFilter {
def accept (file: File) = filter (file)
def accept (dir: File, name: String) = filter (new java.io.File (dir, name))
}
আমি আপনার স্ট্রিম সমাধানটি পছন্দ করি তবে এটি (এবং অন্যান্যরা) লুকানো ডিরেক্টরিতে পুনরাবৃত্তি করে। আমরা listFilesঅ-ডিরেক্টরিতে বাতিল হয়ে যায় এমন সত্যটি ব্যবহার করেও সহজ করতে পারি ।
def tree(root: File, skipHidden: Boolean = false): Stream[File] =
if (!root.exists || (skipHidden && root.isHidden)) Stream.empty
else root #:: (
root.listFiles match {
case null => Stream.empty
case files => files.toStream.flatMap(tree(_, skipHidden))
})
এখন আমরা ফাইলগুলি তালিকাবদ্ধ করতে পারি
tree(new File(".")).filter(f => f.isFile && f.getName.endsWith(".html")).foreach(println)
বা পরবর্তী প্রক্রিয়াজাতকরণের জন্য পুরো স্ট্রিমটি উপলব্ধি করুন
tree(new File("dir"), true).toArray
অ্যাপাচি কমন্স আইওর ফাইলUtils এক লাইনে ফিট করে এবং বেশ পঠনযোগ্য:
import scala.collection.JavaConversions._ // important for 'foreach'
import org.apache.commons.io.FileUtils
FileUtils.listFiles(new File("c:\temp"), Array("foo"), true).foreach{ f =>
}
এখনও কেউ https://github.com/pathikrit/better-files উল্লেখ করেনি
val dir = "src"/"test"
val matches: Iterator[File] = dir.glob("**/*.{java,scala}")
// above code is equivalent to:
dir.listRecursively.filter(f => f.extension ==
Some(".java") || f.extension == Some(".scala"))
Scala.tools.nsc.io এ একবার দেখুন
ডিরেক্টরি ক্লাসে গভীর তালিকাবদ্ধ কার্যকারিতা সহ কয়েকটি খুব দরকারী ইউটিলিটি রয়েছে।
যদি আমি মনে করি সঠিকভাবে এটি retronym দ্বারা হাইলাইট করা হয়েছিল (সম্ভবত অবদান ছিল) এবং স্ট্যান্ডগ্যাপ হিসাবে আইও স্ট্যান্ডার্ড লাইব্রেরিতে নতুন এবং আরও সম্পূর্ণ বাস্তবায়ন পাওয়ার আগে দেখা হত seen
এবং এখানে @ রিক -777 থেকে ফিল্টার সহ @ ডানকান এমসিগ্রিগর থেকে স্ট্রিম সলিউশনটির মিশ্রণ রয়েছে:
def tree( root: File, descendCheck: File => Boolean = { _ => true } ): Stream[File] = {
require(root != null)
def directoryEntries(f: File) = for {
direntries <- Option(f.list).toStream
d <- direntries
} yield new File(f, d)
val shouldDescend = root.isDirectory && descendCheck(root)
( root.exists, shouldDescend ) match {
case ( false, _) => Stream.Empty
case ( true, true ) => root #:: ( directoryEntries(root) flatMap { tree( _, descendCheck ) } )
case ( true, false) => Stream( root )
}
}
def treeIgnoringHiddenFilesAndDirectories( root: File ) = tree( root, { !_.isHidden } ) filter { !_.isHidden }
এটি আপনাকে আউটরিচেক () ফাংশনটির সাহায্যে কোন ধরণের ডিরেক্টরি পুনর্বার করতে হবে তা সিদ্ধান্ত দেওয়ার সময় একটি (সম্ভাব্য বিশাল এবং খুব ধীর) তালিকা [ফাইল] এর পরিবর্তে একটি স্ট্রিম [ফাইল] দেয় gives
কেমন
def allFiles(path:File):List[File]=
{
val parts=path.listFiles.toList.partition(_.isDirectory)
parts._2 ::: parts._1.flatMap(allFiles)
}
আমি ব্যক্তিগতভাবে @ রেক্স কেরের প্রস্তাবিত সমাধানের কমনীয়তা এবং সরলতা পছন্দ করি। তবে এখানে একটি লেজ পুনরাবৃত্ত সংস্করণ দেখতে পারে:
def listFiles(file: File): List[File] = {
@tailrec
def listFiles(files: List[File], result: List[File]): List[File] = files match {
case Nil => result
case head :: tail if head.isDirectory =>
listFiles(Option(head.listFiles).map(_.toList ::: tail).getOrElse(tail), result)
case head :: tail if head.isFile =>
listFiles(tail, head :: result)
}
listFiles(List(file), Nil)
}
এখানে রেক্স কেরারের অনুরূপ সমাধান, তবে একটি ফাইল ফিল্টার অন্তর্ভুক্ত করা হয়েছে:
import java.io.File
def findFiles(fileFilter: (File) => Boolean = (f) => true)(f: File): List[File] = {
val ss = f.list()
val list = if (ss == null) {
Nil
} else {
ss.toList.sorted
}
val visible = list.filter(_.charAt(0) != '.')
val these = visible.map(new File(f, _))
these.filter(fileFilter) ++ these.filter(_.isDirectory).flatMap(findFiles(fileFilter))
}
পদ্ধতিটি একটি তালিকা [ফাইল] ফিরিয়ে দেয় যা অ্যারে [ফাইল] এর চেয়ে কিছুটা সুবিধাজনক। এটি লুকানো সমস্ত ডিরেক্টরি (যেমন '।' দিয়ে শুরু করে) উপেক্ষা করে।
এটি আপনার নির্বাচনের ফাইল ফিল্টার ব্যবহার করে আংশিকভাবে প্রয়োগ করা হয়েছে, উদাহরণস্বরূপ:
val srcDir = new File( ... )
val htmlFiles = findFiles( _.getName endsWith ".html" )( srcDir )
সর্বাধিক সহজ স্কেলা-সমাধান (যদি আপনি স্কালা সংকলক লাইব্রেরির প্রয়োজন মনে করেন না):
val path = scala.reflect.io.Path(dir)
scala.tools.nsc.io.Path.onlyFiles(path.walk).foreach(println)
অন্যথায়, @ রেনেউদের সমাধানটি সংক্ষিপ্ত এবং মিষ্টি (যদি আপনি অ্যাপাচি কমন্স ফাইল ইউটিলে আঁকতে আপত্তি না করেন):
import scala.collection.JavaConversions._ // enables foreach
import org.apache.commons.io.FileUtils
FileUtils.listFiles(dir, null, true).foreach(println)
কোথায় dirএকটি java.io.File:
new File("path/to/dir")
দেখে মনে হচ্ছে কেউ scala-ioস্কেল-ইনকিউব্রেটর থেকে গ্রন্থাগারের উল্লেখ করেনি ...
import scalax.file.Path
Path.fromString("c:\temp") ** "a*.foo"
বা সাথে implicit
import scalax.file.ImplicitConversions.string2path
"c:\temp" ** "a*.foo"
অথবা আপনি যদি implicitস্পষ্টভাবে চান ...
import scalax.file.Path
import scalax.file.ImplicitConversions.string2path
val dir: Path = "c:\temp"
dir ** "a*.foo"
নথিপত্র এখানে পাওয়া যায়: http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_path_sets
এই প্রসারণটি আমার পক্ষে কাজ করে:
def findFiles(dir: File, criterion: (File) => Boolean): Seq[File] = {
if (dir.isFile) Seq()
else {
val (files, dirs) = dir.listFiles.partition(_.isFile)
files.filter(criterion) ++ dirs.toSeq.map(findFiles(_, criterion)).foldLeft(Seq[File]())(_ ++ _)
}
}
আপনি এর জন্য লেজ পুনরাবৃত্তি ব্যবহার করতে পারেন:
object DirectoryTraversal {
import java.io._
def main(args: Array[String]) {
val dir = new File("C:/Windows")
val files = scan(dir)
val out = new PrintWriter(new File("out.txt"))
files foreach { file =>
out.println(file)
}
out.flush()
out.close()
}
def scan(file: File): List[File] = {
@scala.annotation.tailrec
def sc(acc: List[File], files: List[File]): List[File] = {
files match {
case Nil => acc
case x :: xs => {
x.isDirectory match {
case false => sc(x :: acc, xs)
case true => sc(acc, xs ::: x.listFiles.toList)
}
}
}
}
sc(List(), List(file))
}
}
আপনি স্কালার অ্যাবস্ট্রাকফাইলের পরিবর্তে জাভা ফাইলটি ব্যবহার করছেন কেন?
স্কালার অ্যাবস্ট্রাকফাইলে, পুনরুক্তি সমর্থন জেমস মুরের সমাধানটির আরও সংক্ষিপ্ত সংস্করণ লেখার অনুমতি দেয়:
import scala.reflect.io.AbstractFile
def tree(root: AbstractFile, descendCheck: AbstractFile => Boolean = {_=>true}): Stream[AbstractFile] =
if (root == null || !root.exists) Stream.empty
else
(root.exists, root.isDirectory && descendCheck(root)) match {
case (false, _) => Stream.empty
case (true, true) => root #:: root.iterator.flatMap { tree(_, descendCheck) }.toStream
case (true, false) => Stream(root)
}