JavaIO框架

Java IO框架

参考视频: BV1Tz4y1X7H7

1.流的概念

流的定义:内存与存储设备之间传输数据的通道

在这里插入图片描述

2.流的分类

按方向

输入流:将存储设备中的内容读入到内存中。

输出流:将内存中的内容写入到存储设备中。

在这里插入图片描述

按单位

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

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

按功能

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

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

3.字节流

3.1 继承关系

输入流继承关系

在这里插入图片描述

输出流继承关系

在这里插入图片描述

3.2 字节流的抽象父类

InputStream

字节输入流

  • public int read(){}
  • public int read(byte[] b){}
  • public int read(byte[] b,int off,int len){}

OutputStream

字节输出流

  • public void write(int n){}
  • public void write(byte[] b){}
  • public void write(byte[] b,int off,int len){}

3.3 字节流的子类

3.3.1 文件字节流

FileInputStream

  • public int read()//从输入流中读取一个字节数据,返回读到的字节数据,如果达到文件末尾,返回-1。
  • public int read(byte[] b)//从输入流中读取字节数组长度的字节数据存入数组中,返回实际读到的字节数;如果达到文件的尾部,则返回-1。

FileOutputStream

  • public void write(int b)//将指定字节写入输出流。
  • public void write(bute[] b)//一次写多个字节,将b数组中所有字节,写入输出流。
测试
/*
*  FileInputStream测试
*/
public class MainTest {
    public static void main(String[] args) throws IOException {
        //文件内容:dafegesa
        FileInputStream ifs=new FileInputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt");

        //read();读入单个字节
        System.out.println("读入单个字节");
        int data=ifs.read();
        System.out.println((char)data);
        while((data=ifs.read())!=-1){  //-1代表文件已读完
            System.out.println((char)data);
        }   //按1个字节依次输出
//==========上下两个测试部分不能同时进行,因为上半部分读完数据后输入流为空=======
        ifs.reset();
        //read(byte[] b); 读入多个字节
        byte[] b=new byte[3];   //一次读取的字节数=byte的容量
        if((data=ifs.read(b))!=-1){
            System.out.println(new String(b,0,data));
        }   //按3个字节依次输出

        ifs.close();
    }
}
/*
*  FileOutputStream测试
*/
public class MainTest {
    public static void main(String[] args) throws IOException {
        //文件内容:dafegesa     若没有文件则会自动创建
        FileOutputStream ofs=new FileOutputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt");

        //write(int b);
        ofs.write(97);
        ofs.write('b');
        ofs.write('c');

        //write(byte[] b);
        ofs.write(new String("hellorld").getBytes());
        //此时文件bbb.txt内容为abchelloworld    原内容被替换

        ofs.close();
    }
}
读取图片
public class MainTest {
    public static void main(String[] args) throws IOException {
        FileInputStream ifs=new FileInputStream("C:\\Users\\96955\\Desktop\\right\\ganyu\\chigua.png");
        FileOutputStream ofs=new FileOutputStream("C:\\Users\\96955\\Desktop\\tempblog\\chigua.png");


        int count; //保存一次读取到的实际字节数
        byte[] b=new byte[1024];

        while((count=ifs.read(b))!=-1){
            ofs.write(b,0,count);
        }
        System.out.println("复制完成");
        ifs.close();
        ofs.close();
    }
}

在这里插入图片描述

3.3.2 字节缓冲流

BufferedInputStream
BufferedOutputStream

目的:

  1. 提高IO效率,减少访问磁盘的次数;
  2. 数据存储在缓冲区中。flush可以将缓存区的内容写入文件,也可以直接close。
