0801(021天 输入输出流01)

本文详细介绍了Java中的IO流,包括同步阻塞、非阻塞和异步非阻塞的区别,字节流与字符流的分类,以及节点流与过滤流的概念。重点讲解了File类的使用,如构造文件对象、判断文件类型、文件操作方法等,并给出了文件后缀过滤的实现。此外,还展示了如何利用装饰器模式扩展流的功能,以及如何实现文件的复制。
摘要由CSDN通过智能技术生成

0801(021天 输入输出流01)

每日一狗(田园犬西瓜瓜)

在这里插入图片描述

输入输出流

1. 基本概念

在这里插入图片描述

1.1 流的分类:

按照阻塞

  • BLO同步阻塞:数据的读取写入必须阻塞在一个线程内等待其完成。(蹲着等水烧开)
  • NIO同步非阻塞:一个线程不断的轮询每个输入输出的状态改变,如果有状态发生了改变,则进 行下一步的操作。(放在炉子上去干其他事了,时不时回来看一下)
  • ALO异步非阻塞:无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系 统会通知对应的线程来处理。(多个水壶,开了后水壶通知我)

按照传输单位:

(Java具备平台无关性,这里的字节是指8位,字符是16位、使用桥接流可以实现两个流之间的转换)

  • 字节流:是从InputStream/OutputStream派生出来,以字节为基本处理单位,一般用于操作二进 制数据,字节次序是有意义的
  • 字符流:从Reader/Writer派生出来的,以16位的Unicode码表示字符为基本处理单位,一般用 于操作字符数据

按照功能区分:

  • 节点流:负责数据源和程序之间建立连接,结点流对特定的地方读写
  • 过滤流:用于给节点增加功能,过滤流使用结点流进行输入/输出并添加附加功能

按照流方向分为输入流和输出流

注意:I/O流是一类很宝贵的资源,使用完后必须调用close()方法关闭流并释放资源。在关闭流时只用关 闭最外层的流

1.2 适用场景

  • BLO同步阻塞:连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用 中,JDK1.4以前的唯一选择,但程序直观简单易理解
  • NIO同步非阻塞:适用于连接数目比较多且连接比较短的架构,比如聊天服务器,并发局限于应用中,编程比较 复杂,JDK1.4开始支持
  • ALO异步非阻塞:适用于连接数目多且连接比较长的架构,比如相册服务器,充分调用OS参与并发操作,编 程比较复杂,JDK7开始支持。

1.3 扩展功能的方式

过滤流的构造方式是以其他流位参数构造(这样的设计模式称为装饰模式)。Java的IO流使用装饰器模 式,将IO流分成底层节点流和上层处理流。其中节点流用于和底层的物理存储节点直接关联。过滤流是 连接在已存在的流之上,通过对数据的处理为程序提供更为强大的读写功能。

  • 继承:强耦合

  • 装饰器模式(结构模式)、适配器模式(类似于转接头)

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。

装饰器模式中的四种角色:被装饰对象、装饰对象、装饰器Decorator、公共接口或抽象类

在这里插入图片描述

public class Test2 {
	public static void main(String[] args) {
		IShape s = new Circle(10); // 实际工作的对象,就是被装饰的对象
		IShape s2 = new Red(s); // 装饰对象
		s2.draw();
	}
}

//公共接口
interface IShape {
	void draw();
}

//被装饰类
class Circle implements IShape {
	private double r;

	public Circle(double r) {
		this.r = r;
	}

	public void draw() {
		System.out.println("绘制一个半径为" + r + "的圆");
	}
}


//装饰器Decorator
abstract class Decorator implements IShape {
	private IShape shape; // 被装饰对象

	public Decorator(IShape shape) {
		this.shape = shape;
	}

	public void draw() {
		shape.draw();
	}
}

//装饰类
class Red extends Decorator {

	public Red(IShape shape) {
		super(shape);
	}

	@Override
	public void draw() {
		System.out.println("准备红色!!");
		super.draw();
		System.out.println("恢复系统默认的颜色");
	}
}

2. File类

