Java,Scala - 使用代码统计hadoop中hdfs的文件大小以及文件夹大小

      最近有一个需求,就是定时去统计,hdfs上的文件的大小和行数,也就是统计这段时间内新增的数据的条数和占用空间。
      举个例子:一天24小时,每6个小时统计一次,这6个小时内,新增了多少条数据,以及这些数据在hdfs上占用了多少空间。
      

一些配置和前提说明

hadoop的一些说明

      在这里,假设hdfs上的文件没有任何压缩格式,且hdfs中的数据是整齐无缺损的,其中存在用来筛选的时间字段。
      举个例子:

1	159298900	15
2	159298900	45
3	159298901	12
.......

      这里的第一个字段和第三个字段不用管,第二个字段是表示数据的时间的,不过要注意,这个字段表示的是秒还是毫秒

代码的一些说明

      这里无论你是用java还是scala,都不影响。
      就我个人涉及到的知识面而言,无非就是java的FileSystem,以及spark的textFile。所以这个说明其实就是:如何用FileSystem或spark读取hdfs的数据。
      这个在这写太麻烦了,请看下面的链接:
      java 使用FileSystem读取hadoop文件
      使用spark读取hadoop文件的具体内容
      

pom.xml

<dependencies>
	<dependency>
	    <groupId>org.apache.hive</groupId>
	    <artifactId>hive-jdbc</artifactId>
	    <version>2.1.1</version>
	</dependency>
	
	<dependency>
	    <groupId>org.apache.hadoop</groupId>
	    <artifactId>hadoop-client</artifactId>
	    <version>3.0.0</version>
	</dependency>
	
	<dependency>
	    <groupId>org.apache.hadoop</groupId>
	    <artifactId>hadoop-common</artifactId>
	    <version>3.0.0</version>
	</dependency>
</dependencies>

获取行数

使用FileSystem获取文件行数

      这种方法的步骤是:读取hadoop文件,统计行数,没啥难度。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;

public class testNewFile {

    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
        FileSystem fs=FileSystem.get(
            new URI( "hdfs://192.168.153.129:9000"), new Configuration(), "root");
        FSDataInputStream in = fs.open(
        	new Path( "hdfs://192.168.153.129:9000/user/hive/warehouse/test.db/t1/dt=3/t1"));

        BufferedReader d = new BufferedReader(new InputStreamReader(in));
        long count = 0;
        String line;
        while ((line = d.readLine()) != null) {
            count += 1L;
        }
        System.out.println( count );
        d.close();
        in.close();
        fs.close();
    }
}

使用spark获取hdfs 文件的条数

      习惯用scala了,所以这里也用Scala了。


import org.apache.spark.{SparkConf, SparkContext}

/**
  * Created by admin on 2020/7/3.
  */
object test01 {

    def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setAppName("test").setMaster("local[*]")
        val sc = new SparkContext(conf)
        val hadoopRdd = sc.textFile(
            "hdfs://192.168.153.129:9000/user/hive/warehouse/test.db/t1/dt=3/t1"
        )
        println(hadoopRdd.count())

    }
}

获取大小

第一种解决办法:使用getBytes()

      这个其实也是最笨的一个方法,把每条数据读出来,然后value.getBytes().length,就可以获取到当前这一行数据的大小。
      具体代码如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;

public class test {

    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
        FileSystem fs=FileSystem.get(
            new URI( "hdfs://192.168.153.129:9000"), new Configuration(), "root");
        FSDataInputStream in = fs.open(
        	new Path( "hdfs://192.168.153.129:9000/user/hive/warehouse/test.db/t1/dt=3/t1"));

        BufferedReader d = new BufferedReader(new InputStreamReader(in));
        long count = 0;
        long store = 0;
        String line;
        while ((line = d.readLine()) != null) {
            count += 1L;
            store += line.getBytes().length;
        }
        System.out.println( count );
        System.out.println( store );
        d.close();
        in.close();
        fs.close();
    }
}

第二种解决办法:使用listStatus()

      hadoop的jar包里,有这么个api,可以获取一个路径下所有文件、文件夹的状态。这个状态,其中就包含了block的数量,以及文件大小。

简单的情况

      假设该文件夹下面全都是文件,没有文件夹套文件夹套文件的情况。
      代码如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

public class test {

    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
        FileSystem fs=FileSystem.get(
                new URI("hdfs://127.0.0.1:9000"), new Configuration(), "root");
        FileStatus[] in = fs.listStatus(new Path(
                "hdfs://127.0.0.1:9000/user/hive/warehouse/test.db/t1/dt=3"));
        System.out.println( in[0].getLen() );
        fs.close();
    }
}

      因为我知道我这一个文件夹底下只有一个文件,所以我in[0]就完事了。如果一个文件夹下面有N多文件,则需要循环遍历,且相加。

比较麻烦的情况

      这种方法虽然简单,但是最好文件夹下面就全是文件,不要文件夹下面还有文件夹,然后还有文件。也就是说,这种方法不太适合于文件夹下面还有文件夹的情况。
      不是说处理不了,而是如果变成了文件夹下面有N层的话,你就得像统计一个文件夹有多大那样写递归了…很麻烦。

        FileStatus[] in = fs.listStatus(
                new Path( "hdfs://192.168.153.129:9000/user/hive/warehouse/test.db/t1/dt=3"));
        System.out.println( in[0].getLen() );
        System.out.println( in[0].isDirectory() );
        System.out.println( in[0].isFile() );

      有 isDirectory()isFile()方法,递归也可以算出来,但是太麻烦了,想写自己写吧,我这里就不写了…

第三种解决办法:使用getContentSummary()

      上述的那种麻烦的情况,可以使用这种方法来解决。
      hadoop的jar包里,有这么个api,可以获取一个文件夹下,文件的数量,文件夹的数量,以及这个文件夹的大小。不过我只关心这个文件夹的大小,其他的不关心。
      代码如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.ContentSummary;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
 
public class test {
    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
        FileSystem fs=FileSystem.get(
                new URI("hdfs://192.168.153.129:9000"), new Configuration(), "root");
        ContentSummary in = fs.getContentSummary(new Path(
                "hdfs://192.168.153.129:9000/user/hive/warehouse/test.db/t1/dt=3"));
        System.out.println( in.getLength() );
        fs.close();
    }
}

      这样就可以直接获取文件夹的大小了,不用考虑递归什么的了。

额外说点hadoop fs -dus

      这个命令就是显示文件的大小。

[root@Sla2 ~]# hdfs dfs -dus /tmp/root/
dus: DEPRECATED: Please use 'du -s' instead.
4217122515  /tmp/root/

       hadoop fs -dus 的源码:

public static void dus(String src,Configuration conf) throws IOException {
	    Path srcPath = new Path(src);
	    FileSystem srcFs = srcPath.getFileSystem(conf);
	    FileStatus status[] = srcFs.globStatus(new Path(src));
	    if (status==null || status.length==0) {
	      throw new FileNotFoundException("Cannot access " + src + 
	          ": No such file or directory.");
	    }
	    for(int i=0; i<status.length; i++) {
	      long totalSize = srcFs.getContentSummary(status[i].getPath()).getLength();
	      String pathStr = status[i].getPath().toString();
	      System.out.println(("".equals(pathStr)?".":pathStr) + "\t" + totalSize);
	    }
	  }

       看到里面的getContentSummary()了么

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章