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()了麼

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