第八章·Io流

Io流

文件流

文件与流

文件概念

属于文件的一种,与普通文件载体不同,文件是以硬盘为载体储存在计算机上的信息集合;是指存储在外部介质上的数据集合。可管理(增删改查),储存。


流概念

是指在计算机的输入/输出操作中各部件之间的数据流动,按照数据的传输方式分为

  • 输入流(InputStream)----用来读取数据的
  • 输出流(OutputStream)----用来写出数据的

IO是输出输入流的简写


流分类
  • 根据处理流的类型

    • **字符流:**基本单位(8位byte)的流
    • **字节流:**基本单位(16为Unicode)的流
  • 流向分类(以代码为中心)

    • 输入流(Input):从硬盘将数据读取到代码中,只读不写
    • 输出流(Output):从代码中将数据写入硬盘中,只写不读
  • 根据流的角色来分类

    • **节点流:**特定设备需要使用节点流来进行输出操作
    • **过虑流:**对一个已经存在的输入输出流功能进行强化,注意:一般不能单独使用,必须配合节点流来进行使用

常用Io流体系表
分类 字节输入流 字节输出入 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream

file类

  • file类是Java.io包中唯一代表磁盘文件本身的对象,也就是说,如果希望在程序中操作文件和目录,则都可以通过file类完成
  • file类定义了一些方法操作文件,可进行新建,删除,重命名文件和目录等。但file不能访问文件内容本身,如需访问则需要使用输出/输入流
Java 复制代码
package 流;

import java.io.File;

public class 检查文件 {
    public static void main(String[] args) {
        File file = new File("src/main/java/流/文件测试包/文件.txt");
        //获取名字
        String name = file.getName();
        System.out.println(name);
        //获取文件大小(单位是字节)
        long len = file.length();
        System.out.println(len+"字节");
        //是否可读可写
        boolean cr = file.canRead();
        boolean cw = file.canWrite();
        System.out.println("是否可读:"+cr);
        System.out.println("是否可写:"+cw);
        //是否隐藏
        boolean ih = file.isHidden();
        System.out.println("是否隐藏:"+ih);
    }
}

语法格式

Java 复制代码
File 文件名=new File("文件路径");

创建新文档

使用createNewFile()方法
Java 复制代码
package 流;

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

public class 创建文档 {
    public static void main(String[] args)throws IOException {
        File path=new File("src/main/java/流/文件测试包/文件1.txt");
        if(path.exists()){
            //exists:判断文件夹当中是否存在某个文档,返回值只能是booleane类型
            System.out.println("文档已经存在,重新命名");
        }
        else {
                path.createNewFile();//创建文档
                System.out.println("创建成功");
       		 }
    }
}

删除和判断文件/夹
Java 复制代码
package 流;
import java.io.File;
public class 判断_删除文件_夹 {
    public static void main(String[] args)  throws Exception {
        File path=new File("src/main/java/流/文件测试包/文件2.txt");
        if(path.exists()){
            //exists:判断文件夹当中是否存在某个文档
            System.out.println("文档已经存在,重新命名");
        }
        else {
            path.createNewFile();//createNewFile:创建文档
            System.out.println("创建成功");
        }

        //判断是否是文件:isFile   判断是否是文件夹:isDirectory
        System.out.println("判断是否是文件:"+path.isFile());
        System.out.println("判断是否是文件夹:"+path.isDirectory());

         //删除文件夹
        File a=new File("src/main/java/流/文件测试包/文件2.txt");
        System.out.println(a.delete());
        /*a.delete()
        * 返回teur表示删除成功
        * 返回false表示删除失败
        * */
    }
}

获取当前文件夹中所有文件

使用list()方法
Java 复制代码
package 流;

import java.io.File;

public class k {
    public static void main(String[] args) {
        //获取当前目录中的所有子项
        File dir = new File("src/main/java/流/文件测试包");
        /*
            boolean isFile()
            判断当前File表示的是否为一个文件
            boolean isDirectory()
            判断当前File表示的是否为一个目录
         */
        if(dir.isDirectory()){
            /*
                File[] listFiles()
                将当前目录中的所有子项返回。返回的数组中每个File实例表示其中的一个子项
             */
            File[] subs = dir.listFiles();
            System.out.println("当前目录包含"+subs.length+"个子项");
            for(int i=0;i<subs.length;i++){
                File sub = subs[i];
                System.out.println(sub.getName());
            }
        }
    }
}

