### 2.5 python操作hdfs

#### 2.5.1 安装python3

**由于系统默认安装的是python2.7，需要安装python3环境**

- 源码编译安装python3.6.0

  - 安装一些依赖库

    ```
    sudo yum install openssl
    sudo yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel 
    ```

  - 1，下载Python安装包

    ```
    cd /usr/local/src
    wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tgz
    ```

  - 2，解压

    `tar -zxvf Python-3.6.0.tgz`

  - 3，进入解压目录

    `cd Python-3.6.0`

  - 4，编译安装包

    ```
    ./configure --prefix=/usr/local/python3
    make && make install
    ```

  - 5，添加环境变量

    ```
    echo PATH='/usr/local/python3/bin/:$PATH' >> /etc/profile
    source /etc/profile
    ```

  - 6，检查是否安装成功

    ```
    python3.6
    
    Python 3.6.0 (default, Jun  1 2017, 14:01:43) 
    [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> print('hello')
    hello word
    ```

#### 2.5.2 利用python代码实现hdfs的文件操作

- 1，安装hdfs

  pip3 install hdfs

- 2，连接hdfs

  ```python
  from hdfs.client import Client
  # 50070: NameNode web管理端口
  client = Client("http://主机名:50070")  
  client.list("/")  #列出所有hdfs目录
  ```

- 3，status —获取路径的具体信息
  其他参数：status(hdfs_path, strict=True)

  hdfs_path：就是hdfs路径

  strict：设置为True时，如果hdfs_path路径不存在就会抛出异常，如果设置为False，如果路径为不存在，则返回None

- 4，list —获取指定路径的子目录信息

  其他参数：list(hdfs_path, status=False)

  status：为True时，也返回子目录的状态信息，默认为Flase

- 5，makedirs —创建目录

  client.makedirs("/test")

  其他参数：makedirs(hdfs_path, permission=None)

  permission：设置权限

  client.makedirs("/test",permission=777)

- 6，rename —重命名
  格式说明：rename(hdfs_path, local_path）

- 7，delete —删除
  其他参数：delete(hdfs_path, recursive=False) 
  recursive：删除文件和其子目录，设置为False如果不存在，则会抛出异常，默认为False

- 8，upload —上传数据

  client.upload("/test","/opt/bigdata/hadoop/NOTICE.txt")

  其他参数：upload(hdfs_path, local_path, overwrite=False, n_threads=1, temp_dir=None, 
  chunk_size=65536,progress=None, cleanup=True, **kwargs)

  overwrite：是否是覆盖性上传文件
  n_threads：启动的线程数目
  temp_dir：当overwrite=true时，远程文件一旦存在，则会在上传完之后进行交换
  chunk_size：文件上传的大小区间
  progress：回调函数来跟踪进度，为每一chunk_size字节。它将传递两个参数，文件上传的路径和传输的字节数。一旦完成，-1将作为第二个参数
  cleanup：如果在上传任何文件时发生错误，则删除该文件

- 9，download —下载

  其他参数：download(hdfs_path, local_path, overwrite=False, n_threads=1, temp_dir=None, **kwargs) 
  参考上传 upload

- 10，read—读取文件

  with client.read("/test/a.txt") as reader:  
  ​    print reader.read()

  其他参数：read(*args, **kwds)

  hdfs_path：hdfs路径
  offset：设置开始的字节位置
  length：读取的长度（字节为单位）
  buffer_size：用于传输数据的字节的缓冲区的大小。默认值设置在HDFS配置。
  encoding：制定编码
  chunk_size：如果设置为正数，上下文管理器将返回一个发生器产生的每一chunk_size字节而不是一个类似文件的对象
  delimiter：如果设置，上下文管理器将返回一个发生器产生每次遇到分隔符。此参数要求指定的编码。
  progress：回调函数来跟踪进度，为每一chunk_size字节（不可用，如果块大小不是指定）。它将传递两个参数，文件上传的路径和传输的字节数。称为一次与- 1作为第二个参数。

- 11，write –写入

  client.write(filepath, data=data_str, encoding='utf-8')

  ·注：**在对文件操作时，可能会提示错误**

  hdfs.util.HdfsError: Permission denied: user=dr.who, access=WRITE, inode="/test":root:supergroup:drwxr-xr-x 

  解决办法是：在配置文件hdfs-site.xml中加入

  ```
  <property> 
  	<name>dfs.permissions</name> 
  	<value>false</value> 
  </property>
  ```

  安全模式导致错误：

  hdfs.util.HdfsError: Cannot create directory xxx. Name node is in safe mode

  关闭安全模式：

  hadoop dfsadmin -safemode leave