HDFS常见javaAPI操作

/**
 * 总结了HDFS的常见javaAPI操作,包括:
 * 1.创建文件夹
 * 2.删除文件夹
 * 3.创建文件
 * 4.上传文件
 * 5.下载文件
 * 6.使用seek命令多次重定位操作
 * 7.多线程(并发)写入多个文件
 * 8.文件的追加
 * 9.多线程追加入单个文件;注:这种方式无法实现,示例中列出了错误原因
 * 10.不同字符集文件的上传
 * 11.hdfs内部文件拷贝
 * @author SHCH
 *
 */
public class HDFS_Demo1 {
	public static void main(String[] args) throws Exception {
		
		
	}
	/**
	 * hdfs文件的内部拷贝,类似hdfs shell的distcp命令
	 * 但注意,只是拷贝文件
	 * 目前还没找到内部拷贝文件夹的api
	 * 
	 * @throws IOException
	 */
	private static void innerHDFSFileCopy() throws IOException {
		String path="hdfs://192.168.80.132:9000";
		FileSystem fs=FileSystem.get(URI.create(path),new Configuration());
		FSDataInputStream fdis = fs.open(new Path("/one/bb.xml"));
		FSDataOutputStream fdos = fs.create(new Path("/one/cc.xml"));
		//HDFS自身的拷贝
		IOUtils.copyBytes(fdis, fdos, 1024, true);
	}