获取符号特点条件子项目

重载的listFiles方法:File[] listFiles(FileFilter)

该方法要求传入一个文件过滤器,并仅将满足该过滤器要求的子项返回。

java 复制代码
package file;

import java.io.File;
import java.io.FileFilter;

/**
 * 有条件的获取一个目录中的子项
 */
public class ListFilesDemo2 {
    public static void main(String[] args) {
        //获取当前目录下的所有文本文件(文件名是以".txt"结尾的)
        File dir = new File(".");
        if(dir.isDirectory()){
//            FileFilter fileFilter = new FileFilter() {
//                public boolean accept(File f) {
//                    return f.getName().endsWith(".txt");
//                }
//            };
//            /*
//                重载的listFiles方法要求传入一个文件过滤器
//                该方法会将File对象表示的目录中所有满足过滤器条件的子项返回
//             */
//            File[] subs = dir.listFiles(fileFilter);


            File[] subs = dir.listFiles(f->f.getName().endsWith(".txt"));

            for(File sub : subs){
                System.out.println(sub.getName());
            }
        }
    }
}

创建目录mkdirs()
Java 复制代码
package 流;

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

public class 创建多级目录 {
    public static void main(String[] args) throws IOException {
        // 定义需要创建的文件夹路径
        String dirPath = "src/main/java/流/文件测试包/创建目录";
        // 创建文件对象
        File file = new File(dirPath);
        // 判断文件是否存在,不存在则创建
        if (!file.exists()) {
            // 创建文件
            file.mkdirs();
            System.out.println("创建目录成功!");
        } else {
            System.out.println("目录已存在!");
        }
    }
}

mkdirs()和mkdir()区别
  • mkdirs()
    • 它可以创建多级目录结构,如果父目录不存在,它会自动创建所有必要的父目录
  • mkdir()
    • 它只能创建单个目录,并且只有当父目录已经存在时才能成功创建目录。如果父目录不存在,它将抛出异常

常用方法
  • getParent():获取上级目录
  • getPath():获取相对路径
  • getAbsolutePath:获取绝对路径
  • getName():获取名字
  • lastModified():最近一次修改时间

Java 复制代码
package 流;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class 常用方法 {
    public static void main(String[] args) throws IOException {
        File path=new File("src/main/java/流/文件测试包/文件2.txt");
        path.createNewFile();
        System.out.println("上级目录:"+path.getParent());
         System.out.println("该文件的名字为;"+path.getName());
    
    long longdate=path.lastModified();//最近修改时间
    Date date=new Date(longdate);//new Date:获取的是柏林时间
    SimpleDateFormat pp=new SimpleDateFormat("yyy-mm-dd hh:mm:ss:ss");//时间格式转换 SimpleDateFormat()
    System.out.println(pp.format(date));//如果文件不存在则输出初始时间

    File yd=new File("文件测试包/lly.doc");
    System.out.println("相对路径:"+yd.getPath());
    System.out.println("绝对路径:"+yd.getAbsolutePath());

    }
}
/*
输出:
上级目录:src\main\java\流\文件测试包
该文件的名字为;文件2.txt
2024-24-21 12:24:34:34
相对路径:文件测试包\lly.doc
绝对路径:F:\Java_project\java_maven\文件测试包\lly.doc*/

文件字节流

InputStream是Java所有字节输入流类的父类,OutputStream是Java所有字节输出流类的父类,因此继承它们的子类要重新定义父类中的抽象方法。


OutputStream

是字节输出流,也是一个抽象类,new子类来定义其方法


常用方法

write():向输出流中写入一个字节

close:关闭输出流

flush:可以强制将缓冲区中的数据写入输出流,并清空缓冲区


实现代码

