栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVA学习之IO流

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA学习之IO流

IO流

【1】文件 目录
文件:
内存中存放的数据在计算机关机后就会消失,要长久保存数据,就要使用硬盘,光盘,U盘等设备,为了便于数据的管理和检索,引入了"文件"的概念,操作系统以文件为单位管理磁盘中的数据
从数据存储的角度说,所有的文件本质都是一样的,都是由一个个字节组成的,归根到底都是0,1比特串。
文件夹
n多个文件,如果不分类放在一起,用户使用起来显然非常不方便,因此又引入了树形目录(也叫文件夹)的机制,可以把文件放在不同的文件夹中。
【2】如何在java程序中操纵 文件/ 目录 ?
java程序,最典型的特点,面向对象,java程序最擅长的就是操作对象,盘符上的文件/目录,将它的各种信息进行封装,封装为一个对象。
这个对象 --> File类
即 盘符上的文件 --> 封装为对象 --> 对象属于File类的对象 --> 有了这个对象程序就可以直接操纵这个对象,通过这个对象获取文件的各种信息,还可以对文件进行创建,删除

File 类
public class Test01 {
    public static void main(String[] args) throws IOException {
        // 将文件封装为一个File类的对象
        //File file = new File("d:\test.txt");
        //File file1 = new File("d:/test.txt");
        // File.separator属性帮我们获取当前操作系统的路径拼接符号
        File file3 = new File("d:" + File.separator + "test.txt");

        // canRead canWrite  只读 只写
        file3.canRead();
        file3.canWrite();
        // 文件的名字
        file3.getName();
        // 上级目录
        file3.getParent();
        // 是否是一个目录
        file3.isDirectory();
        // 是否是一个文件
        file3.isFile();
        // 是否隐藏
        file3.isHidden();
        // 文件大小
        file3.length();
        // 是否存在
        file3.exists();
        // 删除
        file3.delete();
        // 创建一个新文件
        file3.createNewFile();

    }
}
public class Test02 {
    public static void main(String[] args) throws IOException {
        File f1 = new File("d://test.txt");
        File f2 = new File("d://aa//test.txt");
        System.out.println(f1.equals(f2)); // false

        //跟路径相关
        File f3 = new File("E:\ExerciseJava\day1.txt");
        System.out.println(f3.getAbsoluteFile());
        System.out.println(f3.getAbsolutePath());
        System.out.println(f3.toString());

        System.out.println("---------------------------------");

        File f5 = new File("demo.txt");
        if(!f5.exists()){
            f5.createNewFile();
        }
        // 绝对路径 F:projectLearningJavademo.txt
        System.out.println(f5.getAbsolutePath());
        System.out.println(f5.getAbsoluteFile());
        // 相对路径 demo.txt
        System.out.println(f5.getPath());
        // toString效果 和 相对路径相同
        System.out.println(f5.toString());

        System.out.println("---------------------------------");

        File f6 = new File("a/b/c/demo.txt");
       
        System.out.println(f6.getAbsolutePath());
        System.out.println(f6.getPath());
    }
}

对目录进行操作

public class Test03 {
    public static void main(String[] args) {
        // 将目录封装为File类的对象
        File file = new File("F:\project\LearningJava");

        // 跟目录相关的方法
        File f1 = new File("D:\a");
        // 创建单层目录
        //f1.mkdir();
        File f2 = new File("E:\ExerciseJava\a\b\c");
        // 创建多层目录
        f2.mkdirs();
        // 删除:如果只是删除目录的话,只删除一层,前提是这层目录是空的
        f2.delete();

        // 查看 目录下所有目录和文件的名称
        String[] list = file.list();
        for (String s : list) {
            System.out.println(s);
        }
        
        // listFiles()  返回File对象的数组  作用更加广泛
        File[] files = file.listFiles();
        for (File file1 : files) {
            System.out.println(file1);
        }

    }
}

File类:封装文件/目录的各种信息,对目录/文件进行操作,但是我们不可以获取到文件/目录中的内容
形象理解:IO流 当作一根“管”

IO流体系结构

FileReader && FileWriter

字符流
案例
java代码实现文件复制
功能分解1:文件 --> 程序: FileReader
一个字符一个字符的读取

public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
        // 文件 --> 内存
        File file = new File("E:\ExerciseJava\CopyTxtDemo.txt");

        // 创建一个FileReader的流的对象
        FileReader fr = new FileReader(file);

        // 读取动作
        

        // 方式1:
        

        // 方式2:
        int n1;
        while ((n1 = fr.read()) != -1) {
            System.out.println(n1);
        }

        // 关闭流
        // 流 数据库 网络资源 靠JVM本身没有办法帮我们关闭,所以此时必须程序员手动关闭
        fr.close();
    }
}