测试
/**
* 使用字节缓冲流读取
* BufferedInputStream
*/
public class MainTest {
    public static void main(String[] args) throws IOException {
        FileInputStream ifs=new FileInputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt");

        //缓冲流需要一个底层流
        BufferedInputStream bis=new BufferedInputStream(ifs);

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


        int count; //保存一次读取到的实际字节数
        byte[] b=new byte[1024];
        while((count=bis.read(b,0,b.length))!=-1){
            System.out.println(new String(b,0,count));
        }
        bis.close();
    }
}
/**
* 使用字节缓冲流写入文件
* BufferedOutputStream
*/
public class MainTest {
    public static void main(String[] args) throws IOException {
        FileOutputStream ofs=new FileOutputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt");

        //缓冲流将数据写入缓冲区
        BufferedOutputStream bos=new BufferedOutputStream(ofs);

        //写入文件
        bos.write("helloworld".getBytes());
        bos.flush();  //确认修改。源码内部也会调用flush方法

        bos.close();
    }
}

3.3.3 对象流

ObjectOutputStream
ObjectInputStream

  • 增加了缓冲区功能。
  • 增强了读写8种基本数据类型和字符串功能。
  • 增强了读写对象的功能:
    • readObject()//从流中读取一个对象。又称反序列化
    • writeObject(Object obj)向流中写入一个对象。又称序列化
序列化
/**
* Student类
*/

//要实现序列化必须先实现Serializable接口(源码为空,只是起标记作用)
public class Student implements Serializable {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +"name='" + name + '\'' +", age=" + age +'}';
    }
}

/**
 * 使用ObjectOutputStream实现对象的序列化
 */
public class MainTest {
    public static void main(String[] args) throws IOException {
        FileOutputStream ofs=new FileOutputStream("C:\\Users\\96955\\Desktop\\tempblog\\obj.bin");
        ObjectOutputStream obs=new ObjectOutputStream(ofs);

        //序列化(写文件)
        Student tang=new Student("唐瑞",21);
        obs.writeObject(tang);
        obs.close();
        System.out.println("序列化完成");
    }
}

在这里插入图片描述

反序列化
/**
 * 使用ObjectInputStream实现反序列化(读取重构对象)
 */
public class MainTest {
    public static void main(String[] args) throws IOException,ClassNotFoundException {
        FileInputStream ifs=new FileInputStream("C:\\Users\\96955\\Desktop\\tempblog\\obj.bin");
        ObjectInputStream obs=new ObjectInputStream(ifs);

        //反序列化(读取文件)
        Student student=(Student)obs.readObject();
        obs.close();
        System.out.println("反序列化完成");
        System.out.println(student.toString());
    }
}

在这里插入图片描述

附加说明
  • 序列化类及其内部类必须实现Serializable接口。

  • 序列化类中可以添加序列化版本号ID,以保证序列化的类和被序列化的类是同一个类。在上面的代码中并没有添加序列号版本,虽然IDE没有报错,但是会显示一个警告,提示我添加序列化版本号(串行版本标识)。我们可以在Student类中添加:

private static final long serialVersionUID = 100L;  //序列号

此时执行反序列化会报错

Exception in thread "main" java.io.InvalidClassException: Student; local class incompatible: stream classdesc serialVersionUID = 5061154393647412285, local class serialVersionUID = 100

报错内容说明两个类的serialVersionUID不同,5061154393647412285是我们没有自定义序列号时,序列化过程中系统自动生成的。 可以在修改序列号后重新序列化,这之后反序列化就能通过。

  • tranisient(瞬时的)修饰符,可以避免修饰的属性被序列化,如:

    private transient int age;
    

    此时将学生类序列化后,age不会被写入目标文件。反序列化的结果中,age是一个默认值。

  • 静态属性不能被序列化

  • 可以利用集合来序列化多个对象

ArrayList<Student> arrayList=new ArrayList<Student>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
objectOutputStream.writeObject(arrayList);
ArrayList<Student> list=(ArrayList<Student>)objectInputStream.readObject();

//反序列化的结果是一个集合

4.编码方式

  • IOS-8859-1

    收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。采用1个字节来表示,最多只能表示256个字符。

  • UTF-8

    针对Unicode码表的可变长度字符编码。国际上使用的编码,也称为“万国码”,收录了几乎所有国家的常用字符。采用1至3个字节来表示一个字符。

  • GB2312

    简体中文,采用1个或2个字节来表示字符,95年之前所采用的编码。

  • GBK

    简体中文的扩充,GB2312的升级版本。

  • BIG5

    台湾,繁体中文。

