文章目錄
最近有一個需求,就是定時去統計,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()
了麼