指代一个具体的文件或这文件夹

  • 类File提供了一种与机器无关的方式来描述一个文件对象的属性
  • 对于目录,Java把它简单的处理为一种特殊的文件,即文件名的列表
  • java.io.File用于封装和平台无关的文件夹和文件夹对象,例如获取一个文件的字节数。这个写法是 针对windows平台的,如果使用mac或者linux平台,则需要使用
  • 通过类File中提供的方法,可以得到文件或者目录的描述信息,包括名称、所在路径、可读性等,还可以生成新的文件、目录、改变文件名、删除文件、列出一个目录中所有的文件或者与某个模式匹配的文件等

2.1 基本使用

构造一个文件或文件夹对象

相对路径绝对路径

File f1 = new File("test");
File f2 = new File("F:\\lanou-eclipse-workspace\\20220801\\test");
System.out.println(f1.getAbsolutePath());
System.out.println(f2.getAbsolutePath());

2.2 一些方法

公用

  • getAbsolutePath() //获取对象的绝对路径
  • isFile() //判定是不是一个文件
  • isDirectory() //判定是不是一个文件夹
  • exists() // 判定存不存在
  • delete():boolean 删除文件。也可以删除文件夹,要求文件夹为空,不能有文件和子文件夹
  • renameTo(File):boolean修改名称,可以修改文件名和文件夹名称

文件操作

  • 根据对象创建文件
  • length() // 获取文件长度(字节数量)
  • createNewFile() // 根据文件对象创建其对应的文件

文件夹操作

  • mkdirs():boolean自动创建多级文件夹

  • listFiles():File[]获取当前文件夹的所有子文件信息,子文件为File对象

  • list():String[]获取当前文件夹的所有子文件信息,返回字符串信息

类操作

  • File.separator:当前操作系统的路径分隔符

  • static createTempFile(String prefix, string suffix):根据路径创建临时文件 File 这个临时文件名称会有随机内容

  • 删除创建的临时文件夹(deleteOnExit():void退出系统时自动删除)

  • static listRoots():File[]列出系统的所有的根路径

2.3 练习题

  1. 获取指定文件目录下的所有文件(递归)
package com.yang2;

import java.io.File;

public class T02 {

	public static void main(String[] args) {
		show(new File("src"));

	}

	public static void show(File file) {
		if (file.exists()) {
			if (file.isDirectory()) {
				for (File f : file.listFiles()) {
					show(f);
				}
				System.out.println("文件夹:" + file.getAbsolutePath());
			} else {
				System.out.println("文件" + file.getAbsolutePath() + " 大小:" + file.length());
			}

		}
	}
}

在这里插入图片描述

实现层次结构(传入一个字符表示层数)效果如图所示

在这里插入图片描述

  1. 要求显示整个文件夹中的所有文件数量,文件占用大小(广度优先)
package com.yang2;

import java.io.File;

public class T04 {

	public static void main(String[] args) {
		getBig(new File("src"), "|");
		System.out.println("文件数量:" + num);
		System.out.println("文件大小" + big);
	}

	private static double big = 0;
	private static int num = 0;

	public static void getBig(File f, String s) {
		if (f.exists()) {
			if (f.isDirectory()) {
				if (f.listFiles() != null && f.listFiles().length > 0) {
					System.out.println(s + f.getName());
					for (File tmpf : f.listFiles()) {
						getBig(tmpf, s + "----");
					}
				}
			} else if (f.isFile()) {
				System.out.println(s + f.getName());
				num++;
				big += f.length();
			}
		}
	}
}

在这里插入图片描述

  1. 要求删除指定文件夹(深度优先)
package com.yang2;

import java.io.File;

public class T05 {

	public static void main(String[] args) {
		delete(new File("D:\\src"));
	}

	public static void delete(File file) {
		System.out.println(file.getAbsolutePath());

		if (file.exists()) {
			if (file.isDirectory()) {
				File[] files = file.listFiles();
				if (files != null && files.length > 0) {
					for (File f : files) {
						delete(f);
					}
				}
				file.delete();

			} else if (file.isFile()) {
				file.delete();
			}

		}
	}

}

2.4 文件后缀过滤

过滤文件下一层目录中指定文件后缀名的文件对象

  • 匿名内部类,实现FilenameFilter类中的accept方法,当文件名后缀为正确时返回true,否则返回false
package com.yan3;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;

