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 练习题
- 获取指定文件目录下的所有文件(递归)
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());
}
}
}
}
实现层次结构(传入一个字符表示层数)效果如图所示
- 要求显示整个文件夹中的所有文件数量,文件占用大小(广度优先)
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();
}
}
}
}
- 要求删除指定文件夹(深度优先)
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