java-IO流基础知识

IO流

文件

  • 文件就是保存数据的地方
  • 文件流:文件在程序中是以流的形式来操作的
  • 输入流:数据从文件(硬盘)读取到程序(内存)
  • 输出流:数据从程序(内存)写入到文件(硬盘)

常用的文件操作

  • 创建文件对象相关构造器和方法
new File(String pathname)//根据路径构建一个文件
new File(File parent,String child)//根据父目录文件+子路径构建
new File(String parent,String child)//根据父路径+子路径构建
createNewFile 创建新文件
  • 获取文件的相关信息
@Test
    public void info() {
        //创建文件对象
        File file = new File("G:\\xinfan\\note\\a.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.isFile());
        //是否为文件夹
        System.out.println("是否为文件夹:"+file.isDirectory());
    }
  • 目录的操作和文件删除
@Test
    public void m1(){
        File file = new File("G:\\xinfan\\note\\a.txt");
        if (file.exists()) {
            if (file.delete()) {
                System.out.println("文件被删除");
            } else {
                System.out.println("文件删除失败");
            }
        }
    }

    @Test
    public void m2() {
        //文件夹也是文件的一种
        String path = "G:\\xinfan\\note\\a\\b\\c";
        File file = new File(path);
        if (file.exists()) {
            System.out.println(path + "已经存在");
        } else {
            file.mkdirs();
            System.out.println(path+"被创建");
        }
    }

IO流原理及流的分类

Java IO流原理

  1. I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件、网络通讯等
  2. Java程序中,对于数据的输入/输出操作以“流”的方式进行
  3. java.io包下提供了各种“流”接口和类,用以获取不同种类的数据,并通过方法输入和输出数据
  4. 输入Input:读取外部数据(存储设备的数据)到程序(内存)中
  5. 输出Output:将程序中处理过的数据写入存储设备

流的分类

  • 按操作数据单位不同分为:字节流(用于操作二进制文件)、字符流
  • 按数据流的流向不同分为:输入流、输出流
  • 按流的角色的不同分为:节点流、处理流/包装流
(抽象基类)字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

常用的类

InputStream/OutputStream:字节输入/出流
  • FileInputStream/FileOutputStream:文件输入/出流
/**
     * 读取单个字节 效率比较低
     * ----------->read(byte[] b)
     */
    @Test
    public void read1() {
        String path = "G:\\桌面\\test.txt";
        FileInputStream fileInputStream = null;
        int readData = 0;

        try {
            fileInputStream = new FileInputStream(path);

            while ((readData = fileInputStream.read()) != -1) {//每次向后读一个 所以必须放在判断条件里面
                System.out.print((char) (readData));//utf-8 三个字节为一个字符  所以会中文乱码
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


    /**
     * read(byte[] b)
     */
    @Test
    public void read2() {
        String path = "G:\\桌面\\test.txt";
        FileInputStream fileInputStream = null;

        byte[] buf = new byte[3];
        int length = 0;

        try {
            fileInputStream = new FileInputStream(path);

            while ((length = fileInputStream.read(buf)) != -1) {
                System.out.print(new String(buf,0,length));
                /*System.out.print(new String(buf));//不截取长度最后一次会填入之前的值 不会自动清空
                System.out.println();*/
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


//FileOutPutStream
@Test
    public void write1() {
        String out = "hello000 world";

        String filename = "G:\\桌面\\out.txt";
        FileOutputStream fileOutputStream = null;

        File file = new File(filename);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            fileOutputStream = new FileOutputStream(file);//新的内容会覆盖原来的内容
            //fileOutputStream = new FileOutputStream(file,true);以追加的方式添加
            /*char[] chars = out.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                fileOutputStream.write(chars[i]);

            }*/

            fileOutputStream.write(out.getBytes());
            // void write(byte[] b, int off, int len)
            //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • BufferedInputStream/BufferedOutputStream:缓冲字节输入/出流
package com.xinfan.io.buffered;

import java.io.*;

/**
 * @Author xin
 * @Date 2022/6/8 21:30
 * @Version 1.0
 *
 * 字节处理流拷贝文件
 */
public class BufferedInputStream_ {
    public static void main(String[] args) throws IOException {

        BufferedInputStream bis = null;

        BufferedOutputStream bos = null;

        String path = "G:\\桌面\\11111.png";
        String des = "G:\\桌面\\1111.png";

        byte[] bytes = new byte[1024];
        int readLen = 0;

        bis = new BufferedInputStream(new FileInputStream(path));

        bos = new BufferedOutputStream(new FileOutputStream(des));

        while ((readLen = bis.read(bytes)) != -1) {
            bos.write(bytes,0,readLen);
        }

        bos.close();
        bis.close();

    }
}

  • ObjectInputStream/ObjectOutputStream:对象字节输入/出流 提供序列化和反序列化功能

序列化和反序列化:

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

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

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

    ​ 1.Serializable //推荐使用 这是一个标记接口 没有方法

    ​ 2.Externalizable

对象处理流的注意事项

  • 读写顺序要一致
  • 要求实现序列化和反序列化的对象必须实现Serializable或者Externalizable接口
  • 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
  • 序列化对象时,默认里面所有属性都会序列化,但除了static或transient修饰的成员
  • 序列化对象时,要求里面属性的类型也需要实现序列化接口
  • 序列化具备可继承性,也就是如果一个类实现了序列化,那么它的所有子类默认也实现了序列化
public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException {

        String src = "G:\\桌面\\test.dat";

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

        System.out.println(ois.readInt());
        System.out.println(ois.readDouble());
        System.out.println(ois.readChar());
        System.out.println(ois.readUTF());
        try {
            Object object = ois.readObject();//存取顺序一定要一致否则有可能出现抓换异常
            Dog dog = (Dog)object;
            System.out.println(dog);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

      ois.close();


    }
}

public class ObjectOutputStream_ {
    public static void main(String[] args) throws IOException {

        String des = "G:\\桌面\\test.dat";

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(des));
        oos.writeInt(12);
        oos.writeDouble(9.9);
        oos.writeChar('中');
        oos.writeUTF("写入字符串的方法为UTF");

        oos.writeObject(new Dog("小黄",2));
        oos.close();

    }
}

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

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Reader/Writer
  • FileReader/FileWriter
public static void main(String[] args) {

        String src = "G:\\桌面\\test.txt";
        char[] data = new char[1024];
        int len = 0;
        FileReader fileReader = null;

        try {
            fileReader = new FileReader(src);
            while ((len = fileReader.read(data)) != -1) {
                System.out.print(new String(data,0,len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }


节点流和处理流

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

节点流和处理流的区别和联系

  1. 节点流是底层流/低级流,直接和数据源对接
  2. 处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来处理输入输出
  3. 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连

处理流的功能主要体现在以下两个方面

  1. 性能的提高:主要以增加缓冲的方式来提高输入输出的效率
  2. 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

处理流设计模式简单代码实现

public class BufferedReader_ extends Reader_{

    private Reader_ reader_;

    public BufferedReader_(Reader_ reader_) {
        this.reader_ = reader_;
    }

    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();
        }
    }


    public static void main(String[] args) {
        BufferedReader_ bufferedReader_ = new BufferedReader_(new StringReader_());
        bufferedReader_.readStrings(10);
    }
    

}




abstract class Reader_{
    public void readFile(){}

    public void readString(){}

}

class FileReader1 extends Reader_{

    public void readFile(){
        System.out.println("文件读取流");
    }

}

class StringReader_ extends Reader_{

    public void readString(){
        System.out.println("字符串读取流");
    }

}

转换流(字节流可以设置编码格式)

  1. InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)
  2. OutputStreamWriter:Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流)
  3. 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
  4. 可以在使用时指定编码格式(比如utf-8,gbk,gb2312,ISO8859-1等)
/**
 * @Author xin
 * @Date 2022/6/9 10:03
 * @Version 1.0
 * 通过转换流解决中文乱码问题
 */
public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("G:\\桌面\\test.txt"),"gbk");//通过字节流指定编码
        BufferedReader br = new BufferedReader(isr);
        String line;

        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();

    }
}

输入流

System.in

编译类型:InputStream

运行类型:BufferedInoutStream

输出流

System.out

编译类型:PrintStream

运行类型:PrintStream

打印流

PrintStream和PrintWriter

public class PrintStream_ {
    public static void main(String[] args) throws IOException {


        PrintStream out = System.out;
        //打印的底层就是调用的write方法
        //public void print(String s) {
        //        if (s == null) {
        //            s = "null";
        //        }
        //        write(s);
        //    }
        out.write("hihi".getBytes());
        //指定输出位置
        System.setOut(new PrintStream("G:\\桌面\\b.txt"));
        System.out.println("test");


    }
}


public class PrintWriter_ {
    public static void main(String[] args) throws IOException {
//        PrintWriter writer = new PrintWriter(System.out);

        PrintWriter writer = new PrintWriter(new FileWriter("G:\\桌面\\kkk.txt"));
        writer.write("test");
        writer.close();//一定要关闭输出流 否则写不进去

    }
}

Properties

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

配置文件的格式:

​ 键=值

​ 键=值

  1. 注意:键值对不需要有空格,值不需要用引号引起来。默认类型是string
  2. 常见方法
  • load:加载配置文件的键值对到Properties对象中

  • list:将数据显示到指定的地方

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

  • setProperty(key,value):设置键值对到Properties对象中

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

    https://tool.chinaz.com/tools/unicode.aspx unicode码查询工具

传统方式读取配置文件

public class Properties_ {
    public static void main(String[] args) {
        //传统方法读取配置文件
        tradition();
    }

    public static void tradition() {
        BufferedReader br = null;
        try {
            String line;
            br = new BufferedReader(new FileReader("src\\mysql.properties"));

            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

Properties读取/修改/保存配置文件

public class Properties2_ {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        //properties.load(new BufferedReader(new FileReader("src\\mysql.properties")));
        properties.load(new BufferedReader(new InputStreamReader(new FileInputStream("src\\mysql.properties"),"utf8")));
        properties.list(System.out);
        String user = properties.getProperty("user");//中文乱码
        System.out.println(user);

        //如果已经存在该属性就是修改值
        properties.setProperty("验证码","test");
        //BufferedWriter bw = new BufferedWriter(new FileWriter("src\\mysql2.properties"));

        properties.store(new FileOutputStream("src\\mysql2.properties"),"a");
        //properties.store(bw,"a");

    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值