IO流总结(基础知识)

IO流总结

 IO这章的知识在上面一篇博客也说过一点,主要要体会一下装饰者设计模式和适配器设计模式,这样更利于我们理解复杂的IO体系结构。今天就让我们看一看。不过在讲IO
之前,我们先把文件(File)的知识简单过一下。

一、文件File

文件大家都不陌生,查看JDK帮助文档,我们知道File的定义——文件和目录(文件夹)路径名的抽象表示形式。

1、构造方法

File(String pathname):根据一个路径得到File对象
File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

2、创建功能

public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来

举例:
         //需求1:我要在e盘目录下创建一个文件demo
File file = new File("e:\\a.txt");
大家可能会认为这里用了关键字new,那么文件File就会出来了,其实不是,因为File的定义是:文件和目录(文件夹)路径名的抽象表示形式。它仅仅是文件的表示
形式,不是真实的文件。 所以需要调用这样一句代码file.createNewFile()

      

        //需求2:我要在e盘目录test下创建一个文件b.txt

File file = new File("e:\\test\\b.txt");
System.out.println("createNewFile:" + file3.createNewFile());
运行之后可以看到控制台打印出:
Exception in thread "main" java.io.IOException: 系统找不到指定的路径。

所以注意:要想在某个目录下创建内容,该目录首先必须存在。我们可以这么做:File file1=new File("e:\\test);file1.mkdir();//先把文件夹(目录)创建出来然后在:

        File file2=new   File(e:\\test\\b.txt);file2.createNewFile();//在创建文件

        //看下面这行代码
        File file = new File("e:\\liuyi\\a.txt");
System.out.println("mkdirs:" + file8.mkdirs());
你会看到a.txt是个目录,不要认为指定了.txt后缀就是文件了,要看它调用的是creatNewFile()还是mkdir();

3、删除功能

public boolean delete()
这个方法比较简单,注意:
A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
B:Java中的删除不走回收站。
C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹,所以delete一次只能删除一个文件,如果想删除一个文件夹,那必须要循环遍历了。

4、重命名功能

    public boolean renameTo(File dest)
如果路径名相同,就是改名。
        如果路径名不同,就是改名并剪切。

需求:将G盘所有视频文件该名成“0?-网络编程(概述).avi”,原来视频文件名称为:黑马程序员_毕向东_Java基础视频教程第23天-0?-网络编程(概述).avi

<span style="font-size:18px;">public class FileDemo {
	private static File dest;
	public static void main(String[] args) {
		//封装目录
		File  file=new File("G:\\黑马入学\\网络编程1");
		File[] sorcFolder = file.listFiles();
		for (File f : sorcFolder) {
			String name = f.getName();
			//黑马程序员_毕向东_Java基础视频教程第23天-01-网络编程(概述).avi
			//System.out.println(name);			
			int index = name.indexOf('-');
			String string = name.substring(index+1);
			//再次封装新的文件目录
             dest = new File(file,string);
             f.renameTo(dest);            
		}
	}
}</span>
执行结果:

一看全部改名成功,哈哈。。。

5、判断功能

  public boolean isDirectory():判断是否是目录
  public boolean isFile():判断是否是文件
  public boolean exists():判断是否存在
  public boolean canRead():判断是否可读
  public boolean canWrite():判断是否可写
  public boolean isHidden():判断是否隐藏

6、简单获取功能

 public String getAbsolutePath():获取绝对路径
 public String getPath():获取相对路径
 public String getName():获取名称
 public long length():获取长度。字节数
 public long lastModified():获取最后一次的修改时间,毫秒值

 示例代码:

<span style="font-size:18px;"> public class FileDemo {
	public static void main(String[] args) {
		// 创建文件对象
		File file = new File("demo\\test.txt");

		System.out.println("getAbsolutePath:" + file.getAbsolutePath());
		System.out.println("getPath:" + file.getPath());
		System.out.println("getName:" + file.getName());
		System.out.println("length:" + file.length());
		System.out.println("lastModified:" + file.lastModified());

		// 1432518063391
		Date d = new Date(1432518063391L);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String s = sdf.format(d);
		System.out.println(s);
	}
}</span>
执行结果是:


7、高级获取功能

public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
后者功能更为强大一点,因为返回的是File对象,所以可以得到File的各种属性。


8.文件名称过滤器——FilenameFilter

需求:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称
public String[] list(FilenameFilter filter)
public File[] listFiles(FilenameFilter filter)

示例代码:

<span style="font-size:18px;">public class FileDemo {
	public static void main(String[] args) {
	
		//封装e盘
		File file=new File("e:\\");	
		// 获取该目录下所有文件或者文件夹的String数组
		String[] list = file.list(new FilenameFilter() {			
			@Override
			public boolean accept(File dir, String name) {
				//如果是文件并且是以.jpg结尾的,返回true,一旦返回true,name就会被放进String数组中,
				return new File(dir, name).isFile() && name.endsWith(".jpg");
			}
		});
		for (String string : list) {
			System.out.println(string);
		}
	}
}</span>
虽然普通的方式也能实现,这样看起来,代码更加优雅,现在我们来看看list(FilenameFilter filter)的源码
<span style="font-size:18px;">public String[] list(FilenameFilter filter) {
        String names[] = list();
        if ((names == null) || (filter == null)) {
            return names;
        }
        List<String> v = new ArrayList<>();
        for (int i = 0 ; i < names.length ; i++) {
            if (filter.accept(this, names[i])) {
                v.add(names[i]);
            }
        }
        return v.toArray(new String[v.size()]);
 }</span>

二、IO相关操作

    IO因为体系过于庞大,这里并不面面俱到,捡其重点来说。上面简单说了一下File的使用,File的读取,写入,复制。相信都是我们经常使用的功能。谈起IO流,首先我们要对它有个大致的认识,也就是IO的分类,请看下面:
A:按流向分
输入流 读取数据
输出流 写出数据
B:按数据类型
字节流
字节输入流
字节输出流
字符流
字符输入流
字符输出流

      如果你不知道什么是字节流,什么是字符流,我告诉你,如果电脑记事本可以打开的并且可以看得懂的,那就是可以用字符流操作的文件,当然也可以用字节流来操作,如果电脑记事本能打开,但是我们看不懂的,那就是用字节流来操作的文件,比如MP3文件、JPG文件等,现在我们来看看IO是怎么来操作File的。

1、字节流操作文件

1.1、FileOutputStream写出数据

A:操作步骤
a:创建字节输出流对象
b:调用write()方法
c:释放资源

B:示例代码:
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("hello".getBytes());
fos.close();

1.2、FileInputStream读取数据

FileInputStream读取数据
A:操作步骤
a:创建字节输入流对象
b:调用read()方法
c:释放资源

B:代码体现:
FileInputStream fis = new FileInputStream("fos.txt");
//方式1,我们一次读取一个字节
int by = 0;
while((by=fis.read())!=-1) {
System.out.print((char)by);
}
//方式2  我们一次读取一个字节数组
byte[] bys = new byte[1024];
int len = 0;
while((len=fis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
fis.close();

1.3、四种方式复制文件效率比较

FileInputStream、FileOutputStream这两个类我们称之为基本字节流,相对于基本字节流,IO中还有高效字节流BufferedInputStream、BufferedOutputStream 
看完了这个,那么问题来,哪种方式好呢?
下面我们来看一个例子:
需求:把G:\IO流(IO流小结图解).avi复制到当前项目目录下的copy.avi中
 字节流四种方式复制文件:
 * 基本字节流一次读写一个字节
 * 基本字节流一次读写一个字节数组
 * 高效字节流一次读写一个字节
 * 高效字节流一次读写一个字节数组

G:\IO流(IO流小结图解).av的信息如下:


示例代码:

<span style="font-size:18px;">public class CopyAVI {
	public static void main(String[] args) throws IOException {
		long start = System.currentTimeMillis();
		 method1("G:\\IO流(IO流小结图解).avi", "copy1.avi");
		 //method2("G:\\IO流(IO流小结图解).avi", "copy2.avi");
	        //method3("G:\\IO流(IO流小结图解).avi", "copy3.avi");
		//method4("G:\\IO流(IO流小结图解).avi", "copy4.avi");
		long end = System.currentTimeMillis();
		System.out.println("共耗时:" + (end - start) + "毫秒");
	}

	// 高效字节流一次读写一个字节数组:
	public static void method4(String srcString, String destString)throws IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcString));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destString));
		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = bis.read(bys)) != -1) {
			bos.write(bys, 0, len);
		}

		bos.close();
		bis.close();
	}

	// 高效字节流一次读写一个字节:
	public static void method3(String srcString, String destString)throws IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcString));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destString));

		int by = 0;
		while ((by = bis.read()) != -1) {
			bos.write(by);

		}
		bos.close();
		bis.close();
	}

	// 基本字节流一次读写一个字节数组
	public static void method2(String srcString, String destString)throws IOException {
		FileInputStream fis = new FileInputStream(srcString);
		FileOutputStream fos = new FileOutputStream(destString);

		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = fis.read(bys)) != -1) {
			fos.write(bys, 0, len);
		}
		fos.close();
		fis.close();
	}

	// 基本字节流一次读写一个字节
	public static void method1(String srcString, String destString)throws IOException {
		FileInputStream fis = new FileInputStream(srcString);
		FileOutputStream fos = new FileOutputStream(destString);
		int by = 0;
		while ((by = fis.read()) != -1) {
			fos.write(by);
		}
		fos.close();
		fis.close();
	}
}</span>
执行结果:

方法一执行:

方法二执行:

方法三执行:

方法四执行:

四种方式的性能差异,通过这个执行结果,想必大家也知道了 ,所以在实际开发中选择哪一个来操作文件,相信大家已经有了选择了,反正我是喜欢用方法四!!

2、字符流操作文件

      大家可能会问,操作文件已经有了字节流,为什么还要说字符流呢,哎,谁叫咱们是中国人呢,汉字比较复杂,一个汉字站了两个字节,所以直接用字符流操作不够方便所以就有了字符流。我们来看看字符流的体系结构。

 2.1字符流体系结构  

   |--字符流
|--字符输入流
Reader
int read():一次读取一个字符
int read(char[] chs):一次读取一个字符数组

|--InputStreamReader
|--FileReader
|--BufferedReader
String readLine():一次读取一个字符串
|--字符输出流
Writer
void write(int ch):一次写一个字符
void write(char[] chs,int index,int len):一次写一个字符数组的一部分

|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
void newLine():写一个换行符
void write(String line):一次写一个字符串


       字符流的读写是由基类Reader和Writer来完成的,它们各有两个子类来帮助我们来操作文件。Reader类的子类BufferedReader与Writer的子类BufferedWriter,我们一定可以猜到这是高效字符流操作文件使用的!那么,Reader类的子类InputStreamReader与Writer的子类OutputStreamWriter是干什么的呢?从类的名称来来看,前面是字节的,后面是字符的,我告诉你,这两个类就是转换流,把字节流转换成字符流,那么这有什么用呢?-----键盘录入!!!一会你们就知道了。。。。。注意OutputStreamWriter还有子类FileWriter,InputStreamReader还有子类FileReader。


