it-swarm.com.de

Wie listet man alle Dateien in einem Verzeichnis und dessen Unterverzeichnisse in hadoop hdfs auf

Ich habe einen Ordner in hdfs, der zwei Unterordner hat, von denen jeder über 30 Unterordner verfügt, die schließlich xml-Dateien enthalten. Ich möchte alle xml-Dateien auflisten, die nur den Pfad des Hauptordners angeben dies mit Apache commons-ios FileUtils.listFiles () . Ich habe dies versucht

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

aber es werden nur die beiden ersten Unterordner aufgelistet und es geht nicht weiter ... Gibt es eine Möglichkeit, dies in hadoop zu tun?

18
nik686

Sie müssen das FileSystem - Objekt verwenden und eine Logik für die resultierenden FileStatus-Objekte ausführen, um manuell in die Unterverzeichnisse zu rekursieren.

Sie können einen PathFilter auch anwenden, um die XML-Dateien nur mit der Methode listStatus (Path, PathFilter) zurückzugeben

Die hadoop-Klasse FsShell enthält Beispiele für den Befehl hadoop fs -lsr. Hierbei handelt es sich um ein rekursives ls - siehe the source in Zeile 590 (der rekursive Schritt wird in Zeile 635 ausgelöst).

16
Chris White

Wenn Sie hadoop 2 verwenden. * API gibt es elegantere Lösungen:

    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());
    }
26
Prasoon Joshi

Hast du das probiert:

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");
        }
    }
}
13
ali haider
/**
 * @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;
}

Kurzbeispiel: Angenommen, Sie haben die folgende Dateistruktur:

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

Mit dem obigen Code erhalten Sie:

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

Wenn Sie nur das Blatt (d. H. Dateiname) möchten, verwenden Sie den folgenden Code im else-Block:

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

Dies wird geben:

b
d
e
f
9
Amit Kumar

Jetzt kann man mit Spark dasselbe und schneller machen als andere Ansätze (z. B. Hadoop MR). Hier ist das Code-Snippet.

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)
                }
            }
    }   
}
2
Nikhil Bhide

Hier ist ein Code-Snippet, der die Anzahl der Dateien in einem bestimmten HDFS-Verzeichnis zählt (ich habe hiermit ermittelt, wie viele Reduzierungen in einem bestimmten ETL-Code verwendet werden sollen). Sie können dies leicht an Ihre Bedürfnisse anpassen.

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;
}
1
Marcin

Code-Snippet für rekursive und nichtrekursive Ansätze:

//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
0
CavaJ

verwenden Sie keinen rekursiven Ansatz (Heap-Probleme):) Verwenden Sie eine Warteschlange

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
}

das war einfach, viel Spaß! 

Vielen Dank an Radu Adrian Moldovan für den Vorschlag.

Hier ist eine Implementierung mit Queue:

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
Amit Kumar