当编码方式和解码方式不一致时,会出现乱码。假如要读取的文件中的内容不是字母而是“一二三四”这样的汉字,那么读取出来的信息就是乱码。因为字节流按字节输入输出,而这四个汉字占了12个字节,把一个汉字按一个一个字节读入自然会出现问题,这时就需要使用字符流。

5.字符流

5.1 字符流继承关系

在这里插入图片描述

在这里插入图片描述

5.2 字符流的抽象父类

  • **Reader:**字符输入流

    • public int read()

      从流中读取单个字符,用整型来返回读取的字符;当读到流底部时返回-1。

    • public int read(char[] c)

      从流中读取字符保存到c数组中,返回读取的字符个数,当读到流底部时返回-1。

    • public int read(char[] cbuf,int off,int len){}

      抽象方法。

  • **Writer:**字符输出流

    • public void write(int n)

      写入单个字符,只能写入包含16位低阶字节的整型数值,16位高阶字节将会被忽略。

    • public void write(String str)

      写入一个字符串。

    • public void write(char[] cbuf)

      写入一个字符数组。

5.3 字符流的子类

5.3.1 FileReader

  • public int read()

    继承自InputStreamReader类。读取单个字符,返回读取的字符,当读到流底部时返回-1。

  • public int read(char[] c)

    继承自Reader类。

  • public int read(char[] cbuf,int offset,int length)

    继承自InputStreamReader类。从流中读取部分字符到cbuf中指定位置,返回读取到的字符个数,当读到流底部时返回-1。

public class MainTest {
    public static void main(String[] args) throws IOException{
        FileReader ifs=new FileReader("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt");

        int data;
        //read(); 每次读取一个字符而不是一个字节
        while((data=ifs.read())!=-1){
            System.out.println((char)data);
        }
        ifs.close();
    }
}

在这里插入图片描述

5.3.2 FileWriter

  • public void write(int c)

    继承自OutputStreamWriter类,写入一个字符。

  • public void write(String str)

    继承自Writer类。

  • public void Write(char[] cbuf)

    继承自Writer类。

public class MainTest {
    public static void main(String[] args) throws IOException{
        FileWriter ofs=new FileWriter("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt");

        int data;
        ofs.write("测试测试测试测试");
        ofs.close();
        System.out.println("执行完毕");
    }
}

在这里插入图片描述

5.3.3 字符流复制测试

/**
 * 使用FileReader和FileWrite复制文本文件
 *  注:不能复制图片或二进制文件
 */
public class MainTest {
    public static void main(String[] args) throws IOException{
        InputStreamReader inputStreamReader=new InputStreamReader(new FileInputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt"));
        FileWriter ofs=new FileWriter("C:\\Users\\96955\\Desktop\\tempblog\\temp1.txt");

        //读写
        int data=0;
        while((data=inputStreamReader.read())!=-1){
            ofs.write(data);
        }

        inputStreamReader.close();
        ofs.close();
        System.out.println("执行完毕");
    }
}

5.4 字符缓冲流

BufferedReader
BufferedWriter

  • 高效读写
  • 支持换行输入符
  • 可一次写一行、读一行。
/**
 * 使用字符缓冲流读取文件
 * BufferedReader
 */

public class MainTest {
    public static void main(String[] args) throws IOException{
        InputStreamReader inputStreamReader=new InputStreamReader(new FileInputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp.txt"));
        BufferedReader bufferedReader=new BufferedReader(inputStreamReader);

        //read(char[] cbuf)
        char[] cbuf=new char[3]; //一次读3的字符
        int count;
        while((count=bufferedReader.read(cbuf))!=-1){
            System.out.println(new String(cbuf,0,count));
        }
//==================上下部分不能同时进行,上部分读完后缓冲区已为空===================
        //readline();  一次读取一行
        String line;
        while((line=bufferedReader.readLine())!=null){
            System.out.println(line);
        }

        System.out.println("执行完毕");
    }
}

在这里插入图片描述

/**
 * 使用字符缓冲流写入文件
 * BufferedWriter
 */

public class MainTest {
    public static void main(String[] args) throws IOException{
        BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("C:\\Users\\96955\\Desktop\\tempblog\\temp1.txt"));
        bufferedWriter.write("测试一测试一测试一\r\n测试一测试一");
        //换行符: windows-->\r\n    linux \n
        bufferedWriter.newLine();
        bufferedWriter.write("测试二\r\n测试二测试二测试二测试二");

