2012-07-05 14 views
15

में निर्देशिका में इसकी सभी निर्देशिकाओं और इसकी उपनिर्देशिकाओं को कैसे सूचीबद्ध करें मेरे पास एचडीएफएस में एक फ़ोल्डर है जिसमें दो उपफोल्डर्स हैं जिनमें से प्रत्येक के पास लगभग 30 उपफोल्डर्स हैं, अंततः, प्रत्येक में xml फ़ाइलें होती हैं। मैं केवल सभी मुख्य फ़ोल्डर के पथ देने वाली सभी एक्सएमएल फाइलों को सूचीबद्ध करना चाहता हूं। स्थानीय रूप से मैं इसे apache commons-io's FileUtils.listFiles() के साथ कर सकता हूं। मैं इसहैडऑप एचडीएफएस

FileStatus[] status = fs.listStatus(new Path(args[ 0 ])); 

की कोशिश की है, लेकिन यह केवल दो पहले सबफ़ोल्डर सूचीबद्ध करता है और यह आगे जाना नहीं है। क्या हैडूप में ऐसा करने का कोई तरीका है?

उत्तर

14

आप FileSystem वस्तु का उपयोग करें और मैन्युअल रूप से निदेशिकाओं में recurse करने परिणामी FileStatus वस्तुओं पर कुछ तर्क प्रदर्शन करने के लिए की आवश्यकता होगी।

तुम भी केवल listStatus(Path, PathFilter) विधि

Hadoop FsShell वर्ग Hadoop FS -lsr आदेश है, जो एक पुनरावर्ती ls है के लिए इस बात का उदाहरण है का उपयोग कर xml फ़ाइलें वापस जाने के लिए एक PathFilter आवेदन कर सकते हैं - the source देखते हैं, चारों ओर लाइन 5 9 0 (रिकर्सिव चरण लाइन 635 पर ट्रिगर किया गया है)

+0

से अंतिम फ़ाइलों में शामिल होने के लिए अंततः मैंने आपके सुझाव के मुकाबले एक सरल कार्यान्वयन किया लेकिन आपने मुझे विचार दिया। तनक्स !!! – nik686

+3

टूटी हुई संदर्भ लिंक – AkD

12

आप इस प्रयास किया है:

import java.io.*; 
import java.util.*; 
import java.net.*; 
import org.apache.hadoop.fs.*; 
import org.apache.hadoop.conf.*; 
import org.apache.hadoop.io.*; 
import org.apache.hadoop.mapred.*; 
import org.apache.hadoop.util.*; 

public class cat{ 
    public static void main (String [] args) throws Exception{ 
     try{ 
      FileSystem fs = FileSystem.get(new Configuration()); 
      FileStatus[] status = fs.listStatus(new Path("hdfs://test.com:9000/user/test/in")); // you need to pass in your hdfs path 

      for (int i=0;i<status.length;i++){ 
       BufferedReader br=new BufferedReader(new InputStreamReader(fs.open(status[i].getPath()))); 
       String line; 
       line=br.readLine(); 
       while (line != null){ 
        System.out.println(line); 
        line=br.readLine(); 
       } 
      } 
     }catch(Exception e){ 
      System.out.println("File not found"); 
     } 
    } 
} 
+0

हाँ मैं एक ही उदाहरण के लिए, मैं के लिए भेजा इस above.But करने में सूचीबद्ध करता है गहराई 1.I में उपनिर्देशिका चाहते ve देखा है मुख्य फ़ोल्डर – nik686

1

यहां एक कोड स्निपेट है, जो किसी विशेष एचडीएफएस निर्देशिका में फ़ाइलों की संख्या की गणना करता है (मैंने यह निर्धारित करने के लिए उपयोग किया कि किसी विशेष ईटीएल कोड में कितने रेड्यूसर का उपयोग करना है)। आप अपनी जरूरतों को पूरा करने के लिए इसे आसानी से संशोधित कर सकते हैं।

