HDFS的java api使用

本文档介绍了如何使用Hadoop的Java API进行HDFS文件系统的操作,包括上传本地文件到HDFS、创建新文件、删除文件、读取文件内容、创建和删除目录以及列出目录内容。示例代码详细展示了FileSystem、FSDataInputStream和FSDataOutputStream类的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.2 HDFS控制(Java)

hadoop中关于文件操作类基本上全部是在org.apache.hadoop.fs包中,这些api能够支持的操作包含:打开文件,读写文件,删除文件等。

FileSystem,该类是个抽象类,只能通过来类的get方法得到具体类。get方法存在几个重载版本,常用的是这个:

static FileSystem get(Configuration conf);

 

1.3 代码演示

 

import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

publicclass HadoopFSOperations {
    public static void main(String[] args) throws Exception {
        // createNewHDFSFile("/tmp/create2.c", "hello");
        // System.out.println(readHDFSFile("/tmp/copy.c").toString());
        // mkdir("/tmp/testdir");
        // deleteDir("/tmp/testdir");
        listAll("/tmp/");
    }
    /*
     * upload the local file to the hds notice that the path is full like
     * /tmp/test.c
     */
    public static void uploadLocalFile2HDFS(String s, String d) throws IOException {
        Configuration config = new Configuration();
        FileSystem hdfs = FileSystem.get(config);
        Path src = new Path(s);
        Path dst = new Path(d);
        hdfs.copyFromLocalFile(src, dst);
        hdfs.close();
    }
    /*
     * create a new file in the hdfs. notice that the toCreateFilePath is the
     * full path and write the content to the hdfs file.
     */
    public static void createNewHDFSFile(String toCreateFilePath, String content) throws IOException {
        Configuration config = new Configuration();
        FileSystem hdfs = FileSystem.get(config);
        FSDataOutputStream os = hdfs.create(new Path(toCreateFilePath));
        os.write(content.getBytes("UTF-8"));
        os.close();
        hdfs.close();
    }
    /*
     * delete the hdfs file notice that the dst is the full path name
     */
    public static boolean deleteHDFSFile(String dst) throws IOException {
        Configuration config = new Configuration();
        FileSystem hdfs = FileSystem.get(config);
        Path path = new Path(dst);
        booleanisDeleted = hdfs.delete(path);
        hdfs.close();
        return isDeleted;
    }
    /*
     * read the hdfs file content notice that the dst is the full path name
     */
    public static byte[] readHDFSFile(String dst) throws Exception {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);
        // check if the file exists
        Path path = new Path(dst);
        if (fs.exists(path)) {
            FSDataInputStream is = fs.open(path);
            // get the file info to create the buffer
            FileStatus stat = fs.getFileStatus(path);
            // create the buffer
            byte[] buffer = newbyte[Integer.parseInt(String.valueOf(stat.getLen()))];
            is.readFully(0, buffer);
            // 多次读取
            // int length = 0;
            // while ((length = is.read(buffer, 0, 128)) != -1) {
            // System.out.println(new String(buffer, 0, length));
            // }
            is.close();
            fs.close();
            returnbuffer;
        } else {
            thrownew Exception("the file is not found .");
        }
    }

    /*
     * make a new dir in the hdfs
     * the dir may like '/tmp/testdir'
     */
    public static void mkdir(String dir) throws IOException {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);
        fs.mkdirs(new Path(dir));
        fs.close();
    }

    /*
     * delete a dir in the hdfs
     * dir may like '/tmp/testdir'
     */
    public static void deleteDir(String dir) throws IOException {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);
        fs.delete(new Path(dir));
        fs.close();
    }
    public static void listAll(String dir) throws IOException {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);

        FileStatus[] stats = fs.listStatus(new Path(dir));
    
        for (inti = 0; i<stats.length; ++i) {
            if (stats[i].isFile()) {
                // regular file
                System.out.println(stats[i].getPath().toString());
            } elseif (stats[i].isDirectory()) {
                // dir
                System.out.println(stats[i].getPath().toString());
            } elseif (stats[i].isSymlink()) {
                // is s symlink in linux
                System.out.println(stats[i].getPath().toString());
            }
        }
        fs.close();
    }
}

1.4 FileSystem

我们知道,首先对于任何文件系统都是与当前环境变量紧密联系一起,对于当前 HDFS来说,在创建出当前文件系统实例之前,有必要获得当前的环境变量。代码见下:

Configuration conf = new Configuration();

Configuration 类为用户提供了对当前环境变量的一个实例,其中封装了当前搭载环境的配置,这配置是在我们由 core-site.xml 设置,一般返回值默认的本地系统文件。

而对于 HDFS 为我们提供的 FileSystem,更进一步为我们提供了一套加载当前环境并建立读写路径的 API,使用的方法如下所示:

public static FileSystem get(Configuration conf) throws IOException

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

第一个方法使用默认的 URI 地址获取当前对象中环境变量加载的文件系统,第二个方法使用传入的 URI 获取路径指定的文件系统。

 

1.5 FSDataInputStream

我们在对 FSDataInputStream 进行分析之前,将上面例子中代码替换为如下所示:

​ InputStream fis = fs.open(inPath);

程序依旧可以正常运行。

