如何从pyspark中的hdfs获取目录的文件名列表?

时间:2017-10-04 13:21:03

标签: file path directory pyspark hdfs

我在hdfs中有一个包含许多文件的目录。我知道目录的路径,我正在尝试获取目录包含的那些文件名列表。我怎么能这样做?

如果我有一个目录如下:

+dir/
    +f1
    +f2
    +fN

我想得到如下列表:

[f1, f2, fN]

4 个答案:

答案 0 :(得分:3)

您可以在pyspark中使用HDFS(或任何其他兼容的Hadoop文件系统)API,并使用一点py4j魔法。要列出特定目录中的文件,请使用:

path = "/here/is/my/dir/"
fs = spark._jvm.org.apache.hadoop.fs.FileSystem.get(spark._jsc.hadoopConfiguration())
list_status = fs.listStatus(spark._jvm.org.apache.hadoop.fs.Path(path))
result = [file.getPath().getName() for file in list_status]

list_status集合的元素属于FileSystem类型。使用此API,您可以获取文件元数据,例如信息,如果它是目录,模式,所有者,组,acls,并使用这些信息来过滤掉不需要的文件。

答案 1 :(得分:1)

Pyspark中没有这方面的功能(编辑:最后请参阅Mariusz和UPDATE的回答) - 此功能在Python包pywebhdfs中提供(只需安装{ {1}}):

pip install pywebhdfs

结果是一个(相当长的)Python字典(未显示) - 尝试一点以获得感觉。您可以解析它以获取名称和类型(文件/目录),如下所示:

from pywebhdfs.webhdfs import PyWebHdfsClient
from pprint import pprint

hdfs = PyWebHdfsClient(host='192.10.10.73',port='50070', user_name='ctsats')  # your Namenode IP & username here
my_dir = 'user/ctsats'
pprint(hdfs.list_dir(my_dir))

从这里开始,一个简单的列表理解应该可以完成这项工作 - 例如,在我的情况下,我有两个文件和一个文件。目录存在,这是我如何只保留目录:

data = hdfs.list_dir(my_dir)
dd = [[x["pathSuffix"], x["type"]] for x in data["FileStatuses"]["FileStatus"]]
dd
# [[u'.Trash', u'DIRECTORY'], [u'.sparkStaging', u'DIRECTORY'], [u'checkpoint', u'DIRECTORY'], [u'datathon', u'DIRECTORY'], [u'ms-spark', u'DIRECTORY'], [u'projects', u'DIRECTORY'], [u'recsys', u'DIRECTORY'], [u'sparklyr', u'DIRECTORY'], [u'test.data', u'FILE'], [u'word2vec', u'DIRECTORY']]

为了比较,这里是同一目录的实际列表:

sub_dirs = [x[0] for x in dd if x[1]=='DIRECTORY']
sub_dirs
# [u'.Trash', u'.sparkStaging', u'checkpoint', u'datathon', u'ms-spark', u'projects', u'recsys', u'sparklyr', u'word2vec']

必须启用Hadoop群集中的WebHDFS服务,即您的[ctsats@dev-hd-01 ~]$ hadoop fs -ls Found 10 items drwx------ - ctsats supergroup 0 2016-06-08 13:31 .Trash drwxr-xr-x - ctsats supergroup 0 2016-12-15 20:18 .sparkStaging drwxr-xr-x - ctsats supergroup 0 2016-06-23 13:23 checkpoint drwxr-xr-x - ctsats supergroup 0 2016-02-03 15:40 datathon drwxr-xr-x - ctsats supergroup 0 2016-04-25 10:56 ms-spark drwxr-xr-x - ctsats supergroup 0 2016-06-30 15:51 projects drwxr-xr-x - ctsats supergroup 0 2016-04-14 18:55 recsys drwxr-xr-x - ctsats supergroup 0 2016-11-07 12:46 sparklyr -rw-r--r-- 3 ctsats supergroup 90 2016-02-03 16:55 test.data drwxr-xr-x - ctsats supergroup 0 2016-12-15 20:18 word2vec 文件必须包含以下条目:

hdfs-site.xml

更新(在Mariusz回答之后):以下是Mariusz对Spark 1.6的回答(您需要在我的示例中将<property> <name>dfs.webhdfs.enabled</name> <value>true</value> </property> 替换为spark):

sc

这里的问题是返回文件和子文件夹,而没有任何区分它们的方法。正如所示,path="/user/ctsats" fs = sc._jvm.org.apache.hadoop.fs.FileSystem.get(sc._jsc.hadoopConfiguration()) list_status = fs.listStatus(sc._jvm.org.apache.hadoop.fs.Path(path)) result = [file.getPath().getName() for file in list_status] result # [u'.Trash', u'.sparkStaging', u'checkpoint', u'datathon', u'ms-spark', u'projects', u'recsys', u'sparklyr', u'test.data', u'word2vec'] 解决方案不会受此影响......

我想有办法克服这个问题,但你必须深入研究py4j API - 尽管有欺骗性的外观,pywebhdfs 不是 Python列表:

list_status

答案 2 :(得分:1)

list_status不需要是Python列表。它显然是一个迭代器,这就是你所需要的。如果你真的想要一个python列表,很容易做一个:

pythonlist = list(list_status)

Other than that, you can filter out the files, and omit the directories:

result = [file.getPath().getName() for file in list_status if file.isFile()]

埃弗特

答案 3 :(得分:0)

使用子进程库的python 3:

from subprocess import Popen, PIPE
hdfs_path = '/path/to/the/designated/folder'
process = Popen(f'hdfs dfs -ls -h {hdfs_path}', shell=True, stdout=PIPE, stderr=PIPE)
std_out, std_err = process.communicate()
list_of_file_names = [fn.split(' ')[-1].split('/')[-1] for fn in std_out.decode().readlines()[1:]][:-1]
list_of_file_names_with_full_address = [fn.split(' ')[-1] for fn in std_out.decode().readlines()[1:]][:-1]