private int calculateNumberOfReducers(String input) throws IOException { 
    int numberOfReducers = 0; 
    Path inputPath = new Path(input); 
    FileSystem fs = inputPath.getFileSystem(getConf()); 
    FileStatus[] statuses = fs.globStatus(inputPath); 
    for(FileStatus status: statuses) { 
     if(status.isDirectory()) { 
      numberOfReducers += getNumberOfInputFiles(status, fs); 
     } else if(status.isFile()) { 
      numberOfReducers ++; 
     } 
    } 
    return numberOfReducers; 
} 

/** 
* Recursively determines number of input files in an HDFS directory 
* 
* @param status instance of FileStatus 
* @param fs instance of FileSystem 
* @return number of input files within particular HDFS directory 
* @throws IOException 
*/ 
private int getNumberOfInputFiles(FileStatus status, FileSystem fs) throws IOException { 
    int inputFileCount = 0; 
    if(status.isDirectory()) { 
     FileStatus[] files = fs.listStatus(status.getPath()); 
     for(FileStatus file: files) { 
      inputFileCount += getNumberOfInputFiles(file, fs); 
     } 
    } else { 
     inputFileCount ++; 
    } 

    return inputFileCount; 
} 
19

आप Hadoop 2. * एपीआई का उपयोग कर रहे हैं, तो और अधिक सुरुचिपूर्ण समाधान देखते हैं:

Configuration conf = getConf(); 
    Job job = Job.getInstance(conf); 
    FileSystem fs = FileSystem.get(conf); 

    //the second boolean parameter here sets the recursion to true 
    RemoteIterator<LocatedFileStatus> fileStatusListIterator = fs.listFiles(
      new Path("path/to/lib"), true); 
    while(fileStatusListIterator.hasNext()){ 
     LocatedFileStatus fileStatus = fileStatusListIterator.next(); 
     //do stuff with the file like ... 
     job.addFileToClassPath(fileStatus.getPath()); 
    } 
+1

getConf() विधि क्या है? –

+0

'getConf()' 'कॉन्फ़िगर किए गए 'वर्ग में एक विधि है। आपकी कक्षा आदर्श रूप से इसका विस्तार करेगी। –

6
/** 
* @param filePath 
* @param fs 
* @return list of absolute file path present in given path 
* @throws FileNotFoundException 
* @throws IOException 
*/ 
public static List<String> getAllFilePath(Path filePath, FileSystem fs) throws FileNotFoundException, IOException { 
    List<String> fileList = new ArrayList<String>(); 
    FileStatus[] fileStatus = fs.listStatus(filePath); 
    for (FileStatus fileStat : fileStatus) { 
     if (fileStat.isDirectory()) { 
      fileList.addAll(getAllFilePath(fileStat.getPath(), fs)); 
     } else { 
      fileList.add(fileStat.getPath().toString()); 
     } 
    } 
    return fileList; 
} 

त्वरित उदाहरण: मान लीजिए आप निम्न फ़ाइल संरचना है:

a -> b 
    -> c -> d 
      -> e 
    -> d -> f 

उपरोक्त कोड का उपयोग करके, आपको मिलता है:

a/b 
a/c/d 
a/c/e 
a/d/f 

यदि आप केवल पत्ता चाहते हैं (यानी। फ़ाइल नाम), else ब्लॉक में निम्न कोड का उपयोग करें:

... 
    } else { 
     String fileName = fileStat.getPath().toString(); 
     fileList.add(fileName.substring(fileName.lastIndexOf("/") + 1)); 
    } 

इस दे देंगे:

b 
d 
e 
f 
0

पुनरावर्ती दृष्टिकोण (ढेर मुद्दों) :) का उपयोग नहीं करते एक कतार का उपयोग

queue.add(param_dir) 
while (queue is not empty){ 

    directory= queue.pop 
- get items from current directory 
- if item is file add to a list (final list) 
- if item is directory => queue.push 
} 

जो आसान था, आनंद लें!

0

सुझाव के लिए धन्यवाद राडू एड्रियन मोल्दोवन।