功能分解2:程序 --> 文件 : FileWriter

public class CopyFileDemo2 {
    public static void main(String[] args) throws IOException {
        String str = "abcdef你好老师";

        // 目标文件
        File f = new File("E:\ExerciseJava\DemoTest.txt");

        // FileWriter
        // FileWriter fw = new FileWriter(f,false); 原文件覆盖
        // FileWriter fw1 = new FileWriter(f,true); 原文件追加
        FileWriter fw = new FileWriter(f);

        // 输出到文件 目标文件不存在,自动创建目标文件 ,如果存在 会覆盖这个文件
        

        // 利用缓冲数组进行输出
        char[] chars = str.toCharArray();
        fw.write(chars);

        // 关闭流
        fw.close();
    }
}

实现文件复制 读取 --> 输出

public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
        File inputFile = new File("E:\ExerciseJava\CopyTxtDemo.txt");
        File outPutFile = new File("E:\ExerciseJava\CopyTxtDemoOutput.txt");

        FileReader fr = new FileReader(inputFile);

        FileWriter fw = new FileWriter(outPutFile);

        // 方式一: 一个字符一个字符
        

        // 方式二: 缓冲读取
        

        // 方式三:
        char[] chars = new char[5];
        int len = fr.read(chars);
        while (len != -1){
            // 将缓冲数组有效长度写出
            String s = new String(chars, 0, len);
            fw.write(s);
            len = fr.read(chars);
        }

        // 关闭流
        fw.close();
        fr.close();
    }
}

ps:
文本文件:.txt .java .c .cpp --> 建议使用字符流操作
非文本文件: .jpg .mp3 .mp4 .doc .ppt --> 建议使用字节流操作

利用try-catch finally 处理异常方式

