黑马程序员——IO——File、常用流对象演示

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

File类

File类用来将文件或者对象封装成对象,方便对文件与文件夹的属性信息进行操作。

file对象可以作为参数传递给流的构造函数。

ps:流只能操作数据,不能操作文件,只有File类能对文件进行操作。

示例:File类创建文件

package com.leaf.iotest;

import java.io.File;

public class FileDemo {

	public static void main(String[] args) {
		//可以将一个已存在的,或者不存在的文件或者目录封装成file对象
		//方式1:
		File f1 = new File("E:\\File\\x.txt");
		//方式2:
		File f2 = new File("E:\\File","y.txt");
		//方式3:
		File fh = new File("E:\\File");
		File f3 = new File(fh,"z.txt");
		//能在不同的系统中通用
		File f4 = new File("E:"+File.separator+"File"+File.separator+"xyz.txt");
	}
}
result:



你发现运行代码,却在对应的文件夹下没有发现文件?这是怎么回事?

分析:原来,File类new一个File不是创建一个文件,而是创建一个文件或者问价夹的路径,只有你使用createNewFile并返回true的时候才是文件创建成功。

 

下面我们先介绍一下文件File类的常用方法:

1.      获取

a)        获取文件名

b)        获取文件路径

c)        获取文件大小

d)        获取文件的修改时间

 

示例:

package com.leaf.iotest;

import java.io.File;
import java.text.DateFormat;
import java.util.Date;

public class FileMethodDemo{

	public static void main(String[] args) {
		
		File file1 = new File("1.txt");
		File file2 = new File("E:\\File\\1.txt");
		//获取文件名
		String name = file2.getName();
		//获取绝对路径
		String absPath = file2.getAbsolutePath();
		String path1 = file1.getPath();
		String path2 = file2.getPath();
		long len = file2.length();
		long time = file2.lastModified();
		//相对路径不同,父目录不同,如果此路径名没有指定的父目录,则返回null
		String parent1 = file1.getParent();
		String parent2 = file2.getParent();
		
		Date date = new Date(time);
		DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
		String str_time = df.format(date);
		
		System.out.println("name:"+name);
		System.out.println("absPath:"+absPath);
		System.out.println("path1:"+path1);
		System.out.println("path2:"+path2);
		System.out.println("len:"+len);
		System.out.println("str_time:"+str_time);
		System.out.println("parent1:"+parent1);
		System.out.println("parent2:"+parent2);
	}

}

result:


文件的创建和删除:

示例:

package com.leaf.iotest;

import java.io.File;
import java.io.IOException;

public class FileCreAndDelDemo {
	public static void main(String[] args) throws IOException {
		File file = new File("file.txt");
		// 和输出流不一样,如果文件不存在,则创建,如果文件存在,则不创建
		boolean b1 = file.createNewFile();
		System.out.println("b1 = " + b1);
		// 使用delete方法删除文件夹的时候,如果文件夹中有文件,则会删除失败
		boolean b2 = file.delete();
		System.out.println("b2 = " + b2);
		File dir = new File("abc\\ab");
		// 使用mkdir可以创建多级目录
		boolean b3 = dir.mkdir();// make directory
		System.out.println("b3 = " + b3);

		// 最里层目录被干掉,dir代表的是最里层的目录
		boolean b4 = dir.delete();
	}
}
result:

判断:

package com.leaf.iotest;

import java.io.File;
import java.io.IOException;

public class FileMethodDemo2 {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		File f = new File("a.txt");
		//文件是否存在
		boolean b = f.exists();
		System.out.println("b:"+b);
		if(!f.exists()){
			f.createNewFile();
		}
		if(f.exists()){
			//是文件?
			System.out.println(f.isFile());
			//是目录?
			System.out.println(f.isDirectory());
			f = new File("aa\\bb");
			f.mkdir();
			if(f.exists()){
				System.out.println(f.isFile());
				System.out.println(f.isDirectory());
			}
		}
	}

}

result:

系统的根目录和容量获取

package com.leaf.iotest;

import java.io.File;

public class FileMethodDemo3 {

	public static void main(String[] args) {
		File[] files = File.listRoots();
		for(File file:files){
			System.out.println(file);
		}
		File file = new File("E:\\");
		
		System.out.println("getFreeSpace:"+file.getFreeSpace());
		System.out.println("getTotalSpace:"+file.getTotalSpace());
		System.out.println("getUsableSpace:"+file.getUsableSpace());
	}
}

result:

获取目录下的文件已经文件夹的名称

package com.leaf.iotest;

import java.io.File;

