Java的IO流基础学习


本篇文章只对常用的Java流做基础介绍,主要是文件流,还会包括各种流之间的关系,对Java也是初学者水平,有错误希望大家指正。

流的简介

下面是总结的思维导图,可以先有个结构层次概念
在这里插入图片描述
当涉及到数据交互的时候,Java就使用流来实现。数据源可以是数据库、磁盘文件、网络数据等。

打个比喻,这是我对数据和流的理解,数据库就好比一个大水池,Java程序是希望用水做点事情的器具,像洗车喷头,高压水枪这些,要获取水就要与水之间有管道,这个管道在计算机的世界里是各种传输介质,当然也包括传输协议。

现在回到Java,Java针对需要建立交互的数据源建立传输流,将数据流读取到JVM(内存)中,同时还可以对数据源进行一些在自己权限内的操作。

字节流

现在建立一个文件输入流

package com.my;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class IOTest_1 {
    public static void main(String[] args) {
        try{
            // 打开文件,绝对路径方式
            //File f = new File("D:\\CodeProjects\\JavaProjects\\LearningExamples\\src\\com\\my\\files/Test.txt");
            //相对路径方式,以根目录为基点
            File f = new File("src\\com\\my\\files/Test.txt");
            // 创建基于文件的输入流
            FileInputStream fis = new FileInputStream(f);
            //创建字节数组,数组长度为文件中数据的长度
            byte[] content = new byte[(int)f.length()];
            //以字节流的形式读取文件所有内容
            fis.read(content);
            //使用增强型for打印文件内容
            for(byte b: content){
                //文件中的数据会以数字形式打印
                System.out.println(b);
            }

            //每次使用完流,都应进行关闭
            fis.close();

        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

由于是字节流操作,最终打印出来的都是相应的字节码即ASCII码。

以字节流的形式向文件写入数据,即文件输出流

package com.my;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class IOTest_2 {
    public static void main(String[] args) {
        try{
            //相对路径方式,以根目录为基点
            File f = new File("src\\com\\my\\files/Test.txt");
            //ASCII表对应的数字,65位A,64为@
            byte data[] = { 65, 64};
            // 创建基于文件的输出流
            FileOutputStream fos = new FileOutputStream(f);
            //将数据写入到输出流
            fos.write(data);
            //关闭输出流
            fos.close();

        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

FileInputStream和FileOutputStream都是以字节流的形式处理文件数据,它们分别是InputStream和OutputStream的子类,InputStream和OutputStream都是抽象类,只提供方法声明,不提供方法的具体实现,还有一些字节流操作继承自它们,如ObjectInputStream和ObjectOutputStream等。

字符流

Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据
Reader和Writer和上面的InputStream和OutputStream,它们有一些子类负责相应的字符流操作。

以字符流方式读取文件内容

package com.my;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class IOTest_3 {
    public static void main(String[] args) {
        //相对路径方式,以根目录为基点
        File f = new File("src\\com\\my\\files/Test.txt");
        //将流定义在try()中,try、catch或finally结束时,会自动关闭
        try(FileReader fr = new FileReader(f)){
            char[] content = new char[(int)f.length()];
            //以字符流的形式读取文件所有内容
            fr.read(content);
            for(char c: content){
                System.out.println(c);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

把流定义在try()里,这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术

所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。

以字符流方式向文件中写入数据

package com.my;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class IOTest_4 {
    public static void main(String[] args) {
        //相对路径方式,以根目录为基点
        File f = new File("src\\com\\my\\files/Test.txt");
        //创建基于文件的Writer
        try(FileWriter fw = new FileWriter(f)){

            String data = "这是一个测试abcd";
            //以字符流形式写入文件
            char[] out = data.toCharArray();
            fw.write(out);

        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

字符流操作的基本单位是char,字节流操作的基本单位是byte,很多时候需要进行这种类型的数据转换。

数据流

字符流和字节流的很多功能相似,只是处理数据的方式不同,不过数据流DataOutputStream和DataInputStream是字节流独有的,它们基于多字节的处理方法,从而可以读取基本类型的数据,例如可以选择读取整型数据、字符串数据等。

注:要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。

package com.my;

import java.io.*;

public class IOTest_5 {
    public static void main(String[] args) {
        //相对路径方式
        String path = "src\\com\\my\\files/Test.txt";
        dataWrite(path);
        dataRead(path);
    }

    public static void dataRead(String path){
        File f = new File(path);
        try(
                //需要基于文件输入流字节流形式
                FileInputStream fis = new FileInputStream(f);
                DataInputStream dis = new DataInputStream(fis);
        ){
            //读取指定类型数据
            String str= dis.readUTF();
            int i = dis.readInt();
            boolean b = dis.readBoolean();

            System.out.format("字符串:%s,整型数据:%d,布尔数据:%b",str, i, b);

        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void dataWrite(String path){
        File f = new File(path);
        try(
                FileOutputStream fos = new FileOutputStream(f);
                DataOutputStream dos = new DataOutputStream(fos);
        ){
            //写入指定类型数据
            dos.writeUTF("奥德赛 and 123");
            dos.writeBoolean(true);
            dos.writeInt(23);

        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

缓存流

缓存处理流的功能在字节流和字符流中都有,其目的便是为了减少IO操作。

当我们读写一个文件诗,如果每次都访问源文件,效率会很低。

就好比你用水喷头给车冲洗,水源来自距离你五公里的大河,你每次用喷头都要等五公里外的水过来,一关闭喷头水又回到了那条大河。现在的缓存区就好比在你10米外加一个蓄水池,当你需要用水时,蓄水池先把远处水源中的水拿过来蓄满,当你的喷头将蓄水池的水用光后,蓄水池再去连接水源获取水。

当然Java的IO缓存还有更多操作,蓄水池只是一个简单比喻。

使用缓存流读取数据:

现在Test.txt的内容为:
hello world
you are a good man
thank you

package com.my;

import java.io.*;

public class IOTest_6 {
    public static void main(String[] args) {
        //相对路径方式
        File f = new File("src\\com\\my\\files/Test.txt");
        try (
                // 缓存流必须建立在一个存在的流的基础上
                FileReader fr = new FileReader(f);
                BufferedReader br = new BufferedReader(fr);
        )
        {
            while (true) {
                // 一次读一行
                String line = br.readLine();
                if (null == line)
                    break;
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用缓存流写入数据:

package com.my;

import java.io.*;

public class IOTest_7 {
    public static void main(String[] args) {
        //相对路径方式
        File f = new File("src\\com\\my\\files/Test.txt");
        try (
                FileWriter fw = new FileWriter(f);
                PrintWriter pw = new PrintWriter(fw)
        )
        {            
            pw.println("as well as");
            pw.println(123456);
            pw.println(true);
            //立即将数据写入到硬盘,而不是等到缓存满了才写出去
            pw.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里使用的是PrintWriter,这种写出可以支持多种类型,当然使用BufferedWriter也是可以的,都是Writer的子类,只是写入的数据类型会受到些限制,选择时需要结合具体情境。

对象流

这种流需要结合面向对象,先创建一个对象实例,将该对象序列化到相应的文件,然后在读取改文件进行反序列化重新转换为一个对象,前提是实现该对象的类需要实现Serializable接口。
一个Dog类:

package com.my;

import java.io.Serializable;

public class Dog implements Serializable {
    public String name;

    public int age;

    public Dog(String name, int age){
        this.name = name;
        this.age = age;
    }
    public void run(){
        System.out.println(name + " hp:" + age + "正在奔跑");
    }
}

对象流读写操作:

package com.my;

import java.io.*;

public class IOTest_8 {
    public static void main(String[] args){

        Dog dog = new Dog("小黑",34);

        File f = new File("src\\com\\my\\files/dog.txt");

        try(
                //创建对象输出流
                FileOutputStream fos = new FileOutputStream(f);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                //创建对象输入流
                FileInputStream fis = new FileInputStream(f);
                ObjectInputStream ois = new ObjectInputStream(fis);
        )
        {
            //将对象写入文件
            oos.writeObject(dog);
            //从文件中读取对象
            Dog dog2 = (Dog) ois.readObject();
            //查看获取到的对象信息
            System.out.println(dog2.name);
            System.out.println(dog2.age);
            dog2.run();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }
}

对象流在项目中应用很广,现在可以先了解下。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值