IO流详解

文件流

文件在程序中是以流的形式来操作的

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

常用文件操作

创建文件的三种方式

public class FileCreate {
    public static void main(String[] args) {
        method01();
        method02();
        method03();
    }

    //方式1
    public static void method01(){
        String filePath = "D:/news1.txt";
        File file = new File(filePath);

        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //方式2 根据父目录文件+子路径构建
    public static void method02(){
        File parentFile = new File("D:/");//D:\\
        String fileName = "news2.txt";
        File file = new File(parentFile, fileName);

        try {
            file.createNewFile();
            System.out.println("创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //方式3 根据父目录+子路径构建
    public static void method03(){
        String parentPath = "D:\\";
        String fileName = "news3.txt";
        File file = new File(parentPath, fileName);

        try {
            file.createNewFile();
            System.out.println("创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

获取文件相关信息

public class FileInformation {
    public static void main(String[] args) {
        info();
    }

    //获取文件信息
    public static void info(){
        //先创建文件对象
        File file = new File("D:\\news1.txt");

        System.out.println("文件名字"+file.getName());
        System.out.println("文件绝对路径"+file.getAbsolutePath());
        System.out.println("文件父级目录"+file.getParent());
        System.out.println("文件大小(字节)="+file.length());
        System.out.println("文件是否存在"+file.exists());
        System.out.println("文件是否存在"+file.exists());
        System.out.println("是否是一个文件"+file.isFile());
        System.out.println("是否是一个目录"+file.isDirectory());
    }
}

目录操作

public static void main(String[] args) {
        m2();
    }

    //判断D:\\news.txt 是否存在,如果存在就删除
    public static void m1(){
        String filePath = "D:\\news1.txt";
        File file = new File(filePath);

        if (file.exists()){
            if (file.delete()) {
                System.out.println(filePath+"删除成功");
            } else {
                System.out.println(filePath+"删除失败");
            }
        }else {
            System.out.println("文件不存在");
        }
    }

    //判断D:\\demo是否存在,存在就删除
    //在java编程中,目录也被当做文件
    public static void m2(){
        String directoryPath = "D:\\demo";
        File file = new File(directoryPath);

        if (file.exists()){
            if (file.delete()) {
                System.out.println(directoryPath+"删除成功");
            } else {
                System.out.println(directoryPath+"删除失败");
            }
        }else {
            System.out.println("目录不存在");
        }
    }

    //判断D:\\demo\\a\\b是否存在,存在就提示存在信息,否则就创建
    public static void m3(){
        String directoryPath = "D:\\demo\\a\\b";
        File file = new File(directoryPath);

        if (file.exists()){
            System.out.println("该目录存在");
        }else {
            if (file.mkdirs()){//创建多级目录
                System.out.println("创建成功");
            }else {
                System.out.println("创建失败");
            }
        }
    }
}

流的分类

  • 按操作数据单位不同分为:字节流(8 bit),字符流(按字符)
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色不同分为:节点流,处理流/包装流
(抽象基类)字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

(Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行)

字节流

字节输入流 FileInputStream

public class FileInputStream_ {
    public static void main(String[] args) {
        readFile02();
    }

    //read(int a)单个字节地读取,效率比较低
    public static void readFile01(){
        FileInputStream fileInputStream = null;
        String filePath = "D:\\hello.txt";
        int readData = 0;
        try {
            //创建 FileInputStream 对象用于读取文件
            fileInputStream = new FileInputStream(filePath);

            //如果返回-1,表示读取完毕
            while ((readData = fileInputStream.read())!=-1){
                System.out.print((char) readData);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //使用read(byte[] b) 读取文件提高效率
    public static void readFile02(){
        FileInputStream fileInputStream = null;
        String filePath = "D:\\hello.txt";
        byte[] buffer = new byte[8];//一次读取8个字节
        int len = 0;
        try {
            fileInputStream = new FileInputStream(filePath);

            //如果返回-1,表示读取完毕
            //如果读取正常,返回实际读取的字节数
            while ((len = fileInputStream.read(buffer))!=-1){
                System.out.println(new String(buffer,0,len));
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

字节输出流 FileOutputStream

  1. 覆盖模式:FileOutputStream fileOutputStream = new FileOutputStream(File/String) 写入内容会覆盖原来的内容
  2. 追加模式:FileOutputStream fileOutputStream = new FileOutputStream(File/String,true) 写入内容会追加到原内容末尾
public class FileOutputStream01 {
    public static void main(String[] args) {
        writeFile();
    }

    //将数据写到文件中,如果文件不存在则创建该文件
    public static void writeFile(){
        String filePath = "D:\\a.txt";
        FileOutputStream fileOutputStream = null;

        try {
            fileOutputStream = new FileOutputStream(filePath);

            /*
            写入一个字节
            fileOutputStream.write('H');//char和int类型相互转换
            */

            //写入字符串
            String str = "hello, world!";

            //str.getBytes()可以把字符串转换为字节数组
            //fileOutputStream.write(str.getBytes());

            fileOutputStream.write(str.getBytes(),1,5);
            System.out.println(str.length());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

文件拷贝

public class FileCopy {
    public static void main(String[] args) {
        //1.创建文件输入流,将文件读取到程序
        //2.创建文件输出流,将读取到的数据写入指定文件
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        String srcFilePath = "D:\\hello.txt";
        String destFilePath = "D:\\hello2.txt";

        try {
            fileInputStream = new FileInputStream(srcFilePath);
            fileOutputStream = new FileOutputStream(destFilePath);
            //定义一个字节数组提高读取效率
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len=fileInputStream.read(buffer))!=-1){
                fileOutputStream.write(buffer,0,len);
            }
            System.out.println("拷贝完毕");
        } 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);
            }
        }
    }
}

字符流

字符输入流 FileReader

public class FileReader_ {
    public static void main(String[] args) {
        method02();
    }

    //单个字符读取文件
    public static void method01(){
        String filePath = "D:\\code.txt";
        FileReader fileReader = null;
        int data = 0;
        try {
            //1.创建FileReader对象
            fileReader = new FileReader(filePath);
            //使用read循环读取,单个读取
            while ((data=fileReader.read())!=-1){
                System.out.print((char) data);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (fileReader != null){
                    fileReader.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //字符数组读取文件
    public static void method02(){
        String filePath = "D:\\code.txt";
        FileReader fileReader = null;
        int len = 0;
        char[] buffer = new char[8];
        try {
            //1.创建FileReader对象
            fileReader = new FileReader(filePath);
            //返回的是实际读到的字符数,如果返回为-1说明文件读取完毕
            while ((len=fileReader.read(buffer))!=-1){
                System.out.print(new String(buffer,0,len));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (fileReader != null){
                    fileReader.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

字符输出流 FileWriter

  1. 覆盖模式:FileWriter fileWriter = new FileWriter(File/String) 相当于流的指针在首端

  2. 追加模式:FileWriter fileWriter = new FileWriter(File/String,true) 相当于流的指针在首端

  3. 注意:FileWriter使用后,必须要关闭(close)或者刷新(flush),否则写入不到指定文件

public class FileWriter_ {
    public static void main(String[] args) {
        String filePath = "D:\\note.txt";
        FileWriter fileWriter = null;
        char[] chars = {'a','b','c'};

        try {
            //创建FileWriter对象
            fileWriter = new FileWriter(filePath);

            //write(int)写入单个字符
            //fileWriter.write('j');

            //write(char[])写入指定数组
            //fileWriter.write(chars);

            //write(char[],off,len)写入数组的指定部分
            //fileWriter.write("歪比歪比,歪比巴卜".toCharArray(),0,4);

            //write(String)写入整个字符串
            //fileWriter.write("你好你好");

            //write(String,off,len)写入字符串指定部分
            fileWriter.write("你好你好",0,3);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (fileWriter!=null){
                    fileWriter.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("end");
    }
}

节点流和处理流

  • 基本介绍

    1. 节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter
    2. 处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更强大、更灵活的读写功能,如BufferedReader、BufferedWriter
  • 节点流和处理流的区别和联系

    1. 节点流是底层流/低级流,直接跟数据源相接

    2. 处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出

    3. 处理流对节点流进行包装,使用了修饰器设计模式,不会直接于数据源相连

  • 处理流主要功能体现

    1. 性能提高:主要以增加缓冲的方式来提高输入输出的效率

    2. 操作便捷:处理流提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

处理流设计模式演示

  • Reader_ 抽象父类

    public abstract class Reader_ {
        public void readFile(){}
        public void readString(){}
    	//使用抽象方法统一管理
        //public abstract void read();
    }
    

注意:父类中用抽象方法统一管理read()方法使效率更高,后面在调用时,利用对象动态绑定机制,绑定到对应的实现子类即可

  • FileReader_ 节点流

    public class FileReader_ extends Reader_{
        public void readFile(){
            System.out.println("对文件进行读取。。。");
        }
    }
    
  • StringReader_ 节点流

    public class StringReader_ extends Reader_{
        public void readString(){
            System.out.println("对字符串进行读取。。。");
        }
    }
    
  • BufferedReader_ 处理流

    public class BufferedReader_ extends Reader_{
        private Reader_ reader_;
    
        public BufferedReader_(Reader_ reader_) {
            this.reader_ = reader_;
        }
    
        //对原方法封装一层,这样才能使用,不然会跳到父类Reader_
        public void readFile(){
            reader_.readFile();
        }
    
        public void readString(){
            reader_.readString();
        }
    
        //拓展功能
        //让方法更灵活,多次读取文件、字符串
        public void readFiles(int num){
            for (int i = 0; i < num; i++) {
                reader_.readFile();
            }
        }
    
        public void readStrings(int num){
            for (int i = 0; i < num; i++) {
                reader_.readString();
            }
        }
    }
    
  • Test_ 测试类

    public class Test_ {
        public static void main(String[] args) {
            BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
            bufferedReader_.readFile();
        }
    }
    

处理流

字符流 BufferedReader

public class BufferedReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "D:\\a.java";
        //创建BufferedReader
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        String line;
        while ((line = bufferedReader.readLine())!=null){//按行读取,当返回为null时,表示读取完毕
            System.out.println(line);
        }
        //关闭资源
        bufferedReader.close();
    }
}

字符流 BufferedWriter

public class BufferedWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "D:\\ok.txt";
        //创建BufferedWriter
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));//覆盖模式
        //BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true)); 追加模式
        bufferedWriter.write("hello,幸会幸会!");
        bufferedWriter.newLine();//插入一个和系统相关的换行
        bufferedWriter.write("hello2,幸会幸会!");
        bufferedWriter.newLine();

        bufferedWriter.close();
    }
}

字符处理流拷贝

注意:BufferedReader和BufferedWriter是按字符操作,不要去操作二进制文件,可能造成文件损坏

public class BufferedCopy_ {
    public static void main(String[] args) {
        String srcFilePath = "D:\\a.java";
        String destFilePath = "D:\\a2.java";
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        String line = null;

        try {
            bufferedReader = new BufferedReader(new FileReader(srcFilePath));
            bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));

            while ((line= bufferedReader.readLine())!=null){
                bufferedWriter.write(line);
                bufferedWriter.newLine();
            }

            System.out.println("拷贝完毕");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            //关闭资源
            try {
                if (bufferedReader!=null){
                    bufferedReader.close();
                }
                if (bufferedWriter!=null){
                    bufferedWriter.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

字节处理流拷贝

public class BufferedCopy_ {
    public static void main(String[] args) {
        String srcPath = "D:\\img.jpg";
        String destPath = "D:\\img2.jpg";
        BufferedInputStream bis = null;
        BufferedOutputStream bos =null;
        byte[] buffer = new byte[8];
        int len = 0;
        try {
            bis = new BufferedInputStream(new FileInputStream(srcPath));
            bos = new BufferedOutputStream(new FileOutputStream(destPath));

            while ((len=bis.read(buffer))!=-1){
                bos.write(buffer,0,len);
            }
            System.out.println("拷贝完毕");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (bos != null){
                    bos.close();
                }
                if (bis!=null){
                    bis.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

对象流

  1. 序列化:保存数据时,保存数据的值数据类型
  2. 反序列化:恢复数据时,恢复数据的值数据类型
  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,该类必须实现如下两个接口之一:
    • Serializable 标记接口,没有方法
    • Externalizable
  4. 注意:反序列化顺序要和序列化顺序一致
  5. 序列化的类中建议添加SerialVersionUID以提高兼容性
  6. 序列化对象时,默认将里面的所有属性都进行序列化,static和transient修饰的成员除外
  7. 序列化对象时,要求里面的属性也需要实现序列化接口
  8. 序列化具备可继承性

  • 准备一个支持序列化的类
public class Dog implements Serializable {
    private String name;
    private int age;
    private static String nation;
    private transient String color;

    public Dog(String name, int age, String nation,String color) {
        this.name = name;
        this.age = age;
        this.nation = nation;
        this.color = color;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", nation=" + nation +
                ", 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 static String getNation() {
        return nation;
    }

    public static void setNation(String nation) {
        Dog.nation = nation;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}
  • 序列化 ObjectOutputStream
public class ObjectOutputStream_ {
    public static void main(String[] args) throws IOException {
        //序列化后,保存的文件格式是按照系统格式来保存
        String filePath = "D:\\data.dat";

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));

        //序列化数据到D:\data.dat
        oos.writeInt(100);//int -> Integer(实现了serializable)
        oos.writeBoolean(true);//boolean -> Boolean
        oos.writeChar('c');//char -> Character
        oos.writeDouble(9.5);//double -> Double
        oos.writeUTF("歪比巴卜");//String
        //保存对象
        oos.writeObject(new Dog("旺财",2,"Japan","brown"));

        oos.close();
        System.out.println("保存完毕");
    }
}
  • 反序列化 ObjectInputStream
public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //指定反序列化文件
        String filePath = "D:\\data.dat";

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));

        //读取顺序要和保存时的顺序一致
        System.out.println(ois.readInt());
        System.out.println(ois.readBoolean());
        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());
        //dog的编译类型是Object,dog的运行类型是Dog
        Object dog = ois.readObject();
        System.out.println("运行类型:"+dog.getClass());
        System.out.println("dog信息:"+dog);//底层 Object -> Dog

        //注意
        //1.如果希望调用Dog的方法,需要向下转型
        //2.需要将Dog类的定义放在可以引用的地方
        Dog dog2 = (Dog)dog;
        System.out.println(dog2.getName());

        ois.close();
    }
}
  • 打印结果:
100
true
c
9.5
歪比巴卜
运行类型:class outputStream_.Dog
dog信息:Dog{name='旺财', age=2, nation=null, color='null'}
旺财

转换流

标准输入输出

类型默认设备
System.inInputStream键盘
System.outPrintStream显示器

编码问题

public class CodeQuestion {
    public static void main(String[] args) throws IOException {
        //1. 创建字符输入流 BufferedReader 处理流
        //2. 使用BufferedReader对象读取a.txt
        //3. 默认情况下,读取文件按照utf-8编码
        String filePath = "D:\\a.txt";
        BufferedReader br = new BufferedReader(new FileReader(filePath));

        String s = br.readLine();
        System.out.println("读取到的内容:"+s);
        br.close();
    }
}

如果读取的文件编码格式不为utf-8则会出现乱码,这时就需要用转换流指定编码格式

InputStreamReader

//将字节流FileInputStream转成字符流InputStreamReader,指定编码gbk/utf-8
public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "D:\\a.txt";
        //1.把FileInputStream 转成 InputStreamReader,指定gbk编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath),"gbk");
        //2.把InputStreamReader传入BufferedReader
        BufferedReader br = new BufferedReader(isr);

        //BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk"));
        //3.读取
        String s = br.readLine();
        System.out.println("读取到的内容:"+s);
        //4.关闭外层流
        br.close();
    }
}

OutputStreamWriter

//把字节流FileOutputStream转成字符流OutputStreamWriter,指定编码gbk/utf-8
public class OutputStreamWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "D:\\nb.txt";
        String charSet = "gbk";
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
        osw.write("hi,你真厉害!");
        osw.close();
        System.out.println("按照"+charSet+"方式保存文件");
    }
}

打印流

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

字节打印流 PrintStream

public class PrintStream_ {
    public static void main(String[] args) throws IOException {
        PrintStream out = System.out;
        //默认情况下PrintStream的输出位置是标准输出
        out.print("hello,john");
        //print底层使用write进行打印
        out.write("你好你好".getBytes());
        out.close();

        //修改打印流输出的位置/设备
        System.setOut(new PrintStream("D:f1.txt"));
        System.out.println("hi,玛卡巴卡");
    }
}

字符打印流 PrintWriter

public class PrintWriter_ {
    public static void main(String[] args) throws IOException {
        //PrintWriter printWriter = new PrintWriter(System.out);
        PrintWriter printWriter = new PrintWriter(new FileWriter("D:\\f2.txt"));
        printWriter.println("hi,玛卡巴卡");
        printWriter.close();//不写这个就无法写入数据
    }
}

Properties

基本介绍

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

    配置文件的格式:

    键=值

    键=值

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

  3. 常用方法

    • load:加载配置文件的键值对到properties对象
    • list:将数据显示到指定设备
    • getProperty(key):根据键值获取值
    • setProperty(key,value):设置键值对的值,没有则创建再赋值
    • store:将properties中的键值对存储到配置文件,在idea中,保存信息到配置文件

需求

  • 目标文件 mysql.properties

    ip=192.168.100.100
    user=root
    pwd=123456
    
  • 疑问:读取ip、user、pwd的值

传统方法

public class Properties01 {
    public static void main(String[] args) throws IOException {
        //读取mysql.properties文件并获取ip user pwd
        BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));
        String line = "";
        while ((line = br.readLine())!=null){//循环读取
            //System.out.println(line);
            String[] split = line.split("=");
            System.out.println(split[0]+"的值="+split[1]);
        }
        br.close();
    }
}

properties 读取文件

public class Properties02 {
    public static void main(String[] args) throws IOException {
        //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);
    }
}

properties 修改文件

//使用properties类来创建或修改配置文件
public class Properties03 {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();

        properties.setProperty("charser","utf-8");
        properties.setProperty("user","汤姆");//中文用unicode码存入
        properties.setProperty("pwd","abc111");

        //将k-v从内存中存入配置文件
        properties.store(new FileOutputStream("src\\mysql2.properties"),null);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值