public class FileListDemo {

	public static void main(String[] args) {
		File file = new File("C:\\");
		//获取目录下的文件已经文件夹名称(包括隐藏文件)
		//调用List方法的File对象中封装的必须是目录,否则会发生NullPointerException
		//如果访问的是系统级目录也会发生空指针异常
		//如果目录存在但是没有内容,会返回一个长度为0的数组。
		String[] names = file.list();
		
		for(String name :names){
			System.out.println(name);
		}
	}
}

result:


获取D盘下JavaClass文件下的”.java“文件

package com.leaf.iotest;

import java.io.File;
import java.io.FilenameFilter;

public class FileMethodDemo4 {

	public static void main(String[] args) {
		File dir = new File("D:\\JavaClass");
		String[] names = dir.list(new FilterByJava());
		for(String name :names){
			System.out.println(name);
		}
	}
}
class FilterByJava implements FilenameFilter{
	
	@Override
	public boolean accept(File dir, String name) {
		return name.endsWith(".java");
	}
}

result:


打印出c盘下的隐藏文件

package com.leaf.iotest;

import java.io.File;
import java.io.FilenameFilter;

public class FileListDemo1 {

	public static void main(String[] args) {
		File dir = new File("C:\\");
		File[] files = dir.listFiles(new FilterByHidden());
		for(File file:files){
			System.out.println(file);
		}
	}
}
class FilterByHidden implements FilenameFilter{

	@Override
	public boolean accept(File dir, String name) {
		return dir.isHidden();
	}
	
}

result:


递归算法:

函数自身直接或者间接的调用到了自身,一个功能在被重复使用,并且每次使用时,参与运算的结果和上一次调用有关,这是可以使用递归来解决问题

 

ps

1.      递归一定要明确条件,否则容易栈溢出

2.      注意递归的次数

需求:对指定目录进行所有内容(包含子目录的内容),可以理解为深度遍历。

package com.leaf.iotest;

import java.io.File;

public class FileListDemo3 {

	/**使用递归对文件目录及子目录的所有文件进行打印
	 * @param args
	 */
	public static void main(String[] args) {
		File fileDir = new File("E:\\File");
		listAll(fileDir,0);
	}
	public static void listAll(File dir , int level){
		System.out.println(getSpace(level)+"dir:"+dir.getAbsolutePath());
		level++;
		File[] files = dir.listFiles();
		for(int x = 0;x<files.length;x++){
			if(files[x].isDirectory()){
				listAll(files[x],level);
			}
			System.out.println(getSpace(level)+"files:"+files[x].getAbsolutePath());
		}
	}
	private static String getSpace(int level) {
		StringBuilder sb = new StringBuilder();
		sb.append("|--");
		for(int x = 0;x>level;x++){
			sb.append("| ");
		}
		return sb.toString();
	}

}

result:


递归的作用很多,简单示例:

package com.leaf.iotest;

public class DiGuiDemo {

	/**利用递归求一个数的二进制
	 * @param args
	 */
	public static void main(String[] args) {
		toBin(7);
	}
	public static void toBin(int num){
		if(num >0){
			toBin(num/2);
			System.out.println(num%2);
		}
	}
}

result:


IO中其他流对象:

打印流:

printWriterhe PrintStream:可以直接操作输入流和文件。

 

PrintStream为其他输出流添加了功能,使他们能方便的打印出各种数据值表示形式

与其他输出流不同,PrintStream永远不会泡茶IOException

PrintStream打印的所有字符都使用平台默认的字符编码转换为字节

在需要写入字符而不是写入字节的情况下,应该使用PrintWriter

PrintStream:

1. 提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式

2. 它不抛IOException

构造函数,接收三种类型的值:

1. 字符串路径

2. File对象

3. 字节输出流

示例:

package com.leaf.iotest;

import java.io.PrintStream;

public class PrintStreamDemo {
	public static void main(String[] args) throws Exception {
		PrintStream out = new PrintStream("E:\\File\\print.txt");

		// write(int b)方法只写最低8位
		out.write(97); // a
		// print方法将97先变成字符串保持原样将数据打印到目的地
		out.print(97); // 97
		out.close();
	}
}
result:

PrintWriter:字符打印流

构造函数参数:

1. 字符串路径

2. File对象

3. 字节输出流

4. 字符输出流

 

示例:

package com.leaf.iotest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class PrintWriterDemo {

	public static void main(String[] args) throws IOException {
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(System.out);
		String line = null;
		while((line = bufr.readLine())!= null){
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());
			out.flush();
		}
	}
}

result:

序列流:

SequenceInputStream:多个流进行合并。

需求,将1.tx、2.txt、3.txt文件中的数据合并到一个文件4.txt中。

package com.leaf.iotest;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;

public class SequenceInputStreamDemo {
	public static void main(String[] args) throws Exception {
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		String path = "E:\\File\\";
		v.add(new FileInputStream(path+"1.txt"));
		v.add(new FileInputStream(path+"2.txt"));
		v.add(new FileInputStream(path+"3.txt"));

		Enumeration<FileInputStream> en = v.elements();

		SequenceInputStream sis = new SequenceInputStream(en);

		FileOutputStream fos = new FileOutputStream(path+"4.txt");

		byte[] buf = new byte[1024];

		int len = 0;

		while ((len = sis.read(buf)) != -1) {
			fos.write(buf, 0, len);
		}

		fos.close();
		sis.close();
	}
}

result:

运行前:


“1.txt”


“2.txt”


“3.txt”


运行后:


上述代码中,我们可以使用ArrayList来代替Vector。有兴趣的朋友可以试验一下。

 

需求:设计一个文件切割器,将文件安固定大小切割成n个部分

package com.leaf.iotest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class SplitFileDemo {

	private static final int SIZE = 1024 * 1024;

	public static void main(String[] args) throws IOException {
		File file = new File("E:\\File\\1.mp3");
		splitFile(file);
	}

	public static void splitFile(File file) throws IOException {
		// 用读取流关联源文件
		FileInputStream fis = new FileInputStream(file);

		// 定义一个1M的缓冲区
		byte[] buf = new byte[SIZE];

		// 创建目的
		FileOutputStream fos = null;

		int len = 0;
		int count = 1;

		// 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数,以方便于合并。
		// 这个信息为了进行描述,使用键值对的方式,用到了properties对象。
		Properties prop = new Properties();

		File dir = new File("E:\\File\\partFiles");
		if (!dir.exists())
			dir.mkdirs();

		while ((len = fis.read(buf)) != -1) {
			fos = new FileOutputStream(new File(dir, (count++) + ".part"));
			fos.write(buf, 0, len);
			fos.close();
		}

		// 将被切割文件的信息保存到prop集合中
		prop.setProperty("partcount", count + "");
		prop.setProperty("filename", file.getName());

		fos = new FileOutputStream(new File(dir, count + ".properties"));

		// 将prop集合中的数据存储到文件中
		prop.store(fos, "save file info");

		fis.close();
		fos.close();
	}
}
result:

运行前:


运行后:



合并刚刚切割的文件

示例:

package com.leaf.iotest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;

public class MergeFile {
	public static void main(String[] args) throws IOException {
		File dir = new File("E:\\File\\partFiles");
		mergeFile(dir);
	}

	public static void mergeFile(File dir) throws IOException {

		// 获取指定目录下的配置文件对象
		File[] files = dir.listFiles(new SuffixFilter(".properties"));

		if (files.length != 1)
			throw new RuntimeException(dir + ",该目录下没有properties扩展名的文件或者不唯一");

		// 记录配置文件对象
		File confile = files[0];

		// 获取该文件中的信息
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream(confile);

		prop.load(fis);

		String filename = prop.getProperty("filename");

		int count = Integer.parseInt(prop.getProperty("partcount"));

		// 获取该目录下的所有碎片文件
		File[] partFiles = dir.listFiles(new SuffixFilter(".part"));

		if (partFiles.length != (count - 1)) {
			throw new RuntimeException("碎片文件不符合要求,个数不对!应该是" + count + "个");
		}
		// 将碎片文件和流对象关联并存储到集合中
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();

		for (int x = 1; x <= partFiles.length; x++) {
			al.add(new FileInputStream(partFiles[x - 1]));
		}

		final Iterator<FileInputStream> it = al.iterator();

		// 将多个流合并成一个序列流
		Enumeration<FileInputStream> en = Collections.enumeration(al);

		SequenceInputStream sis = new SequenceInputStream(en);

		FileOutputStream fos = new FileOutputStream(new File(dir, filename));

		byte[] buf = new byte[1024 * 1024];

		int len = 0;

		while ((len = sis.read(buf)) != -1) {
			fos.write(buf, 0, len);
		}

		fos.close();
		sis.close();
	}
}

class SuffixFilter implements FilenameFilter {
	private String suffix;

	public SuffixFilter(String suffix) {
		super();
		this.suffix = suffix;
	}

	public boolean accept(File dir, String name) {
		return name.endsWith(suffix);
	}
}

result:



操作对象:

ObjectInputStream与ObjectOutputStream

 

ps:

被操作的对象需要实现Serialzable,类通过实现java.io.Serializable接口以启动序列号功能,Serializable只是一个标记接口。

这里不做演示了。

 

 

RandomAccessFile:这是一个非常特殊的类

演示:

package com.leaf.iotest;

import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileDemo {
	public static void main(String[] args) throws IOException {
		writeFile();
	}
	// 使用RandomAccessFile对象写入一些人员信息,比如姓名和年龄
	public static void writeFile() throws IOException {
		// 如果文件不存在,则创建,如果文件存在,不创建
		RandomAccessFile raf = new RandomAccessFile("E:\\File\\ranacc.txt", "rw");
		raf.write("张三".getBytes());
		// 使用write方法之写入最后一个字节
		raf.write(97);
		// 使用writeInt方法写入四个字节(int类型)
		raf.writeInt(97);
		raf.write("小强".getBytes());
		raf.writeInt(99);
		raf.close();
	}
}
result:

示例:

package com.leaf.iotest;

import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileDemo2 {
	public static void main(String[] args) throws IOException {
		readFile();
	}

	public static void readFile() throws IOException {
		RandomAccessFile raf = new RandomAccessFile("E:\\File\\ranacc.txt", "r");

		// 通过seek设置指针的位置
		raf.seek(9); // 随机的读取,只要指定指针的位置即可

		byte[] buf = new byte[4];
		raf.read(buf);

		String name = new String(buf);
		System.out.println("name=" + name);

		int age = raf.readInt();
		System.out.println("age=" + age);
		System.out.println("pos:" + raf.getFilePointer());

		raf.close();
	}
}

result:

注:因为我把eclipse的默认编码改成了UTF-8,所以会有上述的乱码问题。


管道流:

PipedInputStream和PipedOutputStream:输入输出可以直接进行连接,通过集合线程使用。

示例:

package com.leaf.iotest;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

class Read implements Runnable
{
	private PipedInputStream in;
	Read(PipedInputStream in)
	{
		this.in = in;
	}
	public void run()
	{
		try
		{
			byte[] buf = new byte[1024];

			System.out.println("读取前。。没有数据阻塞");
			int len = in.read(buf);
			System.out.println("读到数据。。阻塞结束");
			String s= new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道读取流失败");
		}
	}
}

class Write implements Runnable
{
	private PipedOutputStream out;
	Write(PipedOutputStream out)
	{
		this.out = out;
	}
	public void run()
	{
		try
		{
			System.out.println("开始写入数据,等待6秒后。");
			Thread.sleep(6000);
			out.write("piped lai la".getBytes());
			out.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException("管道输出流失败");
		}
	}
}

class  PipedStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream();
		in.connect(out);

		Read r = new Read(in);
		Write w = new Write(out);
		new Thread(r).start();
		new Thread(w).start();
	}
}

result:


操作基本数据类型:

DataInputStream与DataOutputStream

示例:

package com.leaf.iotest;
/*
DataInputStream与DataOutputStream
可以用于操作基本数据类型的数据的流对象。
*/
import java.io.*;
class DataStreamDemo 
{
	public static void main(String[] args) throws IOException
	{
		writeData();
		readData();
		writeUTFDemo();
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
		osw.write("你好");
		osw.close();
		readUTFDemo();
	}
	public static void readUTFDemo()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("E:\\File\\utfdate.txt"));
		String s = dis.readUTF();
		System.out.println(s);
		dis.close();
	}
	public static void writeUTFDemo()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\File\\utfdate.txt"));
		dos.writeUTF("你好");
		dos.close();
	}

	public static void readData()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("E:\\File\\data.txt"));
		int num = dis.readInt();
		boolean b = dis.readBoolean();
		double d = dis.readDouble();
		System.out.println("num="+num);
		System.out.println("b="+b);
		System.out.println("d="+d);
		dis.close();
	}
	public static void writeData()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\File\\data.txt"));
		dos.writeInt(234);
		dos.writeBoolean(true);
		dos.writeDouble(9887.543);
		dos.close();
	}
}

result:


操作字节数组:

ByteArrayInputStream 与 ByteArrayOutputStream

示例:

package com.leaf.iotest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ByteArrayDemo {
	public static void main(String[] args) throws IOException {
		ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
		ByteArrayOutputStream bos = new ByteArrayOutputStream();

		int ch = 0;

		while ((ch = bis.read()) != -1) {
			bos.write(ch);
		}

		System.out.println(bos.toString());
	}
}

result:






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值