如何在hadoop的新目录中解压缩.gz文件?

时间:2016-01-03 04:18:20

标签: hadoop hdfs gz

我在hdfs的文件夹中有一堆.gz文件。我想将所有这些.gz文件解压缩到hdfs中的新文件夹。我该怎么做?

6 个答案:

答案 0 :(得分:27)

我可以想到通过三种不同的方式实现它。

  1. 使用Linux命令行

    以下命令对我有用。

    hadoop fs -cat /tmp/Links.txt.gz | gzip -d | hadoop fs -put - /tmp/unzipped/Links.txt
    

    我的gzip压缩文件是Links.txt.gz
    输出存储在/tmp/unzipped/Links.txt

  2. 使用Java程序

    Hadoop The Definitve Guide一书中,有Codecs部分。在该部分中,有一个程序使用CompressionCodecFactory解压缩输出。我正在重新生成该代码:

    package com.myorg.hadooptests;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;
    import org.apache.hadoop.io.compress.CompressionCodec;
    import org.apache.hadoop.io.compress.CompressionCodecFactory;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.URI;
    
    public class FileDecompressor {
        public static void main(String[] args) throws Exception {
            String uri = args[0];
            Configuration conf = new Configuration();
            FileSystem fs = FileSystem.get(URI.create(uri), conf);
            Path inputPath = new Path(uri);
            CompressionCodecFactory factory = new CompressionCodecFactory(conf);
            CompressionCodec codec = factory.getCodec(inputPath);
            if (codec == null) {
                System.err.println("No codec found for " + uri);
                System.exit(1);
            }
            String outputUri =
            CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
            InputStream in = null;
            OutputStream out = null;
            try {
                in = codec.createInputStream(fs.open(inputPath));
                out = fs.create(new Path(outputUri));
                IOUtils.copyBytes(in, out, conf);
            } finally {
                IOUtils.closeStream(in);
                IOUtils.closeStream(out);
            }
        }
    }
    

    此代码将gz文件路径作为输入。
    您可以执行以下操作:

    FileDecompressor <gzipped file name>
    

    例如当我执行我的gzip压缩文件时:

    FileDecompressor /tmp/Links.txt.gz
    

    我在位置/tmp/Links.txt

    获得了解压缩文件

    它将解压缩的文件存储在同一文件夹中。因此,您需要修改此代码以获取2个输入参数:<input file path> and <output folder>

    一旦你使这个程序工作,你可以编写一个Shell / Perl / Python脚本来为你拥有的每个输入调用这个程序。

  3. 使用Pig脚本

    您可以编写一个简单的Pig脚本来实现此目的。

    我编写了以下脚本,该脚本有效:

    A = LOAD '/tmp/Links.txt.gz' USING PigStorage();
    Store A into '/tmp/tmp_unzipped/' USING PigStorage();
    mv /tmp/tmp_unzipped/part-m-00000 /tmp/unzipped/Links.txt
    rm /tmp/tmp_unzipped/
    

    运行此脚本时,解压缩的内容将存储在临时文件夹中:/tmp/tmp_unzipped。该文件夹将包含

    /tmp/tmp_unzipped/_SUCCESS
    /tmp/tmp_unzipped/part-m-00000
    

    part-m-00000包含解压缩文件。

    因此,我们需要使用以下命令显式重命名它,最后删除/tmp/tmp_unzipped文件夹:

    mv /tmp/tmp_unzipped/part-m-00000 /tmp/unzipped/Links.txt
    rm /tmp/tmp_unzipped/
    

    因此,如果您使用此Pig脚本,则只需要注意参数化文件名(Links.txt.gz和Links.txt)。

    同样,一旦你使这个脚本工作,你可以编写一个Shell / Perl / Python脚本来为你拥有的每个输入调用这个Pig脚本。

答案 1 :(得分:5)

Bash解决方案

在我的情况下,我不想管道解压缩文件,因为我不确定它们的内容。相反,我想确保将zip文件中的所有文件都提取到HDFS上。

我创建了一个简单的bash脚本。评论应该让你知道发生了什么。下面有一个简短的描述。

#!/bin/bash

workdir=/tmp/unziphdfs/
cd $workdir

# get all zip files in a folder
zips=$(hadoop fs -ls /yourpath/*.zip | awk '{print $8}')
for hdfsfile in $zips
do
    echo $hdfsfile

    # copy to temp folder to unpack
    hdfs dfs -copyToLocal $hdfsfile $workdir

    hdfsdir=$(dirname "$hdfsfile")
    zipname=$(basename "$hdfsfile")

    # unpack locally and remove
    unzip $zipname
    rm -rf $zipname

    # copy files back to hdfs
    files=$(ls $workdir)
    for file in $files; do
       hdfs dfs -copyFromLocal $file $hdfsdir
       rm -rf $file
    done

    # optionally remove the zip file from hdfs?
    # hadoop fs -rm -skipTrash $hdfsfile
done

描述

  1. 获取*.zip目录
  2. 中的所有hdfs个文件
  3. 逐个:将zip复制到临时目录(在文件系统上)
  4. 解压
  5. 将所有解压缩的文件复制到zip文件的目录
  6. 清理
  7. 我设法使用/mypath/*/*.zip使用sub-dir结构处理每个zip文件。

    祝你好运:)

答案 2 :(得分:3)

如果您有压缩文本文件,hadoop fs -text支持gzip以及其他常见压缩格式(snappy,lzo)。

hadoop fs -text /tmp/a.gz | hadoop fs -put - /tmp/uncompressed_a

答案 3 :(得分:2)

您可以使用配置单元(假设它是文本数据)来执行此操作。

create external table source (t str) location '<directory_with_gz_files>';
create external table target (t str) location '<target_dir>';
insert into table target select * from source;

数据将被解压缩为新的文件集。

如果您不想更改名称,并且在运行的节点上有足够的存储空间,则可以执行此操作。

hadoop fs -get <your_source_directory> <directory_name>
It will create a directory where you run hadoop command. cd to it and gunzip all the files
cd ..
hadoop fs -moveFromLocal <directory_name> <target_hdfs_path>

答案 4 :(得分:0)

提供Scala代码

import org.apache.hadoop.fs.{FSDataOutputStream, FileSystem, FileUtil, Path}
import org.apache.hadoop.io.compress.{CompressionCodecFactory, CompressionInputStream}
import org.apache.spark.sql.SparkSession
import org.apache.hadoop.io.IOUtils
 val conf = new org.apache.hadoop.conf.Configuration()


 def extractFile (sparkSession: SparkSession, compath : String, uncompPath :String): String = {
         val fs = FileSystem.get(sparkSession.sparkContext.hadoopConfiguration)
         val inputPath  = new Path(compath)
         val factory = new CompressionCodecFactory(sparkSession.sparkContext.hadoopConfiguration);
       val codec = factory.getCodec(inputPath)
         if (codec == null){
           throw new RuntimeException(s"Not a valid codex $codec")
         }
    
         var in : CompressionInputStream = null;
         var out : FSDataOutputStream = null;
         try {
            in = codec.createInputStream(fs.open(inputPath));
            out = fs.create(new Path(uncompPath));
           IOUtils.copyBytes(in, out, conf);
         } finally {
           IOUtils.closeStream(in);
           IOUtils.closeStream(out);
         }
         uncompPath
       }

答案 5 :(得分:-1)

Hadoop的FileUtil课程有unTar()unZip()个方法来实现这一目标。 unTar()方法也适用于.tar.gz.tgz文件。不幸的是,他们只处理本地文件系统上的文件。您必须使用相同类的copy()方法之一来复制到您需要使用的任何分布式文件系统中。