【问题标题】:How to unzip .gz files in a new directory in hadoop?如何在hadoop的新目录中解压缩.gz文件?
【发布时间】:2016-04-07 00:15:31
【问题描述】:

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

【问题讨论】:

标签: hadoop hdfs gzip


【解决方案1】:

我可以考虑通过 3 种不同的方式来实现它。

  1. 使用 Linux 命令行

    以下命令对我有用。

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

    我的压缩文件是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个输入参数:&lt;input file path&gt; and &lt;output folder&gt;

    一旦你让这个程序运行起来,你可以编写一个 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 脚本。

【讨论】:

  • 在 java 代码中出现错误“找不到 {Path} 的编解码器”。有什么建议吗?我检查了文件的路径是否正确。在编解码器中仍然分配了 null
  • 包“org.apache.hadoop.io.compress”是“hadoop-common-.jar”的一部分。这个 jar 存在于“$HADOOP_HOME/share/hadoop/common”中。检查您的类路径是否设置正确。例如检查“HADOOP_COMMON_HOME”是否设置为正确的路径。它应该可以工作。
  • 同样的错误。我也加了这个罐子。 & HADOOP_COMMON_HOME 也是正确的
  • ".zip" 文件。我的文件名是这样的“positions_2012-02-14.dat.zip”只有一个文件在zip“positions_2012-02-14.dat”中
  • 我强烈建议不要使用选项 #1,除非您在节点本身上运行它。总网络使用量将是文件压缩和解压缩大小的总和。
【解决方案2】:

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. 获取hdfs 目录中的所有*.zip 文件
  2. 一个接一个:将zip 复制到一个临时目录(在文件系统上)
  3. 解压
  4. 将所有解压文件复制到压缩包目录
  5. 清理

我设法让它使用/mypath/*/*.zip 为每个压缩文件中的许多 zip 文件使用子目录结构。

祝你好运:)

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      您可以使用 hive 执行此操作(假设它是文本数据)。

      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>
      

      【讨论】:

      • 我喜欢这种方法。如果 只有一个 .gz 文件,这种方法是否使用多个映射器? IE。它是并行gunzip,还是单线程操作? Afaik,gz 不可拆分。谢谢。
      • 如果您的默认格式不是文本(例如 orc),请记住将 STORED AS TEXTFILE 添加到源表定义中。
      【解决方案5】:

      提供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
             }
      

      【讨论】:

        【解决方案6】:

        Hadoop 的FileUtil 类有unTar()unZip() 方法来实现这一点。 unTar() 方法也适用于 .tar.gz.tgz 文件。不幸的是,它们仅适用于本地文件系统上的文件。您必须使用同一类的 copy() 方法之一来复制到您需要使用的任何分布式文件系统。

        【讨论】:

        • 如何从 HDFS 位置读取 zip 文件并将其解压缩到另一个 HDFS 位置
        猜你喜欢
        • 1970-01-01
        • 2022-11-21
        • 2011-03-18
        • 2015-09-10
        • 2010-09-15
        • 1970-01-01
        • 1970-01-01
        • 2021-12-26
        相关资源
        最近更新 更多