আমি কীভাবে সমস্ত ফাইলকে স্কালায় একটি উপ-ডিরেক্টরিতে লিস্ট করব?


91

ডিরেক্টরিতে পুনরাবৃত্তভাবে ফাইল তালিকাভুক্ত করার জন্য কি খুব ভাল "স্কেলা-এস্কু" (আমার ধারণা আমি কার্যকরী বলতে চাই)? একটি নির্দিষ্ট প্যাটার্ন মেলে কি?

উদাহরণস্বরূপ যাও recursively মিলে সব ফাইল "a*.foo"মধ্যে c:\temp

উত্তর:


112

স্কেল কোড সাধারণত পাঠ্য ডিরেক্টরি সহ আই / ও এর সাথে ডিল করার জন্য জাভা ক্লাস ব্যবহার করে। সুতরাং আপনাকে কিছু করতে হবে:

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))
}

7
সতর্কতা: আমি এই কোডটি চালিয়েছি এবং কখনও কখনও f.listFiles নালায় দেয় (কেন জানি না তবে আমার ম্যাকটিতে এটি করে) এবং পুনরাবৃত্তলিস্টফাইলে ফাংশন ক্র্যাশ হয়ে গেছে। আমি স্কেলে একটি মার্জিত নাল চেক তৈরির জন্য যথেষ্ট অভিজ্ঞ নই, তবে যদি এই == নাল আমার পক্ষে কাজ করে তবে খালি অ্যারেটি ফিরিয়ে দেওয়া।
জানুয়ারী

4
@Jan - listFilesআয় nullযদি fএকটি ডিরেক্টরি দিকে নির্দেশ করে না অথবা একটা আই ত্রুটি (অন্তত জাভা বৈশিষ্ট অনুযায়ী) পারেন। নাল চেক যোগ করা উত্পাদন ব্যবহারের জন্য সম্ভবত বুদ্ধিমান।
রেক্স কের

4
কালো @Peter - তুমি এখনো , নাল চেক প্রয়োজন যেহেতু এটা সম্ভব জন্য f.isDirectoryসত্য ফিরে কিন্তু f.listFilesফিরে যাওয়ার null। উদাহরণস্বরূপ, আপনার কাছে ফাইলগুলি পড়ার অনুমতি না থাকলে আপনি একটি পাবেন null। উভয় চেকের পরিবর্তে, আমি কেবল একটি নাল চেক যুক্ত করব।
রেক্স কের

4
বস্তুত আপনি শুধুমাত্র, নাল চেক প্রয়োজন হিসাবে f.listFilesনাল ফেরৎ যখন !f.isDirectory
ডানকান ম্যাকগ্রিগোর

4
নাল চেক সম্পর্কে, সর্বাধিক অভিহিত পদ্ধতি হ'ল নালটিকে বিকল্পে রূপান্তর করা এবং মানচিত্র ব্যবহার করা। সুতরাং অ্যাসাইনমেন্টটি ভাল এই = অপশন (f.listFiles) এবং ++ অপারেটরটি শেষে 'getOrElse' সহ একটি মানচিত্রের ক্রিয়াকলাপের অভ্যন্তরে রয়েছে
বা পেরেল

46

আমি স্ট্রিমগুলির সাথে সমাধানটি পছন্দ করব কারণ আপনি অসীম ফাইল সিস্টেমের মাধ্যমে পুনরাবৃত্তি করতে পারেন (স্ট্রিমগুলি অলস মূল্যায়িত সংগ্রহগুলি)

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)

4
বিকল্প বাক্য গঠন:def getFileTree(f: File): Stream[File] = f #:: Option(f.listFiles()).toStream.flatten.flatMap(getFileTree)
ভ্যাসিলিনভিকভ

4
আমি আপনার অভিপ্রায়টির সাথে একমত, তবে এটি আপনার সমাধানটি অর্থহীন। listFiles () ইতিমধ্যে একটি সম্পূর্ণ মূল্যায়িত অ্যারে প্রদান করে, যা আপনার তখন "অলসভাবে" টোস্ট্রিমে মূল্যায়ন করে। আপনার একটি স্ট্রিম ফর্ম স্ক্র্যাচ দরকার, java.nio.file.DirectoryStream দেখুন।
ড্যানিয়েল ল্যাংডন

7
@ ড্যানিয়েল এটি একেবারে কঠোর নয়, এটি ডিরেক্টরিকে অলসভাবে পুনরাবৃত্তি করে।
গিলাইম মাস

4
আমি এখনই আমার অসীম ফাইল সিস্টেমটিতে এটি চেষ্টা করব :-)
ব্রায়ান অগ্নিউ

সাবধানতা: জাভা কনভার্সনগুলি এখন হ্রাস করা হয়েছে। জাভা কনভার্টারস এবং এস্কালা সজ্জা ইনস্ট্রড ব্যবহার করুন।
সুমা