        bufferedWriter.close();
        System.out.println("执行完毕");
    }
}

在这里插入图片描述

5.5 打印流

PrintWriter:

  • 封装了print()/println()方法,支持写入后换行。
  • 支持数据原样打印。比如打印97会按原样写入97而不是转成‘a’。
public class MainTest {
    public static void main(String[] args) throws IOException{
        PrintWriter printWriter=new PrintWriter(new FileWriter("C:\\Users\\96955\\Desktop\\tempblog\\temp1.txt"));

        //打印到文件
        printWriter.println(97);//97
        printWriter.println('b');//b
        printWriter.println(3.14);//3.14
        printWriter.println(true);//true

        printWriter.close();
        System.out.println("执行完毕");
    }
}

在这里插入图片描述

5.6 转换流

桥转换流:InputStreamReader/OutputStreamWriter

  • 可将字节流转换为字符流。
  • 可设置字符的编码方式。
public class MainTest {
    public static void main(String[] args) throws IOException{
        OutputStreamWriter outputStreamWriter=new OutputStreamWriter(new FileOutputStream("C:\\Users\\96955\\Desktop\\tempblog\\temp1.txt"));

        outputStreamWriter.write("转换流测试");
        outputStreamWriter.close();
        System.out.println("执行完毕");
    }
}

在这里插入图片描述

6.File类

File类可以指向一个文件或一个目录

方法

  • public boolean CreateNewFile()

    当且仅当指定的文件名不存在时创建一个指定的新的、空的文件。创建成功返回true,如果指定文件名已存在返回false。

  • public boolean mkdir()

    创建一个指定路径名的文件夹。当且仅当文件夹被创建时返回true,否则返回false。

  • public boolean delete()

    删除一个指定的文件或文件夹,文件夹必须为空才能被删除。当且仅当指定的文件或文件夹被删除时返回true,否则返回false。

  • public boolean exists()

    检查指定的文件或文件夹是否存在。当且仅当指定的文件或者文件夹存在时返回true,否则返回false。

  • public File[] listFiles()

    列出目录中的所有内容,返回一个指定路径名中的文件数组,如果指定的路径名不代表一个文件夹(目录)就返回null。

  • public boolean renameTo(File dest)

    重命名一个路径名所指定的文件。当且仅当修改操作成功时返回true,否则返回false。

6.1 文件操作

public class MainTest {
    public static void main(String[] args) throws IOException,InterruptedException{
        //输出:
        //路径分隔符:;
        //名称分隔符:\
        separator();
        fileOp();
    }

    public static void separator() {
        System.out.println("路径分隔符:"+File.pathSeparator);
        System.out.println("名称分隔符:"+File.separator);
    }

    public static void fileOp() throws IOException,InterruptedException {
        //1.创建文件
        File file=new File("C:\\Users\\96955\\Desktop\\tempblog\temp1.txt");
        if(!file.exists()){
            boolean flag=file.createNewFile();
            System.out.println("创建状态"+flag);
        }

        //2.删除文件
        //2.1 直接删除
        //System.out.println("删除结果:"+file.delete());

        //2.2使用JVM退出时自动删除
        file.deleteOnExit();
        Thread.sleep(5000);  //延迟5秒后自动删除文件


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

        //4.判断内容
        System.out.println("是否可写:"+file.canWrite());
        System.out.println("是否可读:"+file.canRead());
        System.out.println("是否隐藏:"+file.isHidden());
        System.out.println("是否是文件:"+file.isFile());
        System.out.println("是否是文件夹:"+file.isDirectory());
    }

}

6.2 目录操作

public class MainTest {
    public static void main(String[] args){
        directorOp();
    }

