25

私はhdfsに2つのサブフォルダーを持つフォルダーを持っています。それぞれに約30のサブフォルダーがあり、最後に、それぞれにxmlファイルが含まれています。メインフォルダのパスのみを示すすべてのxmlファイルを一覧表示したいと思います。ローカルでは、apache commons-ioのFileUtils.listFiles()を使用してこれを行うことができます。私はこれを試しました

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

ただし、最初の2つのサブフォルダーのみがリストされており、それ以上は進みません。これをHadoopで行う方法はありますか?

4

9 に答える 9

33

Hadoop 2.* API を使用している場合は、より洗練されたソリューションがあります。

    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());
    }
于 2014-09-03T13:08:47.187 に答える
19

FileSystemオブジェクトを使用し、結果の FileStatus オブジェクトに対していくつかのロジックを実行して、サブディレクトリに手動で再帰する必要があります。

listStatus(Path, PathFilter)メソッドを使用して、PathFilter を適用して xml ファイルのみを返すこともできます。

hadoop FsShell クラスには、hadoop fs -lsr コマンドの例があり、これは再帰的な ls です。ソースの 590 行付近を参照してください (再帰ステップは 635 行でトリガーされます)。

于 2012-07-05T13:25:13.497 に答える
15
/**
 * @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

リーフ (つまり、fileNames) のみが必要な場合は、elseブロックで次のコードを使用します。

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

これにより、次のようになります。

b
d
e
f
于 2015-05-07T11:56:08.410 に答える
14

これを試しましたか:

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");
        }
    }
}
于 2012-07-05T10:32:04.380 に答える
1

これは、特定の HDFS ディレクトリ内のファイル数をカウントするコード スニペットです (これを使用して、特定の ETL コードで使用するレデューサーの数を決定しました)。これは、ニーズに合わせて簡単に変更できます。

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;
}
于 2014-07-08T17:43:15.363 に答える
1

再帰的なアプローチを使用しないでください (ヒープの問題) :) キューを使用します

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
}

それは簡単でした、楽しんでください!

于 2016-03-10T09:34:52.670 に答える
0

提案してくれたRadu Adrian Moldovanに感謝します。

キューを使用した実装は次のとおりです。

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;
}
于 2016-07-11T05:17:23.667 に答える