使用HDFS的Java接口对文件基本操作

##使用HDFS的Java接口进行文件的读写。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fsk8ZK9Q-1585232884001)(picture/1.png)]

FileSystem对象
要从Hadoop文件系统中读取文件,最简单的办法是使用java.net.URL对象打开数据流,从中获取数据。不过这种方法一般要使用FsUrlStreamHandlerFactory实例调用setURLStreamHandlerFactory()方法。不过每个Java虚拟机只能调用一次这个方法,所以如果其他第三方程序声明了这个对象,那我们将无法使用了。因为有时候我们不能在程序中设置URLStreamHandlerFactory实例,这个时候咱们就可以使用FileSystem API来打开一个输入流,进而对HDFS进行操作。

使用FileSystem,查看上传的文件。

public sattic void main(String[] args){
    URI uri = URI.create("hdfs://localhost:9000/user/tmp/test.txt");
    Configuration config = new Configuration();
    FileSystem fs = FileSystem.get(uri, config);
    InputStream in = null;
    try {
        in = fs.open(new Path(uri));
        IOUtils.copyBytes(in, System.out, 2048, false);
    } catch (Exception e) {
        IOUtils.closeStream(in);
    }
}

FileSystem是一个通用的文件系统API,FileSystem实例有下列几个静态工厂方法用来构造对象。

public static FileSystem get(Configuration conf)throws IOException

public static FileSystem get(URI uri,Configuration conf)throws IOException

public static FileSystem get(URI uri,Configuration conf,String user)throws IOException

Configuration对象封装了客户端或服务器的配置,通过设置配置文件读取类路径来实现(如:/etc/hadoop/core-site.xml)。

第一个方法返回的默认文件系统是在core-site.xml中指定的,如果没有指定,就使用默认的文件系统。
第二个方法使用给定的URI方案和权限来确定要使用的文件系统,如果给定URI中没有指定方案,则返回默认文件系统,
第三个方法作为给定用户来返回文件系统,这个在安全方面来说非常重要。

FSDataInputStream对象
实际上,FileSystem对象中的open()方法返回的就是FSDataInputStream对象,而不是标准的java.io类对象。这个类是继承了java.io.DataInputStream的一个特殊类,并支持随机访问,由此可以从流的任意位置读取数据。

在有了FileSystem实例之后,我们调用open()函数来获取文件的输入流。

public FSDataInputStream open(Path p)throws IOException
public abst\fract FSDataInputStream open(Path f,int bufferSize)throws IOException
第一个方法使用默认的缓冲区大小为4KB。

示例代码

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
public class FileSystemCat {
	public static void main(String[] args) throws Exception{
		URI uri = URI.create("hdfs://localhost:9000/user/tmp/test.txt");
    Configuration config = new Configuration();
    FileSystem fs = FileSystem.get(uri, config);
    InputStream in = null;
    try {
        in = fs.open(new Path(uri));
        IOUtils.copyBytes(in, System.out, 2048, false);
    } catch (Exception e) {
        IOUtils.closeStream(in);
    }
	}
}

##使用HDFSAPI上传文件至集群
FSDataOutputStream对象

Java中要将数据输出到终端,需要文件输出流,HDFS的JavaAPI中也有类似的对象。

FileSystem类有一系列新建文件的方法,最简单的方法是给准备新建的文件制定一个path对象,然后返回一个用于写入数据的输出流:

public FSDataOutputStream create(Path p)throws IOException

该方法有很多重载方法,允许我们指定是否需要强制覆盖现有文件,文件备份数量,写入文件时所用缓冲区大小,文件块大小以及文件权限。

注意:create()方法能够为需要写入且当前不存在的目录创建父目录,即就算传入的路径是不存在的,该方法也会为你创建一个目录,而不会报错。如果有时候我们并不希望它这么做,可以先用exists()方法先判断目录是否存在。

在写入数据的时候经常想要知道当前的进度,API也提供了一个Progressable用于传递回调接口,这样我们就可以很方便的将写入datanode的进度通知给应用了。