    public static void directorOp() {
        //1.创建目录
        File dir=new File("C:\\Users\\96955\\Desktop\\tempblog");
        if(!dir.exists()){
            //mkdir();  只能创建单级目录
            boolean flag=dir.mkdirs();  //创建多级目录
            System.out.println("创建结果:"+flag);
        }

        //2.删除目录
        //2.1直接删除
        //System.out.println("删除结果:"+dir.delete());

        //2.2使用JVM删除
        dir.deleteOnExit();


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

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

        //5.遍历目录
        File dir2=new File("C:\\Users\\96955\\Desktop");
        String[] files=dir2.list();
        for(String string:files){
            System.out.println(string);
        }
    }
}

6.3 文件过滤器

FileFilter接口:

public interface FileFilter

  • boolean accepte(File pathname)
  • 当调用File类中的listFiles()方法时,支持传入FileFilter接口实现类,对获取的文件进行过滤,只有满足条件的文件才可以出现在listFiles()的返回值中。
//实现只打印当前目录中的txt文件的文件名

//这段代码卸载6.2中的"5.遍历目录"处
public static void  directorOp() {
    File[] files1=dir2.listFiles(new FileFilter() {		
        //自定义筛选条件
        @Override
        public boolean accept(File pathname) {
            if(pathname.getName().endsWith(".txt")) {
                return true;
            }
            return false;
        }
    });
    
    for (File file : files1) {
        System.out.println(file.getName());
    }
}

6.4 文件操作案例

public class MainTest {
    public static void main(String[] args){
        //......
    }

    //递归遍历目录
    public static void listDer(File dir) {
        File[] files=dir.listFiles();
        if(files!=null && files.length>0){   //files是目录
            for(File file:files){
                if(file.isDirectory()){
                    listDer(file);
                }
                else{
                    System.out.println(file.getName());
                }
            }
        }
    }
    
    //递归删除目录
    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 file.delete();
            }
        }
        dir.delete();
    }
}

7.Prioerties类

又称属性集合。使用方式和map类似。

特点:

  • 存储属性名和属性值(都是字符串类型)
  • 没有泛型
  • 和流有关

方法:

  • public String getProperty(String key)

    根据key在属性列表里查找value,如果原始属性列表找不到就去默认属性列表找。返回key所对应的value。

  • public void list(PrintWriter out)

    将属性列表打印在指定的输出流上,在debug时很有用。

  • public Object setProperty(String key,String value)

    内部调用的是Hashtable的put方法,将key和value成对地保存在属性列表中。返回这个key上一个对应的value,没有就返回null。

Properties可以保存在一个流中或是从一个流中加载,属性列表中的每个键值对都是一个字符串。一个属性列表可以包括另一个第二属性列表来作为它的默认值,如果在原始属性列表中没有找到key时就搜索第二属性列表。

public class MainTest {
    public static void main(String[] args) throws IOException{
        Properties properties=new Properties();
        //添加数据
        properties.setProperty("username","tanghui");
        properties.setProperty("age","21");
        System.out.println(properties.toString());

        //遍历    使用keySet、entrySet的过程与map相近
        //使用stringPropertyNames() 遍历
        Set<String> set=properties.stringPropertyNames();
        for(String string:set){
            System.out.println(string+" "+properties.getProperty(string));
        }

        //和流有关的方法
        //list
        PrintWriter printWriter=new PrintWriter("C:\\Users\\96955\\Desktop\\tempblog\\temp1.txt");
        properties.list(printWriter);   //properties中的内容写入文件
        printWriter.close();

        //store保存
        FileOutputStream fileOutputStream=new FileOutputStream("C:\\Users\\96955\\Desktop\\tempblog\\a.properties");
        properties.store(fileOutputStream,"NOTES");
        fileOutputStream.close();

        //load加载
        Properties properties1=new Properties();
        FileInputStream fileInputStream=new FileInputStream("C:\\Users\\96955\\Desktop\\tempblog\\a.properties");
        properties1.load(fileInputStream);   //从properties文件中读取内容
        fileInputStream.close();
        System.out.println(properties1.toString());
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值