2.1、字符流操作文件

我们先看一个字符流操作文件的例子。
需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

 数据源:
a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader
 目的地:
b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter -- BufferedWriter

示例代码:

<span style="font-size:18px;">public class CopyFileDemo {
	public static void main(String[] args) throws IOException {
		// 封装数据源
		BufferedReader br = new BufferedReader(new FileReader("a.txt"));
		// 封装目的地
		BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

		// 两种方式其中的一种一次读写一个字符数组,当然此处你也可以一次读取一个字节的方法
		// char[] chs = new char[1024];
		// int len = 0;
		// while ((len = br.read(chs)) != -1) {
		// 	bw.write(chs, 0, len);
		// 	bw.flush();
		// }
		
		// 还有一种方式读写数据,这就是BufferedWriter、BufferedReader的强大之处。。。。
		String line = null;
		//下面三句话,我习惯连着写,写入、换行、刷新,动作相当连贯有木有啊!!!!!!
		 while ((line = br.readLine()) != null) {
			 bw.write(line);
		     bw.newLine();
			 bw.flush();
		}
		
		// 释放资源
		bw.close();
		br.close();
	}
}</span>
代码解读: bw.newLine();这句话的意思是换行,调用的效果和我们写“\r\n”是一样的,但是newLine可以夸平台的,这就是区别!
           readLine()这个方法有点厉害,因为它一次读一行!!!
博客写到这里,我们发现,复制文件文件起码有5种方式,前面所讲的1.基本字节流一次读写一个字节、2.基本字节流一次读写一个字节数组、3.高效字节流一次读写一个字节、4.高效字节流一次读写一个字节数组共4种,再加上上面的一种,共5种,而且第五种是最好的,个人感觉。。。。

3、IO编程实战

3.1、复制单级文件夹

/*
 * 需求:复制指定目录下的指定文件,并修改后缀名。
 * 指定的文件是:.java文件。
 * 指定的后缀名是:.txt
 * 指定的目录是:txt
 * 数据源:G:\designModel
 * 目的地:G:\txt
 * 
 * 分析:
 * A:封装目录
 * B:获取该目录下的java文件的File数组
 * C:遍历该File数组,得到每一个File对象
 * D:把该File进行复制
 * E:在目的地目录下改名
 */

 * 数据源:G:\designModel如下图所示:



 示例代码:

<span style="font-size:18px;">public class CopyFolder {

	public static void main(String[] args) throws IOException {
		 //A:封装目录
	     File srcFolder=new File("G:\\designModel");
	     //封装目的地
	     File destFolder=new File("G:\\myNote");
	     //如果目的地文件不存在,就创建一个
	     if(!destFolder.exists()){
	    	 destFolder.mkdir();
	     }
	     //B:获取该目录下的java文件的File数组     
	     File[] srcFiles = srcFolder.listFiles(new FilenameFilter() {		
			@Override
			public boolean accept(File dir, String name) {
				// 文件过滤器,得到.java文件,去除其他类型的文件
				return new File(dir,name).isFile()&&name.endsWith(".java");
			}
		});
	     
	     // C:遍历该File数组,得到每一个File对象
	     
	      for (File file : srcFiles) {
	    	  String name = file.getName();
	    	  File newFile=new File(destFolder,name);
			  copyFile(file,newFile);
		  }
	      
	  	  //E:在目的地目录下改名
	      for (File file :destFolder.listFiles()) {
			
	    	  String name = file.getName();
	    	  String newName = name.replace(".java", ".txt");
	    	  File newFile=new File(destFolder,newName);
			  file.renameTo(newFile);
		}
	      
	}

		//	D:把该File进行复制
	private static void copyFile(File file, File newFile) throws IOException {
		
		BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));
		BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(newFile));    
		byte [] bys=new byte[1024];
		int len=0;
		while((len=bis.read(bys))!=-1){
			bos.write(bys,0,len);
		}
		//关闭资源
		bis.close();
		bos.close();
	}
}</span>
执行结果:



3.2、复制多级文件夹

思路分析
  数据源:G:\\
  目的地:G:\\


    A:封装数据源File
    B:封装目的地File
    C:判断该File是文件夹还是文件
  a:是文件夹
                 就在目的地目录下创建该文件夹
         获取该File对象下的所有文件或者文件夹File对象
         遍历得到每一个File对象
           回到C
           b:是文件
          复制(字节流)

示例代码:

<span style="font-size:18px;">public class CopyFolders{
	public static void main(String[] args) throws IOException {
		// 封装数据源File
		File srcFile = new File("G:\\");
		// 封装目的地File
		File destFile = new File("E:\\");
		// 复制文件夹的功能
		copyFolder(srcFile, destFile);
	}

	private static void copyFolder(File srcFile, File destFile)throws IOException {
		// 判断该File是文件夹还是文件
		if (srcFile.isDirectory()) {
			// 文件夹
			File newFolder = new File(destFile, srcFile.getName());
			newFolder.mkdir();
			// 获取该File对象下的所有文件或者文件夹File对象
			File[] fileArray = srcFile.listFiles();
			for (File file : fileArray) {
				copyFolder(file, newFolder);
			}
		} else {
			// 文件
			File newFile = new File(destFile, srcFile.getName());
			copyFile(srcFile, newFile);
		}
	}

	//复制文件
	private static void copyFile(File srcFile, File newFile) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = bis.read(bys)) != -1) {
			bos.write(bys, 0, len);
		}
		bos.close();
		bis.close();
	}
}</span>


3.3 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件

思路分析:
A:创建学生类
B:创建集合对象
    因为要排序,所以用TreeSet<Student>
C:键盘录入学生信息存储到集合
D:遍历集合,把数据写到文本文件


<span style="font-size:18px;">public class Student {
	// 姓名
	private String name;
	// 语文成绩
	private int chinese;
	// 数学成绩
	private int math;
	// 英语成绩
	private int english;

	//构造方法和setter/getter方法省去了。。。。。。。。  
}</span>
<span style="font-size:18px;">public class StudentIO {
	public static void main(String[] args) throws IOException {
		// 创建集合对象(采用匿名内部类的方式,创建带有比较器的集合对象)
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				int num = s2.getSum() - s1.getSum();
				int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
				int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
				int num4 = num3 == 0 ? s1.getName().compareTo(s2.getName()): num3;
				return num4;
			}
		});

		// 键盘录入学生信息存储到集合
		for (int x = 1; x <= 5; x++) {
			Scanner sc = new Scanner(System.in);
			System.out.println("请录入第" + x + "个的学习信息");
			System.out.println("姓名:");
			String name = sc.nextLine();
			System.out.println("语文成绩:");
			int chinese = sc.nextInt();
			System.out.println("数学成绩:");
			int math = sc.nextInt();
			System.out.println("英语成绩:");
			int english = sc.nextInt();

			// 创建学生对象
			Student s = new Student();
			s.setName(name);
			s.setChinese(chinese);
			s.setMath(math);
			s.setEnglish(english);

			// 把学生信息添加到集合
			ts.add(s);
		}

		// 遍历集合,把数据写到文本文件
		BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));
		//以下三行代码连写
		bw.write("学生信息如下:");
		bw.newLine();
		bw.flush();
	    bw.write("姓名\t语文成绩\t数学成绩\t英语成绩");
		bw.newLine();
		bw.flush();
		for (Student s : ts) {
			StringBuilder sb = new StringBuilder();
			sb.append(s.getName()).append("\t").append(s.getChinese())
					.append("\t").append(s.getMath()).append("\t")
					.append(s.getEnglish());
			bw.write(sb.toString());
			bw.newLine();
			bw.flush();
		}
		// 释放资源
		bw.close();
		System.out.println("学习信息存储完毕");
	}
}</span>
输入:


执行结果:


好啦,如果上面的例子可以弄懂,IO就基本没有什么问题啦,哈哈。。。


  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值