package org.apache.hadoop.util;
public interface Progressable{
public void progress();
}

IOUtils.copyBytes(in, out, 4096, false)方法实现了文件合并及上传至hdfs上
IOUtils.copyBytes(in, out, 4096, false)
–in:是FSDataInputStream类的对象,是有关读取文件的类,也就是所谓“输入流”
–out:是FSDataOutputStream类的对象,是有关文件写入的类,也就是“输出流”
–4096表示用来拷贝的buffer大小(buffer是缓冲区)–缓冲区大小

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.io.File;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
public class FileSystemUpload {	
	public static void main(String[] args) throws IOException {
		//请在 Begin-End 之间添加代码,完成任务要求。
        /********* Begin *********/
		File localPath=new File("/develop/test.txt");
		String hdfsPath ="hdfs://localhost:9000/user/hadoop/test.txt";
		InputStream in=new BufferedInputStream(new FileInputStream(localPath));
		//获取输入流对象
		Configuration config=new Configuration();
		FileSystem fs=FileSystem.get(URI.create(hdfsPath),config);
		long fileSize=localPath.length() > 65536 ? localPath.length()/65536 :1;
		//待上传文件大小
		FSDataOutputStream out =fs.create(new Path(hdfsPath),new Progressable(){
		//方法在每次上传了64KB字节大小的文件之后会自动调用一次
			long fileCount=0;
			public void progress(){
				System.out.println("总进度"+(fileCount/fileSize)*100+"%");
				fileCount++;
			}
		});
	IOUtils.copyBytes(in,out,2048,true);//最后一个参数的意思是使用完之后是否关闭流
	}
}

##删除HDFS中的文件和文件夹

列出文件
我们在开发或者维护系统时,经常会需要列出目录的内容,在HDFS的API中就提供了listStatus()方法来实现该功能。

public FileStatus[] listStatus(Path f)throws IOException

public FileStatus[] listStatus(Path f,PathFilter filter)throws IOException

public FileStatus listStatus(Path[] files)throws IOException

public FileStatus() listStatus(Path[] files,PathFilter filter)throws IOException

当传入参数是一个文件时,他会简单的转变成以数组方式返回长度为1的FileStatus对象,当传入参数是一个目录时,则返回0或多个FileStatus对象,表示此目录中包含的文件和目录。

listStatus()方法的使用:

public static void main(String]args)throws IOException {
string uri ="hdfs://localhost:9000/";//HDFS根目录
string path1 ="hdfs://localhost:9000/user";
Configuration config = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri),config);
Path[]paths ={new Path(uri),new Path(path1)};//构建要显示目录的数组
Filestatus[1 status = fs.liststatus(paths);
Path[]listPaths = Fileutil.stat2Paths(status);
for(Path path:listPaths){
system.out.println(path):

删除文件
使用FileSystem的delete()方法可以永久性删除文件或目录。

public boolean delete(Path f,boolean recursive)throws IOException

如果f是一个文件或者空目录,那么recursive的值可以忽略,当recursize的值为true,并且p是一个非空目录时,非空目录及其内容才会被删除(否则将会抛出IOException异常)。

import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
public class FileSystemDelete {
	
	public static void main(String[] args) throws IOException {
		String uri="hdfs://localhost:9000/";
		String path3="hdfs://localhost:9000/user";
		String path2="hdfs://localhost:9000/user/hadoop";
		String path1="hdfs://localhost:9000/user/tmp";
		Configuration config=new Configuration();
		FileSystem fs=FileSystem.get(URI.create(uri),config);
		fs.delete(new Path(path2),true);//删除
		fs.delete(new Path(path3),true);//删除
		Path[] paths={new Path(uri),new Path(path1)};
		FileStatus[] status=fs.listStatus(paths);
		Path[] listPaths=FileUtil.stat2Paths(status);
		for (Path path:listPaths){
			System.out.println(path);
		}
	}
}
发布了9 篇原创文章 · 获赞 1 · 访问量 100

猜你喜欢

转载自blog.csdn.net/qq_42112448/article/details/105130054