private static List<String> listAllFilePath(Path hdfsFilePath, FileSystem fs) 
throws FileNotFoundException, IOException { 
    List<String> filePathList = new ArrayList<String>(); 
    Queue<Path> fileQueue = new LinkedList<Path>(); 
    fileQueue.add(hdfsFilePath); 
    while (!fileQueue.isEmpty()) { 
    Path filePath = fileQueue.remove(); 
    if (fs.isFile(filePath)) { 
     filePathList.add(filePath.toString()); 
    } else { 
     FileStatus[] fileStatus = fs.listStatus(filePath); 
     for (FileStatus fileStat : fileStatus) { 
     fileQueue.add(fileStat.getPath()); 
     } 
    } 
    } 
    return filePathList; 
} 
0

अब, एक तेजी से अन्य तरीकों की तुलना में (जैसे Hadoop एमआर के रूप में) एक ही है और अपनी तरह से करने के लिए स्पार्क का उपयोग कर सकते हैं:

यहाँ एक कार्यान्वयन का उपयोग कतार है। कोड स्निपेट यहाँ है।दोनों पुनरावर्ती और गैर पुनरावर्ती दृष्टिकोण के लिए

def traverseDirectory(filePath:String,recursiveTraverse:Boolean,filePaths:ListBuffer[String]) { 
    val files = FileSystem.get(sparkContext.hadoopConfiguration).listStatus(new Path(filePath)) 
      files.foreach { fileStatus => { 
       if(!fileStatus.isDirectory() && fileStatus.getPath().getName().endsWith(".xml")) {     
        filePaths+=fileStatus.getPath().toString()  
       } 
       else if(fileStatus.isDirectory()) { 
        traverseDirectory(fileStatus.getPath().toString(), recursiveTraverse, filePaths) 
       } 
      } 
    } 
} 
0

कोड स्निपेट:

//helper method to get the list of files from the HDFS path 
public static List<String> 
    listFilesFromHDFSPath(Configuration hadoopConfiguration, 
          String hdfsPath, 
          boolean recursive) throws IOException, 
             IllegalArgumentException 
{ 
    //resulting list of files 
    List<String> filePaths = new ArrayList<String>(); 

    //get path from string and then the filesystem 
    Path path = new Path(hdfsPath); //throws IllegalArgumentException 
    FileSystem fs = path.getFileSystem(hadoopConfiguration); 

    //if recursive approach is requested 
    if(recursive) 
    { 
     //(heap issues with recursive approach) => using a queue 
     Queue<Path> fileQueue = new LinkedList<Path>(); 

     //add the obtained path to the queue 
     fileQueue.add(path); 

     //while the fileQueue is not empty 
     while (!fileQueue.isEmpty()) 
     { 
      //get the file path from queue 
      Path filePath = fileQueue.remove(); 

      //filePath refers to a file 
      if (fs.isFile(filePath)) 
      { 
       filePaths.add(filePath.toString()); 
      } 
      else //else filePath refers to a directory 
      { 
       //list paths in the directory and add to the queue 
       FileStatus[] fileStatuses = fs.listStatus(filePath); 
       for (FileStatus fileStatus : fileStatuses) 
       { 
        fileQueue.add(fileStatus.getPath()); 
       } // for 
      } // else 

     } // while 

    } // if 
    else  //non-recursive approach => no heap overhead 
    { 
     //if the given hdfsPath is actually directory 
     if(fs.isDirectory(path)) 
     { 
      FileStatus[] fileStatuses = fs.listStatus(path); 

      //loop all file statuses 
      for(FileStatus fileStatus : fileStatuses) 
      { 
       //if the given status is a file, then update the resulting list 
       if(fileStatus.isFile()) 
        filePaths.add(fileStatus.getPath().toString()); 
      } // for 
     } // if 
     else  //it is a file then 
     { 
      //return the one and only file path to the resulting list 
      filePaths.add(path.toString()); 
     } // else 

    } // else 

    //close filesystem; no more operations 
    fs.close(); 

    //return the resulting list 
    return filePaths; 
} // listFilesFromHDFSPath 
संबंधित मुद्दे