I/O框架

1. 什么是流


  • 概念:内存与存储设备之间传输数据的通道

  • 水借助管道传输;数据借助流传输

2. 流的分类


1. 按方向【重点】

  • 输入流:将<存储设备>中的内容读到<内存>中

  • 输出流:将<内存>中的内容写到<存储设备>中

2. 按单位

  • 字节流:以字节为单位,可以读写所有数据

  • 字符流:以字符为单位,只能读写文本数据

3. 按功能

  • 节点流:具有实际传输数据的读写功能

  • 过滤流:在节点流的基础之上增强功能

3. 字节流


3.1 字节流的父类(抽象类)

1. InputStream

常用方法:

方法 功能
public int read() 从输入流读取数据的下一个字节
public int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区
public int read(byte[] b, int off, int len) 从输入流读取最多len字节的数据到一个字节数组

2. OutputStream

常用方法:

方法 功能
public void write(int n) 将指定的字节写入此输出流
public void write(byte[] b) 将b.length字节从指定的字节数组写入此输出流
public void write(byte[] b, int off, int len) 从指定的字节数组写入len个字节,从偏移off开始输出到此输出流

3.2 文件字节流

1. 文件输入流:FileInputStream

FileInputStream的使用

public static void main(String[] args) throws Exception{
  //1.创建FileInputStream,并指定路径
  FileInputStream file = new FileInputStream("d:\\aaa.txt");
  
  //2.读取文件
  //2.1 单个字节读取
  int data = 0; //指读取的个数
  while ((data = file.read()) != -1){ //-1指读到最后读完了返回-1
    System.out.println((char) data);
  }

  //2.2 一次读取多个字节
  byte[] bytes = new byte[10];
  int count = 0;
  while ((count = file.read(bytes)) != -1 ){
    //bytes指这个数组的值,0是指从length=0开始读取流,count指到count时候停止读取,实际读取的个数
    System.out.println(new String(bytes,0,count));
  }

  //3.关闭
  file.close();
}

2. 文件输出流:FileOutputStream

FileOutputStream的使用

public static void main(String[] args) throws Exception{
  //1.创建文件字节输出流  指定路径写入
  FileOutputStream file = new FileOutputStream("d:\\bbb.txt",true); //true表示不覆盖原先的,接着后面写

  //2.写入文件 :单个字节写入
  file.write(97); //写入字符a
  file.write('b');
  file.write('c');
  file.write('d');

  //多个字节写入
  String s = "helloworld";
  file.write(s.getBytes());

  //3.关闭
  file.close();
}

小案例:使用文件字节流FileInputStream和FileOutputStream实现文件的复制

public static void main(String[] args) throws Exception{
  //1.创建流
  //1.1 文件输入流
  FileInputStream in = new FileInputStream("文件路径");
  //1.2 文件输出流
  FileOutputStream out = new FileOutputStream("文件路径");

  //2.边读边写
  byte[] bytes = new byte[1024];
  int count = 0;
  while ((count = in.read(bytes)) != -1){
    out.write(bytes,0,count);
  }

  //3.关闭
  in.close();
  out.close();
}

3.3 字节缓冲流

缓冲流:BufferedInputStream 和 BufferedOutputStream

作用:

  1. 提高IO效率,减少访问磁盘次数
  2. 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close

BufferedInputStream缓冲流的使用

public static void main(String[] args) throws Exception{
  //1.创建BufferedInputStream
  FileInputStream fis = new FileInputStream("文件路径");//节点流 数据一般从内存读取
  BufferedInputStream bis = new BufferedInputStream(fis); //缓冲流 通过节点流读取,不用每次从内存读取

  //2.读取
  int count = 0;
  while ((count = bis.read()) != -1){
    System.out.println((char) count);
  }

  //用自己创建的缓冲流读取
  byte[] buf = new byte[1024];
  int data = 0;
  while ((data = bis.read(buf)) != -1){
    System.out.println(new String(buf,0,data));
  }

  //3.关闭  关闭缓冲流即可
  bis.close();
}

BufferedOutputStream缓冲流的使用

public static void main(String[] args) throws Exception{
  //1.创建BufferedOutputStream缓冲区
  FileOutputStream fos = new FileOutputStream("d:\\ddd.txt");
  BufferedOutputStream bos = new BufferedOutputStream(fos);

  //2.写入文件
  for(int i = 0; i < 10; i++) {
    bos.write("helloworld\r\n".getBytes()); //写入缓冲区 \r\n:换行
    bos.flush(); //刷新到硬盘
  }

  //3.关闭:内部调用flush()方法
  bos.close();

}