java 复制代码
package com.ch012.h003;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class shuchuruliu {
    public static void out(){
        //地址
        File lyy=new File("src/com/ch012/h003/ceshi/测试.txt");
        try{
            FileOutputStream ldy=new FileOutputStream(lyy,true);//true为追加操作内容
            String zb="风声鹤起,问我要有多大,梦里把你吓";//原本准备内容
            ldy.write(zb.getBytes());//x写入内容
            ldy.close();//关闭资源
            System.out.println("成功输入!");
        }
        catch (FileNotFoundException e){
            System.out.println("找不到指定文件");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
out();//调用方法
    }
}
//输出:
风声鹤起,问我要有多大,梦里把你吓
Java 复制代码
package 流;

import java.io.FileOutputStream;
import java.io.IOException;

public class 文件字节流1 {
    public static void main(String[] args) {
        try {
            FileOutputStream a=new FileOutputStream("src/main/java/流/文件测试包/文件3");
            String a1="1234567890";
            a.write(a1.getBytes());//把数据写到内存
            a.flush();//把内存中的数据刷新写到硬盘上
            a.close();//关闭
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

InputStream

是输入流,也是一个抽象类,主要负责将数据进行读取操作,在进行实列化的时候一定要是实列化其子类,new子类来使用方法

Java 复制代码
package 流;

import java.io.FileInputStream;


public class 文件字节流 {
    public static void main(String[] args) {
        try {
            FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件3");

            byte[]b=new byte[10];//设置一个数组接收读取文件的内容
            a.read(b);
            System.out.println(new String(b));//打印出读取的内容
            a.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

常用方法

read():读取数据

close:关闭资源


代码实现

java 复制代码
package 流;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class 读取文件内容 {
    public static void main(String[] args) throws IOException {
        File ye=new File("src/main/java/流/文件测试包/文件2.txt");
        FileInputStream le = new FileInputStream(ye);
        byte[]bytes=new byte[1024];
        /*读取数据*/
        int len=le.read(bytes);
        while (len!=-1){
            System.out.println(new String(bytes,0,len));
            len=le.read(bytes);
        }
    }
}

字节流拷贝文件
java 复制代码
package 流;

import java.io.*;
public class 字节流复制 {
    
    //将文件复制到另一个文件
    public static void main(String[] args) throws IOException {
        FileInputStream in=new FileInputStream("src/main/java/流/文件测试包/文件.txt");
        FileOutputStream out=new FileOutputStream("src/main/java/流/文件测试包/文件2.txt");
        byte[] b=new byte[100];
        int len;
        while((len=in.read(b))!=-1){
            out.write(b,0,len);
        }
        in.close();
        out.close();
    }
}
/*注意:

使用write方法帮我们去进行写入工作的时候,为了解决部分编码问题(乱码),于是传入三个参数

第一个:byte[]存放读取出来的内容

第二个:起始位置,因为是进行拷贝工作,所以一般起始位置都是从0开始

第三个:编号*/

文件字符流


FileReader

主要负责读取工作

java 复制代码
package 流.文件字符流;

import java.io.FileReader;
import java.io.IOException;
public class 文件字符流 {
    public static void main(String[] args) throws IOException {
        //读取文件数据
        FileReader fr = new FileReader("src/main/java/流/文件测试包/文件.txt");
        char[]c=new char[10];
        int len=0;
        while ((len=fr.read(c))!=-1){
            System.out.println(new String(c,0,len));
        }
        fr.close();
    }
}

writer
java 复制代码
package 流.文件字符流;

import java.io.FileWriter;
import java.io.IOException;

public class 文件字符流2 {
    public static void main(String[] args) throws IOException {
        FileWriter a=new FileWriter("src/main/java/流/文件测试包/文件.txt");
        a.write("一滴水的感恩!");
        a.flush();
        a.close();
    }
}

字符流拷贝
java 复制代码
package 流.文件字符流;

import java.io.*;

public class 拷贝 {
    public static void main(String[] args) throws IOException {
            FileReader a = new FileReader("src/main/java/流/文件测试包/文件.txt");
           FileWriter b = new FileWriter("src/main/java/流/文件测试包/文件2.txt");

        char[]c=new char[100];
        int len;
        while ((!((len=a.read(c))!=-1))){//读取数据
            b.write(c,0,len);//写入数据
        }
           a.close();
           b.close();
    }
}

缓冲流

缓冲字节流

功能

在流链接中的作用:加快读写效率

通常缓冲是最终链接在低级流上的流


flush的传递

flush()方法是被定义在java.io.Flushable中。而字节输出流的超类java.io.OutputStream实现了该接口,这意味着所有的字节输出流都有flush方法。而除了缓冲流之外的高级流的flush方法作用就是调用它链接的流的flush方法将该动作传递下去。最终传递给缓冲流来清空缓冲区。


BufferedInputStream
Java 复制代码
package 流.缓冲流;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
//缓冲字节流读取文件内容
public class 缓冲字节流 {
    public static void main(String[] args) throws IOException {
        FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件2");
        BufferedInputStream b=new BufferedInputStream(a);
        byte[]c=new byte[100];
        int len;
        while ((len=b.read(c))!=-1){
            System.out.println(new String(c,0,len));
        }
        a.close();
        b.close();
    }
}

BufferedOutputStream
Java 复制代码
package io;

import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 缓冲输出流的写缓冲问题
 */
public class BosFlushDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("bos.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        String line = "super idol的笑容都没你的甜~";
        byte[] data = line.getBytes(StandardCharsets.UTF_8);
        bos.write(data);
        /*
            void flush()
            强制将缓冲流的缓冲取(内部维护的字节数组)中已经缓存的字节一次性写出
         */
//        bos.flush();
        System.out.println("写出完毕!");
        bos.close();//缓冲输出流的close()方法内部会自动调用一次flush()方法确保数据写出
    }
}

写缓冲问题

由于缓冲输出流会将写出的数据装满内部缓冲区(默认8kb的字节数组)后才会进行一次真实的写出操作。当我们的数据不足时,如果想要及时写出数据,可以调用缓冲流的flush()方法,强制将缓冲区中已经缓存的数据写出一次。


缓冲字节流拷贝
Java 复制代码
package 流.缓冲流;

import java.io.*;

public class 缓冲字节流文件复制 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("src/main/java/流/文件测试包/b51866052244a2414c0d2cc75f3c3752.png");
        BufferedInputStream bis = new BufferedInputStream(fis);

        FileOutputStream fos = new FileOutputStream("src/main/java/流/文件测试包/创建目录/复制的图片.png");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int len;
        long start = System.currentTimeMillis();
        while((len=bis.read())!= -1){
            bos.write(d);
        }
        long end = System.currentTimeMillis();//格林尼治标准时间
        System.out.println("复制完毕!耗时:"+(end-start)+"ms");
        bis.close();
        bos.close();

    }
}

缓冲字符流

BufferedReader
Java 复制代码
package 流.缓冲流;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class 缓冲字符输入流 {
    public static void main(String[] args) throws IOException {
        FileReader r=new FileReader("src/main/java/流/文件测试包/文件3");
        BufferedReader  br=new BufferedReader(r);
        char[]b=new char[100];
        int len;
        while ((len=br.read(b))!=-1){
            System.out.println(new String(b,0,len));
        }
        r.close();
    }
}

BufferedWriter
Java 复制代码
package 流.缓冲流;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class 缓冲字符输出流 {
    public static void main(String[] args) throws IOException {
        FileWriter a=new FileWriter("src/main/java/流/文件测试包/文件2.txt");
        BufferedWriter b=new BufferedWriter(a);
        String c="hello world";
        System.out.println("成功");
        b.write(c);
        b.flush();
        b.close();
        a.close();
    }
}

缓冲字符流拷贝
Java 复制代码
package 流.缓冲流;

import java.io.*;

public class 缓冲字符流拷贝 {
    public static void main(String[] args) throws IOException {
        BufferedReader a=new BufferedReader(new FileReader("src/main/java/流/文件测试包/文件3"));
        BufferedWriter b=new BufferedWriter(new FileWriter("src/main/java/流/文件测试包/文件2.txt"));
        char[] c=new char[1024];
        int len=0;

            while((len=a.read(c))!=-1) {
                b.write(c, 0, len);
        }
        System.out.println("成功");
        b.flush();
        b.close();
        a.close();
    }
}

字符转换流

字符流与字节流之间的转换


好处

1,可以进行编码格式的设置

2,可以加快读写速度

3,读写的数据类型为字节类型


InputStreamReader

将字符输入流和字节输入流之间进行转换

Java 复制代码
package 流.转换流;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class 转换输入流 {
    public static void main(String[] args) throws IOException {
        FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件4");
        InputStreamReader  b=new InputStreamReader(a,"UTF-8");
        char[]c=new char[10];
        int len;
        while((len=b.read(c))!=-1){
            System.out.println(new String(c,0,len));
        }
        b.close();
        a.close();
    }
}

OutputStreamWrier

将字符流输出流和字节输出流之间进行转换

Java 复制代码
package 流.转换流;

import java.io.*;

public class 转换输出流 {
    public static void main(String[] args) throws IOException {
        FileOutputStream out = new FileOutputStream("src/main/java/流/文件测试包/文件5");
        OutputStreamWriter  outWriter = new OutputStreamWriter(out,"utf-8");

        outWriter.write("转换输出流");
        System.out.println("成功");
        outWriter.close();
        out.close();
    }
}

字节对象流

直接把某个对象写入到某个文件中,直接读取某个文件中的对象属性


为什么使用序列化操作

1,可以将对象永久的保存到磁盘中

2,可以把对象通过网络上进行传输到另一台机器上

**注:**无论是保存在磁盘中还是传输,都需要将对象转换为字节后才可以进行


使用序列化的前提

  • 必须实现Serilizable接口

创建被序/反序列化的对象

Java 复制代码
package 流.对象流;
import java.io.Serializable;
public class chuangjian implements Serializable {
    String name;
    int age;
    private transient String id;
    public chuangjian(String name, int age, String id){
        this.name=name;
        this.age=age;
        this.id=id;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age;
    }
}

实现了序列化接口的类建议显示的定义常量:static final long serialVersionUID = 1L;


序列化操作

将对象的某些属性或方法写入到某个文件中(将对象写入文档)


ObjectOutputStream

主要负责写入工作,实现序列化操作(将某个对象写入到某个文件中)

Java 复制代码
package 流.对象流;

import java.io.*;

public class 对象流反序列化 {
    public static void main(String[] args) throws IOException {
        chuangjian a=new chuangjian("zhangsan",21,"jd218429");

        FileOutputStream b=new FileOutputStream("src/main/java/流/文件测试包/文件.txt");
        ObjectOutputStream b1=new ObjectOutputStream(b);
        b1.writeObject(a);
        System.out.println("成功");
        b1.close();
    }
}

transient关键字

当一个属性被transient关键字修饰后,该对象在进行序列化时,转换出来的字节中是不包含该属性的。忽略不必要的属性可以达到对象"瘦身"的操作。

对象瘦身可以在对象持久化时减少磁盘开销。在进行传输时可以缩短传输速度。

如果该对象不需要序列化,那么该关键字不发挥其他任何效果

Java 复制代码
public class chuangjian implements Serializable {
    String name;
    int age;
    private transient String id;

序列化时不包含otherInfo属性,并且反序列化时该属性值为null

Java 复制代码
Person{name='zhangsan', age=21,id=null}

反序列化操作

将某个文件中的对象读取出来(在文件中读取对象)


ObjectInputStream

主要负责读取工作,实现反系列化操作(将某个文件中的对象读取出来)

Java 复制代码
package 流.对象流;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class 序列化 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件.txt");
        ObjectInputStream b=new ObjectInputStream(a);
        chuangjian c= (chuangjian) b.readObject();
        System.out.println(c);
        b.close();
    }
}
相关推荐
_oP_i27 分钟前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx30 分钟前
android sqlite 数据库简单封装示例(java)
android·java·数据库
武子康1 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘2 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意2 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上3 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人3 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.3 小时前
Mybatis-Plus
java·开发语言
不良人天码星3 小时前
lombok插件不生效
java·开发语言·intellij-idea