public class CopyFileDemo {
    public static void main(String[] args) {
        File inputFile = new File("E:\ExerciseJava\CopyTxtDemo.txt");
        File outPutFile = new File("E:\ExerciseJava\CopyTxtDemoOutput.txt");

        FileReader fr = null;
        FileWriter fw = null;

        try{
            fr = new FileReader(inputFile);

            fw = new FileWriter(outPutFile);

            char[] chars = new char[5];
            int len = fr.read(chars);
            while (len != -1){
                // 将缓冲数组有效长度写出
                String s = new String(chars, 0, len);
                fw.write(s);
                len = fr.read(chars);
            }
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if(fw != null){// 防止空指针异常
                    fw.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }

            try{
                if(fr != null){// 防止空指针异常
                    fr.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
FileInputStream

字节流

public class Test01 {
    public static void main(String[] args) throws IOException {
        // 字节流
        File file = new File("E:\ExerciseJava\CopyTxtDemo.txt");

        FileInputStream fis = new FileInputStream(file);

        
        int read = fis.read();
        while(read != -1){
            System.out.println(read);
            read = fis.read();
        }

        fis.close();
    }
}

【2】利用字节流读取非文本文件 (以图片为例)
一个字节一个字节读取 效率低

public class Test01 {
    public static void main(String[] args) throws IOException {
        // 字节流
        File file = new File("E:\ExerciseJava\aa.png");

        FileInputStream fis = new FileInputStream(file);

        // 定义一个计数器  用来记录读入的字节的个数
        int count = 0;
        int read = fis.read();
        while (read != -1) {
            System.out.println(read);
            read = fis.read();
            count++;
        }

        System.out.println("读入字节数量" + count);

        fis.close();
    }
}

【2】利用缓冲数组 效率高

public class Test02 {
    public static void main(String[] args) throws IOException {
        // 字节流
        File file = new File("E:\ExerciseJava\aa.png");

        FileInputStream fis = new FileInputStream(file);

        // 利用缓冲数组
        byte[] b = new byte[1024*2];
        int len = fis.read(b);
        while(len != -1){
            //System.out.println(len);
            for (int i = 0; i < len; i++) {
                System.out.println(b[i]);
            }
            len = fis.read(b);
        }

        fis.close();
    }
}
【3】非文本文件复制:读入一个字节写出一个字节
```java
public class Test02 {
    public static void main(String[] args) throws IOException {
        // 字节流
        File file = new File("E:\ExerciseJava\aa.png");

        File file1 = new File("E:\ExerciseJava\aa2.png");

        FileInputStream fis = new FileInputStream(file);

        FileOutputStream fos = new FileOutputStream(file1);

        // 利用缓冲数组
        int len = fis.read();
        while(len != -1){
            fos.write(len);
            len = fis.read();
        }
        fos.close();
        fis.close();

    }
}

【4】非文本文件复制: 缓冲读取写入

public class Test02 {
    public static void main(String[] args) throws IOException {
        // 字节流
        File file = new File("E:\ExerciseJava\aa.png");

        File file1 = new File("E:\ExerciseJava\aa3.png");

        FileInputStream fis = new FileInputStream(file);

        FileOutputStream fos = new FileOutputStream(file1);

        // 利用缓冲数组
        byte[] b = new byte[1024*8];
        int len = fis.read(b);
        while(len != -1){
            fos.write(b,0,len); // ps: 重点 : 提取有效长度
            len = fis.read(b);
        }
        fos.close();
        fis.close();
    }
}
BufferedInputStream & BufferedOutputStream

缓冲字节流

【1】一个字符一个字符读
与硬盘交互次数多

【2】利用缓冲字节数组:
降低与硬盘交互次数

【3】利用缓冲区

单纯利用FileInputStream 与 FileOutputStream 是无法完成的
优化: 引入 BufferedInputStream 与 BufferOutputStream --> 处理流

public class Test06 {
    public static void main(String[] args) throws IOException {
        // 字节流
        File file = new File("E:\ExerciseJava\aa.png");

        File file1 = new File("E:\ExerciseJava\aa3.png");

        FileInputStream fis = new FileInputStream(file);

        FileOutputStream fos = new FileOutputStream(file1);

        BufferedInputStream bis = new BufferedInputStream(fis);

        BufferedOutputStream bos = new BufferedOutputStream(fos);

        byte[] b = new byte[1024*6];

        int len = bis.read(b);

        while (len != -1){
            bos.write(b,0,len);
             // 底层已经帮我们做了刷新缓冲区操作
            len = bis.read(b);
        }
        
        // 如果处理流包裹着节点流,那么其实只需要关闭高级流(处理流)
        bos.close();
        bis.close();
        fos.close();
        fis.close();
    }
}
BufferedReader && BufferedWriter
public class Test07 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\ExerciseJava\CopyTxtDemo.txt");

        File file1 = new File("E:\ExerciseJava\CopyTxtDemo11.txt");

        FileReader fr = new FileReader(file);

        FileWriter fw = new FileWriter(file1);

        BufferedReader br = new BufferedReader(fr);

        BufferedWriter bw = new BufferedWriter(fw);


        // 一个字符一个字符读
        

        // 利用缓冲数组
        char[] chars = new char[30];

        int len = br.read(chars);
        while(len != -1){
            bw.write(chars,0,len);
            len = br.read(chars);
        }

        // 方式三: 读取String

        String str = br.readLine();
        while(str != null){ // 每次读取文本文件中一行,然后返回对应字符串
            bw.write(str);
            // 在文本文件中,应该在写出一个换行
            bw.newLine();// 新起一行
            str = br.readLine();
        }

        bw.close();
        br.close();
    }
}
InputStreamReader && OutputStreamWriter

【1】转换流: 作用:将字节流和字符类进行转换
InputStreamReader 与 OutputStreamWriter 属于 字符流
InputStreamReader: 将字节输入流 --> 转换为字符的输入
OutputStreamWriter:将字节输出流 --> 转换为字符的输出

public class Test08 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\ExerciseJava\CopyTxtDemo.txt");

        File file1 = new File("E:\ExerciseJava\CopyTxtDemo12.txt");

        FileInputStream fis = new FileInputStream(file);

        FileOutputStream fos = new FileOutputStream(file1);

        // 将字节转换为字符的时候,需要指定一个编码,与文件本身的编码格式统一
        // 不指定编码格式,就会获取程序本身的编码 --> utf-8
        InputStreamReader isr = new InputStreamReader(fis,"utf-8");

        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");

        char[] chars = new char[20];
        int len = isr.read(chars);
        while (len != -1){
            osw.write(chars,0,len);
            len = isr.read(chars);
        }
        osw.close();
        isr.close();
        fos.close();
        fis.close();

    }
}
System类对IO流的支持

System类
System.in 获取标准输入流 --> 默认从键盘输入

public class Test01 {
    public static void main(String[] args) throws IOException {
        //InputStream in = System.in;
        //int n = in.read(); // read()方法等待键盘的录入,所以这个方法是一个阻塞方法
        //System.out.println(n);

        // 以上案例:从键盘录入一个int类型的数据:
        // 从上面的代码证明,键盘录入实际上是:System.in
        // 形象理解:从键盘上输入的东西,顺着这个System.in这个流,流向了程序内存
        // Scanner作用:扫描器:起扫描作用的,扫键盘通过流 流出来的数据
        // Scanner sc = new Scanner(System.in)

        // 既然Scanner 的其他应用:
        Scanner sc = new Scanner(new FileInputStream(new File("E:\ExerciseJava\CopyTxtDemo.txt")));
        while(sc.hasNext()){
            System.out.println(sc.next()); //abc你好
        }
    }
}

System.out 获取标准输出流 --> 默认输入到显示器

public class Test02 {
    public static void main(String[] args) {
        PrintStream out = System.out;
        out.print("nihao1");// 直接在控制台写出,不换行
        out.print("nihao2");
        out.print("nihao3");
        out.println("nihao4");
        out.println("nihao5");
        out.println("nihao6");

        System.out.println("Hello.World");
    }
}

案例: 键盘录入内容输出到文件中
思路:

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

        InputStream in = System.in;

        // 字节流 --> 字符流
        InputStreamReader isr = new InputStreamReader(in);

        // 缓冲流
        BufferedReader br = new BufferedReader(isr);

        File file = new File("E:\ExerciseJava\out.txt");

        FileWriter fw = new FileWriter(file);

        BufferedWriter bw = new BufferedWriter(fw);

        String s = br.readLine();
        while(!s.equals("exit")){
            bw.write(s);
            bw.newLine();// 换行操作
            s = br.readLine();
        }

        bw.close();
        br.close();
    }
}
DataInputStream && DataOutputStream

【1】数据流:用来操作基本数据类型和字符串的
DataInputStream:将文件中存储的基本数据类型和字符串 写入内存的变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量 写出 文件中
DataOutputStream 例子

public class Test04 {
    public static void main(String[] args) throws IOException {
        // DataOutputStream:
        File f = new File("");
        //FileOutputStream fos = new FileOutputStream(f);
        //DataOutputStream dos = new DataOutputStream(fos);
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("E:\ExerciseJava\D1.txt")));
        dos.writeUTF("你好");
        dos.writeBoolean(false);
        dos.writeInt(1);
        dos.writeShort(1);

        dos.close();
    }
}


DataInputStream 例子

public class Test05 {
    public static void main(String[] args) throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream(new File("E:\ExerciseJava\D1.txt")));
        System.out.println(dis.readUTF());
        System.out.println(dis.readBoolean());
        System.out.println(dis.readInt());
        System.out.println(dis.readShort());
        dis.close();
    }
}


ps: 写出的类型一定要跟读入的类型 匹配 顺序一致

ObjectInputStream && ObjectOutputStream

【1】对象流: 用于存储和读取基本数据类型数据或对象的处理流
它的强大之处就是可以把JAVA中的对象写入到数据源中,也能把对象从数据源还原回来

【2】序列化和反序列化
ObjectOutputStream类:把内存中的java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久地保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点。 --> 序列化
用ObjectInputStream类: 当其他程序获取了这种二进制数据,就可以恢复成原来的java对象。 --> 反序列化

将字符串对象写入到文件中去 序列化

public class Test01 {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\ExerciseJava\outObject.txt")));
        oos.writeObject("你好");
        oos.close();
    }
}

查看文件:

将文件中的对象读入内存 反序列化

public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:\ExerciseJava\outObject.txt")));
        Object o = ois.readObject();
        String str = (String) o;
        System.out.println(str);
        ois.close();
    }
}

查看控制台

操作自定义类的序列化与反序列化

自定义Person类

public class Person {
    private int age;
    private String name;

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

    public Person() {
    }

    public int getAge() {
        return age;
    }
    
    

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

    public String getName() {
        return name;
    }

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

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

public class Test01 {
    public static void main(String[] args) throws IOException {
        Person p = new Person(19,"lili");

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\ExerciseJava\outPersonObject.txt")));

        oos.writeObject(p);

        oos.close();

    }
}

运行时出现异常: 原因 :未进行序列化
想要序列化的对象对应的类必须要实现serializable接口
Serializable接口内部,什么都没有,这种接口叫,标识接口,起标识作用

public class Person implements Serializable {
	private static final long serialVersionUID = 1223L;
    private int age;
    private String name;

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

    public Person() {
    }

    public int getAge() {
        return age;
    }



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

    public String getName() {
        return name;
    }

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

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

序列化对象到文件

public class Test01 {
    public static void main(String[] args) throws IOException {
        Person p = new Person(19,"lili");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\ExerciseJava\outPersonObject.txt")));
        oos.writeObject(p);
        oos.close();
    }
}

从文件将序列化文件读入内存

public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:\ExerciseJava\outPersonObject.txt")));
        Person person = (Person) ois.readObject();
        System.out.println(person);
        ois.close();
    }
}

【3】serialVersionUID
凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态变量
1.private static final long serialVersionUID;
2.serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容
3.如果类没有显示定义这个静态变量,它的值是java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID可能发生变化,故建议显式声明
4.简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)

Idea中配置序列化版本号



【4】序列化的细节
1.被序列化的类的内部属性都是可以被序列化的(基本数据类型,都是可序列化的)
2.static , transient修饰的属性,不可被序列化

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/820079.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号