	/**
	 * 修改hdfs-site.xml,添加property,dfs.support.append并设置为true,可以实现文件的追加(hadoop1不支持),
	 * 
	 * 
	 * 下面这个方法会出错,如下:
	 * because DFSClient_NONMAPREDUCE_1373065962_11 is already the current lease holder.
	 * 意思是说多个并发线程不能写入同一个文件
	 * 
	 * 注:此时文件有可能已经写入数据,但数据中只是一个线程写入的内容!!!
	 */
	private static void multiThreadWriteSingleFile() {
		class MyRunnable implements Runnable {
			private int idx;

			public MyRunnable(int... idx) {
				if (idx.length > 0)
					this.idx = idx[0];
			}
			FileSystem fs = null;
			@Override
			public void run() {
				try {
					fs = FileSystem.get(URI.create("hdfs://192.168.80.132:9000"), new Configuration());
					FSDataOutputStream fdos = fs.append(new Path("/one/appendfile"));
					for (int k = 0; k < 5; k++) {
						for (int i = 0; i < 5; i++) {
							fdos.write(Thread.currentThread().getName().getBytes());
							fdos.write(" ".getBytes());
						}
						fdos.write("\n".getBytes());
						//不知道有啥用......
						fdos.sync();
						Thread.currentThread().sleep(100);// 让其它綫程执行一下
					}
					IOUtils.closeStream(fdos);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		;
		// 启动三个线程
		for (int i = 0; i < 3; i++) {
			new Thread(new MyRunnable()).start();
		}
	}

	/**
	 * 开启多个线程写入不同文件
	 * 
	 */
	private static void multiThreadputData() {
		class MyRunnable implements Runnable {
			private int idx;

			public MyRunnable(int idx) {
				this.idx = idx;
			}

			FileSystem fs = null;

			@Override
			public void run() {
				try {
					fs = FileSystem.get(URI.create("hdfs://192.168.80.132:9000"), new Configuration());
					FSDataOutputStream fdos = fs.create(new Path("/one/file" + idx));
					// 写五行
					for (int k = 0; k < 5; k++) {
						// 每行写五个单词
						for (int i = 0; i < 5; i++) {
							// 写入5个字符一组,模拟英文单词
							for (int j = 0; j < 5; j++) {
								char ch = "abcdefghijklmnopqrstuvwxyz".charAt(new Random().nextInt(26));
								fdos.write(ch);
							}
							fdos.write(" ".getBytes());
						}
						fdos.write("\n".getBytes());
						// 让其它程序执行一下
						Thread.currentThread().sleep(100);
					}
					IOUtils.closeStream(fdos);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		;
		// 启动三个线程
		for (int i = 0; i < 3; i++) {
			new Thread(new MyRunnable(i + 1)).start();
		}
	}

	/**
	 * 由于本地(中文版windows)文件是gbk格式,因此,按照gbk读取,但centos默认字符集是utf8,要解决字符集问题,需要按照utf8格式输出
	 * 
	 * @throws IOException
	 * @throws FileNotFoundException
	 * @throws UnsupportedEncodingException
	 */
	private static void putDataWithCharSet() throws IOException, FileNotFoundException, UnsupportedEncodingException {
		FileSystem fs = FileSystem.get(URI.create("hdfs://192.168.80.132:9000"), new Configuration());
		FileInputStream fis = new FileInputStream(new File("d:/test.txt"));
		FSDataOutputStream fdos = fs.create(new Path("/one/test2.txt"));
		byte[] b = new byte[1024];
		int len = 0;
		while ((len = fis.read(b)) != -1) {
			// 由于本地(中文版windows)文件是gbk格式,因此,按照gbk读取,但centos默认字符集是utf8,要解决字符集问题,需要按照utf8格式输出
			fdos.writeUTF(new String(b, 0, len, "gbk"));
		}
		// IOUtils.copyBytes(fis, fdos, 1024, true);
		IOUtils.closeStream(fdos);
		fis.close();
	}

	/**
	 * 如果路径是一个目录,则列出给定路径中文件/目录的状态。 注:必须是一个目录,如果列出跟目录下的,需要加“/”
	 * 
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private static void listStatus() throws IOException, FileNotFoundException {
		// 注意:path最后必须有路径“/”(或具体的文件夹)
		String path = "hdfs://192.168.80.132:9000/";
		FileSystem fs = FileSystem.get(URI.create(path), new Configuration());
		FileStatus[] statuss = fs.listStatus(new Path(path));
		for (FileStatus s : statuss) {
			// 大体与listFiles相似,此处简单一些
			// 另外:包含的还有文件夹的信息
			System.out.println(s.getPath().toString());
		}
	}

	/**
	 * 列出给定路径中文件的状态和块位置。如果路径是一个目录,如果recursive 是false的,则返回目录中的文件;如果recursive
	 * 是true的,那么在子树中返回的文件根在路径上。如果路径是一个文件,返回文件的状态和块位置。 注:
	 * 1.listFiles包含块信息,liststatus则没有 2.只获取文件的信息,而没有文件夹的信息
	 * 
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private static void listFiles() throws IOException, FileNotFoundException {
		String path = "hdfs://192.168.80.132:9000";
		FileSystem fs = FileSystem.get(URI.create(path), new Configuration());
		RemoteIterator files = fs.listFiles(new Path("/"), true);
		while (files.hasNext()) {
			LocatedFileStatus status = files.next();
			String pathname = status.getPath().toString();
			boolean type = status.isDirectory();
			BlockLocation[] blockLocations = status.getBlockLocations();
			long blockSize = status.getBlockSize();
			FsPermission permission = status.getPermission();
			System.out.println(pathname);
			System.out.println("\t文件类型" + (type == true ? "文件夹" : "文件"));
			System.out.println("\t块位置");
			for (int i = 0; i < blockLocations.length; i++) {
				System.out.println("\t\t" + blockLocations[i].toString());
			}
			System.out.println("\t块大小:" + blockSize);
			System.out.println("\t权限:" + permission.toString());
			/*
			 * status的其它方法 isDirectory isFile getBlockSize getBlockLocations获取块位置
			 * 
			 */
		}
	}

	/**
	 * 从HDFS上获取数据,同时使用seek方法重新定位
	 * 
	 * @throws IOException
	 */
	private static void getDataUseSeek() throws IOException {
		String path = "hdfs://192.168.80.132:9000";
		String file = "/testfile";
		FSDataInputStream fdis = null;
		FileSystem fs = FileSystem.get(URI.create(path), new Configuration());
		try {
			Path f = new Path(file);
			// 可以通过fs的isFile或isDirectory方法获得file的类型
			if (!fs.isFile(f)) {
				System.out.println("要下載的文件是文件夹,只能下载文件!");
				return;
			}
			fdis = fs.open(new Path(file));
			byte[] b = new byte[1024];
			int len = 0;
			System.out.println("第一次打印:");
			while ((len = fdis.read(b)) != -1) {
				String res = new String(b, 0, len);
				System.out.println(res);
			}
			System.out.println("第二次打印:");
			// FSDataInputStream实现了Seekable接口,因此可以通过seek方法重新定位到字节数据的任意位置,还有一个skip方法,尽可以向前定位
			fdis.seek(0);
			while ((len = fdis.read(b)) != -1) {
				String res = new String(b, 0, len);
				System.out.println(res);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeStream(fdis);
		}
	}

	/**
	 * 从hdfs获取数据,类似shell的get命令
	 * 
	 * @throws IOException
	 */
	private static void getData() throws IOException {
		String path = "hdfs://192.168.80.132:9000/";
		String file = "/testfile";
		String localFile = "d:/b.txt";
		FileSystem fs = FileSystem.get(URI.create(path), new Configuration());
		FSDataInputStream fdis = null;
		FileOutputStream fos = null;
		try {
			fdis = fs.open(new Path(path));
			fos = new FileOutputStream(new File(localFile));
			IOUtils.copyBytes(fdis, fos, 1024, false);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeStream(fdis);
			if (fos != null)
				fos.close();
		}
	}

	/**
	 * 。 像hdfs上传数据,类似shell的put命令
	 * 
	 * @throws IOException
	 */
	private static void putData() throws IOException {
		String path = "hdfs://192.168.80.132:9000/";
		String file = "/testfile";
		String localFile = "d:/a.txt";
		FileSystem fs = FileSystem.get(URI.create(path), new Configuration());
		FSDataOutputStream dos = null;
		FileInputStream fis = null;
		try {
			// 通过fs的create方法获取像hdfs发送数据的FSDataOutputStream
			dos = fs.create(new Path(file));
			fis = new FileInputStream(new File(localFile));
			IOUtils.copyBytes(fis, dos, 1024, false);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeStream(dos);
			if (fis != null)
				fis.close();
		}
	}

	private static void removeDir() throws IOException, URISyntaxException {
		String path = "hdfs://192.168.80.132:9000/"; // 用以创建URI对象
		String dir = "/three";
		FileSystem fs = FileSystem.get(URI.create(path), new Configuration());
		boolean delete = fs.delete(new Path(dir), true);
		if (delete) {
			System.out.println("删除一个文件夹" + dir);
		}
	}

	/**
	 * 使用hadoop API创建一个文件夹 注意区分两个路径,传入get方法的是URI对象;mkdir方法传入的是Path对象
	 * 
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	private static void createDir() throws IOException, URISyntaxException {
		String path = "hdfs://192.168.80.132:9000/"; // 用以创建URI对象
		String dir = "/three";// 用于组建Path对象
		FileSystem fs = FileSystem.get(new URI(path), new Configuration());// 使用默认的配置,
		boolean mkdirs = fs.mkdirs(new Path(dir));
		if (mkdirs) {
			System.out.println("创建一个文件夹" + dir);
		}
		// fs.close();
	}

	/**
	 * 使用纯java方式访问hdfs
	 * 
	 * 这种方式功能较弱,最好的方式使用Hadoop提供的API来访问
	 */
	private static void getHDFSFileWithOutHadoopAPI() throws MalformedURLException, IOException {
		String path = "hdfs://192.168.80.132:9000/users/testfiles/CreateTestFile.py";
		URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
		URL url = new URL(path);
		InputStream is = url.openStream();
		IOUtils.copyBytes(is, System.out, 1024, true);
	}
}

你可能感兴趣的:(HDFS常见javaAPI操作)