25

জাভা 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


আমি পেয়েছি: ত্রুটি: (38, 32) মান asScala java.util.Iterator [java.nio.file.Path] এর সদস্য নয়। ফাইলসওয়াক (dir) .iterator ()। asScala.filter (ফাইল.আইরেগুলার ফাইল) _))। foreach (println)
stuart


11

স্কালা একটি বহুমাত্রিক ভাষা। ডিরেক্টরিকে পুনরাবৃত্তি করার একটি ভাল "স্কালা-এস্কু" উপায়টি একটি বিদ্যমান কোডটি পুনরায় ব্যবহার করা হবে!

আমি কমন্স-আইও -কে কোনও ডিরেক্টরিকে পুনরাবৃত্তি করার একদম স্কেল-এস্কো পদ্ধতি ব্যবহার করার বিষয়টি বিবেচনা করব । এটিকে সহজ করার জন্য আপনি কিছু অন্তর্নিহিত রূপান্তর ব্যবহার করতে পারেন। লাইক

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))
}

11

আমি আপনার স্ট্রিম সমাধানটি পছন্দ করি তবে এটি (এবং অন্যান্যরা) লুকানো ডিরেক্টরিতে পুনরাবৃত্তি করে। আমরা 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

6

অ্যাপাচি কমন্স আইওর ফাইল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 =>

}

আমাকে টাইপ তথ্য যুক্ত করতে হয়েছিল: ফাইলআপিল.লিটফাইলেস (নতুন ফাইল ("সি: \ টেম্প")), অ্যারে ("ফু"), সত্য)। টু অ্যারে (অ্যারে [ফাইল] ())। ফোরচ {এফ =>}
জেসন হুইলার

এটি কেস-সংবেদনশীল ফাইল সিস্টেমে খুব বেশি কার্যকর নয় কারণ সরবরাহকৃত এক্সটেনশানগুলি অবশ্যই কেসের সাথে মেলে। এক্সটেনশনফিলকম্পারেটর নির্দিষ্ট করার উপায় নেই বলে মনে হয়।
ব্রেন্ট ফাউস্ট

একটি কর্মফল: অ্যারে সরবরাহ করুন ("foo", "FOO", "পিএনজি", "পিএনজি")
রেনেউদ

5

এখনও কেউ 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")) 

3

Scala.tools.nsc.io এ একবার দেখুন

ডিরেক্টরি ক্লাসে গভীর তালিকাবদ্ধ কার্যকারিতা সহ কয়েকটি খুব দরকারী ইউটিলিটি রয়েছে।

যদি আমি মনে করি সঠিকভাবে এটি retronym দ্বারা হাইলাইট করা হয়েছিল (সম্ভবত অবদান ছিল) এবং স্ট্যান্ডগ্যাপ হিসাবে আইও স্ট্যান্ডার্ড লাইব্রেরিতে নতুন এবং আরও সম্পূর্ণ বাস্তবায়ন পাওয়ার আগে দেখা হত seen


3

এবং এখানে @ রিক -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



3

স্কালায় লাইব্রেরি রয়েছে 'স্কেলা.রেফ্লেট.আইও' যা পরীক্ষামূলক বলে বিবেচিত কিন্তু কাজটি করে

import scala.reflect.io.Path
Path(path) walkFilter { p => 
  p.isDirectory || """a*.foo""".r.findFirstIn(p.name).isDefined
}

3

আমি ব্যক্তিগতভাবে @ রেক্স কেরের প্রস্তাবিত সমাধানের কমনীয়তা এবং সরলতা পছন্দ করি। তবে এখানে একটি লেজ পুনরাবৃত্ত সংস্করণ দেখতে পারে:

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)
}

ওভারফ্লো সম্পর্কে কি?
norisknofun

1

এখানে রেক্স কেরারের অনুরূপ সমাধান, তবে একটি ফাইল ফিল্টার অন্তর্ভুক্ত করা হয়েছে:

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 )

1

সর্বাধিক সহজ স্কেলা-সমাধান (যদি আপনি স্কালা সংকলক লাইব্রেরির প্রয়োজন মনে করেন না):

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")

1

দেখে মনে হচ্ছে কেউ 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


0

এই প্রসারণটি আমার পক্ষে কাজ করে:

  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]())(_ ++ _)
    }
  }

0

আপনি এর জন্য লেজ পুনরাবৃত্তি ব্যবহার করতে পারেন:

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))
  }
}

-1

আপনি স্কালার অ্যাবস্ট্রাকফাইলের পরিবর্তে জাভা ফাইলটি ব্যবহার করছেন কেন?

স্কালার অ্যাবস্ট্রাকফাইলে, পুনরুক্তি সমর্থন জেমস মুরের সমাধানটির আরও সংক্ষিপ্ত সংস্করণ লেখার অনুমতি দেয়:

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)
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.