3.4 对象流


对象流:ObjectInputStream 和 ObjectOutputStream

作用:

  1. 增强了缓冲区功能
  2. 增强了读写8种基本数据类型和字符串的功能
  3. 增强了读写对象的功能
    • readObject() 从流中读取一个对象
    • writeObject(Object obj) 向流中写入一个对象

使用流传输对象的过程称为序列化、反序列化

从内存中写入文件到硬盘中的过程称之为序列化,反之为反序列化

3.5 序列化与反序列化

3.5.1 序列化

使用ObjectOutputStream实现序列化:要求序列化的类必须要实现Serializable接口

1.创建一个学生类

public class Student implements Serializable {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

2.使用ObjectOutputStream实现序列化

public static void main(String[] args) throws Exception{
  //1.创建对象流objectoutputStream
  FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
  ObjectOutputStream oos = new ObjectOutputStream(fos);

  //2.序列化(写入操作)
  Student s = new Student("张三", 20);
  oos.writeObject(s);

  //3.关闭
  oos.close();

}

3.5.2 反序列化

使用ObjectInputStream实现反序列化:读取重新构成对象

public static void main(String[] args) throws Exception{
  // 1. 创建对象流
  FileInputStream fis = new FileInputStream("d:\\stu.bin");
  ObjectInputStream ois = new ObjectInputStream(fis);
  // 2. 读取文件(反序列化)
  Student s = (Student)ois.readObject();
  System.out.println(s.toString);
  // 3. 关闭
  ois.close();    
}

注意事项:

  1. 序列化类要想序列化必须实现Serializable接口
  2. 序列化类中的对象属性(即类中的其他类)也要求实现Serializable接口
  3. 序列化版本号ID(serialVersionUID),保证序列化的类和反序列化的类是同一个类
  4. 使用transient修饰属性,这个属性就不能序列化
  5. 静态属性不能序列化
  6. 序列化多个对象,可以借助集合来实现

4. 字符编码


  • ISO-8859-1:收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号

  • UTF-8:针对Unicode码表的可变长度字符编码

  • GB2312:简体中文

  • GBK:简体中文、扩充

  • BIG5:台湾省,繁体中文

5. 字符流


5.1 字符流的父类(抽象类):

1. Reader:字符输入流

常用的方法:

方法 功能
public int read() 读一个字符
public int read(char[] c) 将字符读入数组
public int read(char[] b, int off, int len) 将字符读入数组的一部分

2. Writer:字符输出流

常用的方法:

方法 功能
public void write(int n) 写一个字符
public void write(String str) 写一个字符串
public void write(char[] c) 写一个字符数组

5.2 文件字符流

1. 文件字符输入流:FileReader

使用FileReader读取文件

public static void main(String[] args) throws Exception{
  //1.创建FileReader
  FileReader fr = new FileReader("d:\\aaa.txt");
  //2.读取
  //2.1 单个字符读取
  int data = 0;
  while ((data = fr.read()) != -1){
    System.out.print((char) data);
  }
  //2.2 一次读多个字符
  char[] buf = new char[10];
  int count = 0;
  while ((count = fr.read(buf)) != -1){
    System.out.println(new String(buf,0,count));
  }

  //3.关闭
  fr.close();
}

2. 文件字符输出流:FileWriter

使用FileWriter写入文件

public static void main(String[] args) throws Exception{
  //1.创建FileReader
  FileWriter fw = new FileWriter("d:\\ddd.txt");
  //2.写入文件
  for(int i = 0; i < 10; i++) {
    fw.write("中国加油\r\n");
    fw.flush();
  }
  //3.关闭
  fw.close();
}

小案例:使用字符流FileReader 和 FileWriter来复制文本文件

注意:

(1)字符流只能复制文本文件,不能复制图片或二进制文件

(2)使用字节流可以复制任意文件,因为计算机使用二进制存储文件

public static void main(String[] args) throws Exception{
  //1.创建字符流
  FileReader fr = new FileReader("d:\\ddd.txt");
  FileWriter fw = new FileWriter("d:\\eee.txt");
  //2.读写
  int data = 0;
  while ((data = fr.read()) != -1){
    fw.write(data);
    fw.flush();
  }
  //3.关闭
  fr.close();
  fw.flush();
}

5.3 字符缓冲流

缓冲流:BufferedReader 和 BufferedWriter

作用:

  1. 高效读写
  2. 支持输入换行符
  3. 可一次写一行、读一行

缓冲流BufferedReader的使用

public static void main(String[] args) throws Exception{
  //1.创建缓冲流BufferedReader
  FileReader fr = new FileReader("d:\\eee.txt");
  BufferedReader br = new BufferedReader(fr);
  //2.读取
  //2.1 第一种方式
  char[] buf = new char[1024];
  int count = 0;
  while ((count = br.read(buf)) != -1){
    System.out.println(new String(buf,0,count));
  }

  //2.2 第二种方式 一行一行地读取
  String s = null;
  while ((s = br.readLine()) != null){
    System.out.println(s);
  }
  //3.关闭
  br.close();
}

缓冲流BufferedWriter的使用

public static void main(String[] args) throws Exception{
  //1.创建缓冲流BufferedReader
  FileWriter fw = new FileWriter("d:\\eee.txt");
  BufferedWriter bw = new BufferedWriter(fw);
  //2.写入
  for(int i = 0; i < 10; i++) {
    bw.write("好好学习");
    bw.newLine(); //相当于换行符
    bw.flush();
  }
  //3.关闭
  bw.close();

}

6. 打印流


6.1 PrintWriter:

  • 封装了print() / println()方法 支持写入后换行
  • 支持数据原样打印
public static void main(String[] args) throws Exception{
  // 1 创建打印流
  PrintWriter pw = new PrintWriter("d:\\eee.txt");
  // 2 打印
  pw.println(12);
  pw.println(true);
  pw.println(3.14);
  pw.println('a');
  // 3 关闭
  pw.close();
}

7. 转换流(字节流与字符流的转换)


桥转换流: InputStreamReader / OutputStreamWriter

  • InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符

  • OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset

作用:

  1. 可将字节流转换为字符流

  2. 可设置字符的编码方式

使用InputStreamReader读取文件,可以指定编码方式

public static void main(String[] args) throws Exception{
  //1.创建InputStreamReader,并指定编码方式
  FileInputStream fis = new FileInputStream("d:\\eee.txt"); //需创建一个字节输入流
  InputStreamReader isr = new InputStreamReader(fis,"utf-8");
  //2.读取文件 单个字符读取
  int data = 0;
  while ((data = isr.read()) != -1){
    System.out.print((char) data);
  }
  //3.关闭
  isr.close();
}

使用OutputStreamReader写入文件,可以指定编码方式

public static void main(String[] args) throws Exception{
  //1.创建OutputStreamReader,并指定编码方式
  FileOutputStream fos = new FileOutputStream("d:\\eee.txt");//先创建一个字节输出流
  OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
  //2.写入文件
  for(int i = 0; i < 10; i++) {
    osw.write("中国加油\r\n");
    osw.flush();
  }
  //3.关闭
  osw.close();
}

8. File类


概念:代表物理盘符中的一个文件或者文件夹

常用的方法:

方法 功能
createNewFile() 创建一个新文件
mkdir() 创建一个新目录
delete() 删除文件或空目录
exists() 判断File对象表示的文件或目录是否存在
getAbsolutePath() 获取文件的绝对路径
getName() 取得名字
getParent() 获取文件/目录所在的目录
isDirectory() 是否是目录
isFile() 是否是文件
length() 获得文件的长度
listFiles() 列出目录中的所有内容
renameTo() 修改文件名为

File类的使用

(1)分隔符

(2)文件操作

(3)文件夹操作

(4)FileFilter接口的使用

1.分隔符的使用

System.out.println("路径分隔符"+ File.pathSeparator); //输出 路径分隔符;
System.out.println("名称分隔符"+File.separator); //输出 名称分隔符\

2.文件操作

//(1)创建文件 createNewFile()
File file = new File("d:\\eee.txt");

if (!file.exists()){ //判断是否存在
  boolean b = file.createNewFile();
  System.out.println("创建结果:"+b);
}

//(2)删除文件
//第一种:直接删除
file.delete();
//第二种:使用jvm退出时删除
file.deleteOnExit();

//(3)获取文件信息
System.out.println("获取文件的绝对路径:"+file.getAbsolutePath());
System.out.println("获取路径:"+file.getPath());
System.out.println("获取文件名称:"+file.getName());
System.out.println("获取父目录:"+file.getParent());
System.out.println("获取文件长度:"+file.length());
System.out.println("获取文件创建时间:"+new Date(file.lastModified()).toLocaleString());

//(4)判断
System.out.println("判断是否可写:"+file.canWrite());
System.out.println("判断是否是文件:"+file.isFile());
System.out.println("判断是否隐藏:"+file.isHidden());

3.文件夹操作

//(1)创建文件夹
File file = new File("d:\\aaa\\bbb\\ccc");
if (!file.exists()){
  //file.mkdir(); //只能创建单级目录
  file.mkdirs();  //创建多级目录
}
//(2)删除文件夹
//第一种:直接删除(只能删除最里面的目录,并且只能是空目录)
file.delete();
//第二种:使用jvm退出时删除
file.deleteOnExit();

//(3)获取文件夹信息
System.out.println("获取绝对路径:"+file.getAbsolutePath());
System.out.println("获取路径:"+file.getPath());
System.out.println("获取文件名称:"+file.getName()); //获取的是最里层的目录名称
System.out.println("获取父目录:"+file.getParent());
System.out.println("获取文件创建时间:"+new Date(file.lastModified()).toLocaleString());

//(4)判断
System.out.println("判断是否是文件夹:"+file.isDirectory());
System.out.println("判断是否隐藏:"+file.isHidden());

//(5)遍历文件夹 list()
File dir = new File("d:\\office");
String[] list = dir.list();
for (String s : list) {
  System.out.println(s);
}

4.FileFilter接口

接口:public interface FileFilter

其方法:boolean accept(File pathname)

当调用File类中的listFiles()方法时,支持传入FileFilter接口实现类,对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中

FileFilter接口的使用

File[] files = dir.listFiles(new FileFilter() {
  @Override
  public boolean accept(File pathname) {
    if (pathname.getName().endsWith(".JPG")){ //选择以.JPG为后缀的文件输出
      return true;
    }
    return false; //其他不输出
  }
});
for (File file1 : files) {
  System.out.println(file1);
}

递归遍历文件夹

public class listDemo {
  public static void main(String[] args) {
    File f = new File("文件夹路径");
    lisDir(f);
  }
    