//文件过滤
public class Test3 {
	public static void main(String[] args) {
		File f = new File("d:/data");
		if (f.exists()) {
			File[] fs = f.listFiles(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					File temp = new File(dir, name);
					if (temp != null && temp.isFile()) {
						if (name.endsWith(".txt"))
							return true;
					}
					return false;
				}
			});
			System.out.println(Arrays.toString(fs));
		}
	}
}

lanbda表达式

package com.yan3;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;

//文件过滤
public class Test3 {
	public static void main(String[] args) {
		File f = new File("d:/data");
		if (f.exists()) {
			File[] fs = f.listFiles(()->{
				public boolean accept(dir, name) 
                    return name!=null && name.endsWith(".ini");
			});
			System.out.println(Arrays.toString(fs));
		}
	}
}

2.5 Path和Paths以及Files工具方法

1、Path接口代表一个平台无关的平台路径

2、Files提供工具方法操作文件

  • 复制文件件Files.copy(Paths.get("T1.java"), new FileOutputStream("a.txt"))
  • 一次性读取文件的所有行List lines=Files.readAllLines()

3、Paths提供创建Path的静态工厂方法

3. 字节流

3.1 InputStream

读取并输出文件的所有内容

  • int read() :读取一个字节,返回的是整数
  • int read(byte[]) :一次性读取byte数组大小的字节,返回值为末端索引,一般是8192
  • int read(byte[],int1,int2) :从byte[]数组的int1开始写到int2填满
  • void close()关闭流
  • int available()报告流中直接可读的字节数
  • skip(long)跳过流中指定的字节

3.2 OutputStream

  • write(int):写入字符
  • write(byte[]):写入字节数组
  • void write(byte[],int1,int2):将byte[]中int1到int2中的数据写到指定文件中
  • write(byte[], boolean append):是否支持追加写

键盘录入存入本地文件中

package com.yang3;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Scanner;

public class T03 {

	public static void main(String[] args) throws Exception {
		try (OutputStream os = new FileOutputStream("D:\\桌面\\test.txt")) {
			Scanner sc = new Scanner(System.in);
			while (true) {

				String lines = sc.nextLine();
				if ("quit".equals(lines)) {
					break;
				}
				byte[] arr = lines.getBytes();
				for (int i = 0; i < arr.length; i++) {
					os.write(arr[i]);
				}
				os.write('\n');
			}
			sc.close();
		}
	}

}

在这里插入图片描述

3.3 实现文件夹的拷贝

package com.yang3;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class 文件拷贝 {

	public static void main(String[] args) {
		File source = new File("D:\\桌面\\20220801");
		File target = new File("D:\\桌面\\copy");
		copy(source, target);
	}

	public static void copy(File source, File target) {
		if (source.exists()) {
			File targetTmp;
			targetTmp = new File(target, source.getName());

			if (source.isDirectory()) {
				targetTmp.mkdirs();
//				System.out.println(targetTmp.getAbsolutePath());
				for (File f : source.listFiles()) {
					copy(f, targetTmp);
				}
			} else if (source.isFile()) {
//				System.out.println(targetTmp.getAbsolutePath());
				try {
					copyFile(source, targetTmp);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

		}
	}

	public static void copyFile(File source, File target) throws Exception {
		System.out.println(source.getAbsolutePath() + "-->" + target.getAbsolutePath());
		try (InputStream in = new FileInputStream(source.getAbsoluteFile());
				OutputStream out = new FileOutputStream(target.getAbsoluteFile());) {

			byte[] arr = new byte[8192];
			int len = 0;
			while ((len = in.read(arr)) > 0) {
				out.write(arr);
			}
		}
	}
}

在这里插入图片描述


扩展小芝士

  • java并不保证删除成功,具体的文件操作是依靠操作系统实现的

  • 所有的文件操作都不保证

  • 一般来说:

    • 接口:定义规范(能实现啥方法)
    • 抽象类:定义公共的方法
    • 实现类:封装单独属性
  • 解除对象和方法的耦合性

    • new 子 声 父 可以解除对象和逻辑结构的强耦合性
    • 在传参的时候尽可能传递抽象的东西,只要方法逻辑一致就可以不用重载实现多态
  • java中找不到东西 返回-1,异常情况返回-1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值