public class FSDataInputStream extends DataInputStream implements Seekable, PositionedReadable { 
                                                                                                    
    publicsynchronizedvoid seek(longdesired) throws IOException { 
        ((Seekable) in).seek(desired);
    }

    publicint read(longposition, byte[] buffer, intoffset, intlength) throws IOException {
        return ((PositionedReadable) in).read(position, buffer, offset, length); 
    }

    publicvoid readFully(longposition, byte[] buffer, intoffset, intlength) throws IOException{
        ((PositionedReadable) in).readFully(position, buffer, offset, length);
    }

    publicvoid readFully(longposition, byte[] buffer) throws IOException {
        ((PositionedReadable) in).readFully(position, buffer, 0, buffer.length); 
    }
}

  • 其实read(byte[] b)方法和readFully(byte []b)都是利用InputStream中read()方法,每次读取的也是一个字节,只是读取字节数组的方式不同,查询jdk中源代码发现。

  • read(byte[] b)方法实质是读取流上的字节直到流上没有字节为止,如果当声明的字节数组长度大于流上的数据长度时就提前返回,而readFully(byte[] b)方法是读取流上指定长度的字节数组,也就是说如果声明了长度为len的字节数组,readFully(byte[] b)方法只有读取len长度个字节的时候才返回,否则阻塞等待,如果超时,则会抛出异常 EOFException。

publicclass FSDSample {
    publicstaticvoid main(String[] args) throws Exception {
        
        Configuration conf = new Configuration(); // 获取环境变量
        FileSystem fs = FileSystem.get(conf); // 获取文件系统
        FSDataInputStream fsin = fs.open(new Path("sample.txt")); // 建立输入流
        byte[] buff = newbyte[128]; // 建立辅助字节数组
        intlength = 0;
        while ((length = fsin.read(buff, 0, 128)) != -1) { // 将数据读入缓存数组
            System.out.println(new String(buff, 0, length)); // 打印数据
        }
        System.out.println("length = " + fsin.getPos()); // 打印输入流的长度

        fsin.seek(0); // 返回开始处
        while ((length = fsin.read(buff, 0, 128)) != -1) { // 将数据读入缓存数组
            System.out.println(new String(buff, 0, length)); // 打印数据
        }

        fsin.seek(0); // 返回开始处
        byte[] buff2 = newbyte[128]; // 建立辅助字节数组
        fsin.read(buff2, 0, 128);
        System.out.println("buff2 =" + new String(buff2));
        System.out.println(buff2.length);
    }
}

1.6 FSDataOutputStream

public FSDataOutputStream create(Path f) throws IOException {
        return create(f, true);
    }

    public FSDataOutputStream create(Path f, booleanoverwrite) throws IOException {
        return create(f, overwrite, getConf().getInt("io.file.buffer.size", 4096),     getDefaultReplication(),
                getDefaultBlockSize());
    }

FSDataOutputStream 也是继承自 OutoutStream 的一个子类,专用为 FileSystem 提供文件的输出流。然后可以使用 OutoutStream 中的 write 方法对字节数组进行写操作。

public class FSWriteSample {
    public static void main(String[] args) throws Exception {
        Path path = new Path("writeSample.txt"); // 创建写路径
        Configuration conf = new Configuration(); // 获取环境变量
        FileSystem fs = FileSystem.get(conf); // 获取文件系统
        FSDataOutputStream fsout = fs.create(path); // 创建输出流
        byte[] buff = "hello world".getBytes(); // 设置输出字节数组
        fsout.write(buff); // 开始写出数组
        IOUtils.closeStream(fsout); // 关闭写出流
    }
}

public FSDataOutputStream create(Path f, Progressable progress) throws IOException {
}

有一个是Progressable progress 的形参, Progressable 接口如下所示:

publicinterface Progressable {
    public void progress(); // 调用 progress 方法
}

Progressable 接口中只有一个 progress 方法,每次在 64K 的文件写入既定的输入流以后,调用一次 progress 方法,这给我们提供了很好一次机会,可以将输出进度显示,代码如下:

public class FSWriteSample2 {
    static int index = 0;
    public static void main(String[] args) throws Exception {
        StringBuffer sb = new StringBuffer(); // 创建辅助可变字符串
        Random rand = new Random();
        for (inti = 0; i< 9999999; i++) { // 随机写入字符
            sb.append((char) rand.nextInt(100));
        }
        byte[] buff = sb.toString().getBytes(); // 生成字符数组
        Path path = new Path("writeSample.txt"); // 创建路径
        Configuration conf = new Configuration(); // 获取环境变量
        FileSystem fs = FileSystem.get(conf); // 获取文件系统
        FSDataOutputStream fsout = fs.create(path, new Progressable() { // 创建写出流
                    @Override
                    publicvoid progress() { // 默认的实用方法
                        System.out.println(++index); // 打印出序列号
                    }
                });
        fsout.write(buff); // 开始写出操作
        IOUtils.closeStream(fsout); // 关闭写出流
    }
}

注意: FSDataOutputStream 与 FSDataInputStream 类似,也有 getPos 方法,返回是文件内以读取的长度。但是不同之处在于, FSDataOutputStream 不能够使用 seek 方法对文件重新定位。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值