  public static void lisDir(File dir){
    File[] files = dir.listFiles();
    System.out.println(dir.getAbsolutePath());//获取绝对路径
    if (files != null && files.length > 0){ 
      for (File file : files) {
        if (file.isDirectory()){ //判断文件夹里是否还有文件夹
          lisDir(file); //递归
        }else {
          System.out.println(file.getAbsolutePath());
        }
      }
    }
  }
}

递归删除文件夹

public class listDemo {
  public static void main(String[] args) {
    File f = new File("文件夹路径");
    deleteDir(f);
  }
    
  public static void deleteDir(File dir){
    File[] files = dir.listFiles();
    if(files != null && files.length > 0){
      for(File file : files){
        if(file.isDirectory()){
          deleteDir(file); // 递归
        }else{
          // 删除文件
          System.out.println((file.getAbsolutePath() + "删除" + file.delete()));
        }
      }
    }
    System.out.println((dir.getAbsolutePath() + "删除" + dir.delete()));
  }
}

9. Properties


Properties:属性集合

特点:

  1. 存储属性名和属性值
  2. 属性名和属性值都是字符串类型
  3. 没有泛型
  4. 和流有关

Properties的使用

1. 创建集合

Properties pr = new Properties();

2. 添加数据

pr.setProperty("userName","张三");
pr.setProperty("age","20");
System.out.println(pr.toString()); //输出 {age=20, userName=张三}

3. 遍历

//3.1 使用keySet()
//3.2 使用entrySet()
//3.3 使用stringPropertyNames()
Set<String> pro = pr.stringPropertyNames();
for (String s : pro) {
  System.out.println(s+"---"+pr.get(s));
}

4. 和流有关的方法 :list()

//list()方法
PrintWriter printWriter = new PrintWriter("文件路径");
pr.list(printWriter);
printWriter.close();

5. store()方法:保存

FileOutputStream fos = new FileOutputStream("d:\\eee.properties");//扩展名一般写properties
pr.store(fos,"注释");
fos.close();

6. load()方法:加载

Properties pr2 = new Properties();
FileInputStream stream = new FileInputStream("d:\\eee.properties");
pr2.load(stream);
stream.close();
System.out.println(pr2.toString());
posted @ 2023-04-02 23:42  ·追·  阅读(14)  评论(0)    收藏  举报
/*鼠标跟随效果*/ //返回顶部 returnTop