Day13-IO流

IO流

文件

  • 用来保存数据

  • 文件流

  • 流:数据在数据源(文件)和程序(内存)之间经历的路径

  • 输入流:数据从数据源(文件)到程序(内存)的路径

  • 输出流:数据从程序(内存)到数据源(文件)的路径

常用的文件操作

  • 创建文件对象相关构造器和方法

    new File(String pathname) //根据路径构建一个File对象
    new File(File parent,String child) //根据父目录文件+子路径构建
    new File(String parent,String child) //根据父目录+子路径构建   
    createNewFile 创建新文件   

package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
public class Demo01 {
    public static void main(String[] args) {
    }
    @Test
    public void createFile(){
       //方式1
       String filePath="/Users/liushaoqin/Desktop/test.txt";
        File file = new File(filePath);
        try {
            file.createNewFile();
            System.out.println("创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //方式2
        File parentFile = new File("/Users/liushaoqin/Desktop");
        String childFileName="test1.txt";
        File file2 = new File(parentFile, childFileName);
        try {
            System.out.println("创建成功");
            file2.createNewFile();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //方式3
        String parentFilePath="/Users/liushaoqin/Desktop";
        String childFileName1="test2.txt";
        File file3 = new File(parentFilePath, childFileName1);
        try {
            file3.createNewFile();
            System.out.println("创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
 

IO流原理及流的分类

  • 按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件

  • 按数据流的流向不同分为:输入流,输出流

  • 按流的角色的不同分为:节点流,处理流/包装流

抽象基类字节流字符流
输入流 InputStream Reader
输出流 OutputStream Writer

1)java的IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象类派生的

2)由这四个类派生出来的子类名称都是以其父类名作为子类名后缀

文件VS流

InputStream:字节输入流

InputStream抽象类是所有类字节输入流的超类

InputStream常用的子类

  • FileInputStream:文件输入流

  • BufferedInputStream:缓冲字节输入流

  • ObjectInputStream:对象字节输入流

package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo02 {
    public static void main(String[] args) {
    }
    @Test
    //FileInputStream 文件输入流用法演示
    public void readFile() throws IOException {
        String filePath = "/Users/liushaoqin/Desktop/test.txt";
        FileInputStream fileInputStream = new FileInputStream(filePath);
        int readData = 0;
        while ((readData = fileInputStream.read()) != -1) {
            System.out.print((char)readData);
        }
        fileInputStream.close();
    }
    @Test
    public void readFile02() throws IOException {
        String filePath = "/Users/liushaoqin/Desktop/test.txt";
        FileInputStream fileInputStream = new FileInputStream(filePath);
        byte[] buf=new byte[8];
        int readCount = 0;
        //从该输入流读取最多b.length字节的数据到字节数组,如果字节长度小于数组长度,则返回字节长度。
        //如果返回-1,则说明到达文件末尾
        while ((readCount=fileInputStream.read(buf))!=-1) {
            System.out.print(new String(buf,0,readCount));
        }
        fileInputStream.close();
    }
}
 

OutputStream:字节输出流

OutputStream抽象类是所有类字节输出流的超类

package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03 {
    public static void main(String[] args) {
    }
    //FileOutputStream类演示
    @Test
    public void writeFile() {
        String filePath = "/Users/liushaoqin/Desktop/a.txt";
        FileOutputStream fileOutputStream=null;
        try {
            //1.new FileOutputStream(filePath)创建方式,当写入内容时,会覆盖原来的内容
            //2.new FileOutputStream(filePath,true)创建方式,当写入内容时,是追加到文件后面
            fileOutputStream = new FileOutputStream(filePath,true);
            String content="Hello,world";
            //str.getBytes()可以把字符串-》字节数组
            fileOutputStream.write(content.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
 

练习

编程完成图片/音乐的拷贝

package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.io.*;
public class Demo04 {
    public static void main(String[] args) {
    }
    @Test
    //编程完成图片/音乐的拷贝
    public void copyFile(){
        String filePath="/Users/liushaoqin/Desktop/兔年快乐.jpg";
        String filePath2="/Users/liushaoqin/Desktop/兔年快乐1.jpg";
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;
        try {
            fileInputStream = new FileInputStream(filePath);
            //这里构造器里不用true,不会覆盖是因为这里只创建了一个对象,不停的在文件里写信息
            //会覆盖是因为多次打开文件,每次都创建了一个新的对象,不指定append就会覆盖
            fileOutputStream = new FileOutputStream(filePath2);
            byte[] buf=new byte[1024];
            int read = 0;
            while ((read=fileInputStream.read(buf))!=-1){
                //读取到后就写入到文件,通过fileOutputStream即,一边读一边写
                fileOutputStream.write(buf,0,read);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (fileInputStream!=null) {
                    fileInputStream.close();
                }
                if (fileOutputStream!=null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
 

Reader/Writer抽象类是所有类字符输入/出流的超类

  1. FileReader相关方法

    • new FileReader(File/String)

    • read:每次读取单个字符,返回该字符,如果到文件末尾返回-1

    • read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1

    • new String(char[]):将char[]转换成String

    • new String(char[],off,len):将char[]的指定部分转换成String

  2. FileWriter相关方法

    • new FileWriter(File/String):覆盖模式,相当于流的指针在首端

    • new FileWiriter(File/String,true):追加模式,相当于流的指针在尾端

    • write(int):写入单个字符

    • write(char[]):写入指定数组

    • write(char[],off,len):写入指定数组的指定部分

    • write(string):写入整个字符串

    • write(string, off,len):写入字符串的指定部分

    • String类:toCharArray,将String转换成char[]

    • FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件

节点流和处理流

  1. 节点流:可以从一个特定的数据源读写数据,入FileReader、FileWriter

  2. 处理流(包装流):是"连接"在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter

package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.*;
//使用BufferedReader读取文本文件,并显示在控制台
public class Demo06 {
    public static void main(String[] args) {
    }
    @Test
    public void readFile(){
        String filePath="/Users/liushaoqin/Desktop/note.txt";
        BufferedReader bufferedReader=null;
        try {
            bufferedReader = new BufferedReader(new FileReader(filePath));
            //按行读取
            String line;
            //当返回null是,表示文件读取完毕
            while ((line=bufferedReader.readLine())!=null){
                System.out.println(new String(line));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                //关闭流,这里注意,只需要关闭BufferedReader,因为底层会自动的去关闭节点流
                bufferedReader.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    } 
}

package com.lsq.study.IO流;
import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
import org.junit.jupiter.api.Test;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.security.cert.TrustAnchor;
////使用BufferedWriter将"hello,world"写入到文件中
public class Demo07 {
    public static void main(String[] args) {
    }
    @Test
    public void writeFile() throws IOException {
        String filePath="/Users/liushaoqin/desktop/note.txt";
        //new FileWriter(filePath,true)表示以追加的方式写入
        //new FileWriter(filePath)表示以覆盖的方式写入
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
        bufferedWriter.write("hello,world");
        //插入一个和系统相关的换行符
        bufferedWriter.newLine();
        bufferedWriter.close();
    }
}
 
package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.*;
//综合使用BufferedReader和BufferedWriter完成文本文件拷贝
public class Demo08 {
    public static void main(String[] args) {
    }
    @Test
    public void fileCopy() throws IOException {
        String filePath="/Users/liushaoqin/Desktop/note.txt";
        String filePath1="/Users/liushaoqin/Desktop/note1.txt";
        //BufferedReader和BufferedWriter是安装字符操作
        //不要去操作二进制文件[声音、视频、doc、pdf...],可能造成文件损坏
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath1));
        String line;
        while((line=bufferedReader.readLine())!=null){
            //说明:readLine读取一行内容,但是没有换行
            bufferedWriter.write(line);
            bufferedWriter.newLine();
        }
        if (bufferedReader!=null){
            bufferedReader.close();
        }
        if (bufferedWriter!=null){
            bufferedWriter.close();
        }
    }
}
 

序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值和数据类型

  2. 反序列化就是在恢复数据时,恢复数据的值和数据类型

  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:

    • Serializable //这是一个标记接口

    • Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口

ObjectInputStream和ObjectOutputStream(包装流)

  • ObjectInputStream提供反序列化功能

  • ObjectOutputStream提供序列化功能

  • 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致,否则会出现异常

package com.lsq.study.IO流;
import org.junit.jupiter.api.Test;
import java.io.*;
//编程完成图片/音乐的拷贝(要求使用Buffered...流)
public class Demo09 {
    public static void main(String[] args) {
    }
    @Test
    public void copyFile() throws IOException {
        String srcPath = "/Users/liushaoqin/Desktop/兔年快乐.jpg";
        String destPath = "/Users/liushaoqin/Desktop/兔年快乐1.jpg";
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcPath));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destPath));
        byte[] bytes=new byte[1024];
        int readLen;
        while ((readLen=bufferedInputStream.read(bytes))!=-1){
            bufferedOutputStream.write(bytes,0,readLen);
        }
        if (bufferedInputStream!=null){
            bufferedInputStream.close();
        }
        if (bufferedOutputStream!=null){
            bufferedOutputStream.close();
        }
    }
}
 
package com.lsq.study.IO流;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
//演示序列化用法,使用ObjectOutputStream序列化基本数据和一个Dog对象(name,age)
// 并保存到data.dat文件中
public class Demo10 {
    public static void main(String[] args) throws IOException {
        String filePath = "/Users/liushaoqin/Desktop/data.dat";
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
        objectOutputStream.writeInt(100);
        objectOutputStream.writeBoolean(true);
        objectOutputStream.writeChar('a');
        objectOutputStream.writeUTF("刘文姬");
        objectOutputStream.writeObject(new Dog("小绿",3));
        objectOutputStream.close();
    }
}
 
package com.lsq.study.IO流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
//使用ObjectInputStream读取data.dat并反序列化恢复数据
public class Demo11 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String filePath="/Users/liushaoqin/Desktop/data.dat";
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
        //读取的时候必须按照序列化的顺序读取,否则会抛出异常
        System.out.println(objectInputStream.readInt());
        System.out.println(objectInputStream.readBoolean());
        System.out.println(objectInputStream.readChar());
        System.out.println(objectInputStream.readUTF());
        Object object = objectInputStream.readObject();
        System.out.println(object.getClass());
        System.out.println("当前对象"+object);
        objectInputStream.close();
    }
}
 
package com.lsq.study.IO流;
import java.io.Serializable;
public class Dog implements Serializable {
    private String name;
    private int age;
    //serialVersionUID序列化的版本号,可以提高兼容性
    //例如,当添加新的属性时不会认为是一个新的Dog类而是在原版本上做升级
    private static final long serialVersionUID =1L;
    public Dog(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 "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
 

注意事项

  1. 读写顺序要一致

  2. 要求序列化或反序列化对象,需要实现Serializable

  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性

  4. 序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口

  6. 序列化具备可继承行,也就是说如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

标准输入输出流

 类型默认设备
System.in 标准输入 InputStream 键盘
System.out 标准输出 PrintStream 显示器

转换流InputStreamReader和OutputStreamWriter

字节流----》字符流

  1. InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)

  2. OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)

  3. 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流

  4. 可以在使用时指定编码格式(比如utf-8,gbk,gb2312,ISO8859-1等)

package com.lsq.study.IO流;
import java.io.*;
//演示使用InputStreamReader转换流解决中文乱码问题
//将字节流FileInputStream转化成字节流InputStreamReader,指定编码gbk/utf-8
public class Demo12 {
    public static void main(String[] args) throws IOException {
        String filePath = "/Users/liushaoqin/Desktop/note.txt";
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "utf-8");
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String s = bufferedReader.readLine();
        System.out.println(s);
    }
}
 
package com.lsq.study.IO流;
import java.io.*;
//演示OutputStreamWriter使用
//把FileOutputStream字节流转换成字符流OutputStreamWriter
public class Demo13 {
    public static void main(String[] args) throws IOException {
        String filePath = "/Users/liushaoqin/Desktop/note.txt";
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), "utf-8");
        //BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        outputStreamWriter.write("加油,希望总在前方!");
        outputStreamWriter.close();
    }
}
 

打印流PrintStream(字节)和PrintWriter(字符)

打印流只有输出流没有输入流

package com.lsq.study.IO流;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
//演示PrintStream(字节打印流)
public class Demo14 {
    public static void main(String[] args) throws IOException {
        PrintStream out = System.out;
        //在默认情况下,PrintStream输出数据的位置是标准输出,即显示器
        out.println("Hello,world");
        out.write("刘文姬".getBytes());
        out.close();
        //可以修改打印流输出的位置/设备
        System.setOut(new PrintStream("/Users/liushaoqin/Desktop/note.txt"));
        System.out.println("加油,你一定可以找到一个新工作 ");
    }
}
 
package com.lsq.study.IO流;
import java.io.*;
//演示PrintWriter使用方式
public class Demo15 {
    public static void main(String[] args) throws IOException {
        //PrintWriter printWriter = new PrintWriter(System.out);
        PrintWriter printWriter = new PrintWriter(new FileWriter("/Users/liushaoqin/Desktop/note.txt"));
        printWriter.println("Hello,刘文姬");
        printWriter.close();
    }
}

Properties类

  1. 专门用于读取配置文件的集合类

    • 配置文件的格式

    • 键=值

    • 键=值

  2. 注意:键值对不需要有空格,值不需要引号引起来,默认类型是String

  3. Properties的常见方法

    • load:加载配置文件的键值对到Properties对象

    • list:将数据显示到指定设备/流对象

    • getProperty(key):根据键获取值

    • s etProperty(key,value):设置键值对到Properties对象

    • store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode编码

package com.lsq.study.IO流;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class Demo16 {
    public static void main(String[] args) throws IOException {
        //使用Properties类来读取mysql.properties文件
        //1.创建Properties对象
        Properties properties = new Properties();
        //2.加载指定配置文件
        properties.load(new FileReader("src/mysql.properties"));
        //3.把k-v显示到控制台
        properties.list(System.out);
        //4.根据key获取value值
        String user = properties.getProperty("user");
        String pwd = properties.getProperty("pwd");
        System.out.println("用户名="+user);
        System.out.println("密码="+pwd);
    }
}
 
package com.lsq.study.IO流;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
//
public class Demo17 {
    public static void main(String[] args) throws IOException {
        //使用Properties类来创建配置文件,修改配置文件内容
        //创建
        //1.如果该文件没有key,就是创建
        //2.如果该文件有key,就是修改
        Properties properties = new Properties();
        properties.setProperty("charset","utf-8");
        properties.setProperty("user","文姬");
        properties.setProperty("pwd","1234");
        //将k-v存储文件中即可
        properties.store(new FileOutputStream("src/mysql2.properties"),null);
    }
}

例题1

   public void h1() throws IOException {
        String directoryPath="/Users/liushaoqin/Desktop/mytemp";
        File file = new File(directoryPath);
        if (!(file.exists())) {
            if(file.mkdirs()){
                System.out.println("创建"+directoryPath+"目录成功");
            }else {
                System.out.println("创建"+directoryPath+"目录失败");
            }
        }
        String filePath=directoryPath+"/hello.txt";
        file= new File(filePath);
        if(!(file.exists())){
            if(file.createNewFile()){
                System.out.println("创建"+filePath+"文件成功");
                BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
                bufferedWriter.write("Hello,world!");
            }else {
                System.out.println("创建" + filePath + "文件失败");
            }
        }else {
            System.out.println(filePath+"文件已存在");
        }
    }

 例题2

   public void h2() throws IOException {

        String filePath="/Users/liushaoqin/Desktop/note.txt";
        FileInputStream fileInputStream = new FileInputStream(filePath);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream,"UTF-8"));
        int i=0;
        String s="";
        while ((s=bufferedReader.readLine())!=null){
            System.out.println(++i+s);
        }
        bufferedReader.close();
   }

例题3

 
    public void h3() throws IOException {
        Properties properties = new Properties();
        properties.load(new FileReader("src/dog.properties"));
        properties.list(System.out);
        //返回的是Object类型,在后面加一个空串,Object-》string
        String name = properties.get("name")+"";
        //Onject-->int
        int age = Integer.parseInt(properties.get("age")+"");
        String color = properties.get("color")+"";
        Dog_ dog = new Dog_(name,age,color);
        System.out.println(dog);
        String filePath="src/dog.dat";
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
        objectOutputStream.writeObject(dog);
        objectOutputStream.close();
    }
 
    //再编写一个方法,反序列化dog
    @Test
    public void inSer() throws IOException, ClassNotFoundException {
        String filePath="src/dog.dat";
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
        Dog_ dog = (Dog_) objectInputStream.readObject();
        System.out.println("=============反序列化后dog=========");
        System.out.println(dog);
        objectInputStream.close();
    }
class Dog_ implements Serializable{
    private String name;
    private int age;
    private String color;
    public Dog_(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
    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;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Dog_{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
} 
posted @ 2023-07-18 21:33  仓鼠的气垫床  阅读(5)  评论(0编辑  收藏  举报