Java中的IO流

本文详细介绍了Java中的流概念,区分了字节流和字符流,列举了java.io包下的主要流类,如FileInputStream、FileOutputStream等,并探讨了带有缓冲区的流、数据专属流、标准流以及对象专属流的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

简要介绍Java中的字节流和字符流对应的类的使用。


目录

前言

一、Java流的介绍

1、流的简介:

 2、流的分类

3、Java中的流

4、java.io包下的六大流 

二、文件专属流

1、FileInputStream

 2、FileOutputStream

3、FileReader和FileWriter 

三、带有缓冲区的流、数据专属流和标准流

1、带有缓冲区的流

2、数据流 

 3、标准流

四、对象专属流

五、File类


一、Java流的介绍

1、流的简介:

流(Stream)是计算机数据传输中一个相对比较抽象的概念,可以借助现实生活的各种流动的现象来理解。简单来说,流所具有的特点包括,总体以串行的方式一点点的移动,通常具有方向性和连续性,向某个特定的方向汇集。现实世界中的流,比如水流的特点正好与计算机数据传输的方式相对应,传输的数据可以是文字、视频、音频等等,都是一点点的从一端传输到另一端。因此就用流来代替计算机中数据传输的现象。

 2、流的分类

可以有两种分类方式:

        (1)、按流的方向:

                分为输入(读)和输出(写)流

        (2)、按读取数据的不同方式:

                分为字节流和字符流。字节流一次取一个字节,什么文件都可以读取。字符流一次读取一个字符,只能读取普通txt文本(word文档也不行)。

3、Java中的流

        Java中的流以对象的方式存在,都放在java.io包下 

Java 流的四大家族:

        java.io.InputStream:字节输入流

        java.io.OutputStream:字节输出流

        java.io.Reader:字符输入流

        java.io.Writer:字符输出流

以上这四大家族全是抽象类,都有对应的具体类。

它们都实现了java.io.Closable接口,因此都有close( )方法释放资源。

所有的输出流都实现了Flushable接口,都有flush()方法来刷新,以便能强制输出,清空输出流。 

4、java.io包下的六大流 

        都是具体类,都能直接创建对象。要看它们继承的是哪个家族,就看结尾是哪个抽象类。如 FileInputStream就是继承的InputStream。InputStreamReader就是继承的Reader.

        文件专属:

        FileInputStream、FileOutputStream、FileReader、FileWriter

        带有缓冲区的流:

        BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

        数据专属流:

        DataInputStream、DataOutputStream

        标准流:

        PrintSream、PrintWriter

        对象专属流:

        ObjectInputStream、ObjectOutputStream

        转换流(将字节流转换为字符流):

        InputStreamReader、OutputStreamWriter


二、文件专属流

        流创建和关闭的时候都有异常。

1、FileInputStream

文件字节输入流(FileInputStream)对象的创建要调用有参构造方法传入一个相对路径(在IDEA中,它的相对路径是从项目下开始)或者绝对路径。

import java.io.*;
import java.util.Arrays;

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

        //创建文件字节输入流对象
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("streamtest.txt");
            //有read()方法读取数据,读取到的是字符的编码。当不传入参数时,一次读取一个字节。
            //可传入一个byte[]数组来接收读取的字节。
            //该方法会报IO异常
            int readInfo = fis.read();
            System.out.println(readInfo);//104

            //传入byte[]数组时,read()的返回值是读取的元素个数
            //注意,文件指针此时已经移动了一个字节
            byte b[] = new byte[15];
            int readCount = fis.read(b);
            System.out.println(readCount);//11
            System.out.println(Arrays.toString(b));//[101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 0, 0, 0, 0]

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            //一定要记得关闭流
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

}

 有read( )方法去读取数据,读取到的是字符的编码。当不传入参数时,一次读取一个字节。可传入一个byte[]数组来接收读取的字节。read( )方法会报IO异常,传入byte[]数组时,read()的返回值是读取的元素个数。注意,文件指针读取时会移动位置,也就是说下一次读取时,将会从文件指针指向的位置开始读。

 FileInputStream还有int available( )和long skip( long n)方法。

        available( )方法返回文件中剩余的没有读到的字节数量。

        skip( )方法可用来跳过几个字节不读。

 2、FileOutputStream

该类对象使用write( )方法来输出。注意,输出流每输出一次都要使用flush( )方法刷新一下,write( )和flush( )方法都有异常需要处理。

import java.io.*;
import java.util.Arrays;
public class Test02{
    public static void main(String[] args) {
        FileOutputStream fos = null;
        //创建文件字节输出流
        try {
            fos = new FileOutputStream("streamtest.txt");

            //write()方法中可传入一个整形数字,一个byte[]数组,还可以指定从数组哪个部分开始,和输出的元素个数
            fos.write(100);//UTF-8编码下是d

            //使用write()方法写入时,没有该文件会创建一个新的文件再写入。
            // 如果文件中原本有内容会清空后再写入。如果想要追加写入就要使用FileOutputStream的另一个构造方法
            //FileOutputStream(String path,boolean append),append为true代表追加写入
            //在连续使用write()方法时由于文件指针在移动,因此是在上一次写入的位置之后追加写入
            byte[] b = new byte[]{85,86,87,88,89,90};//UTF-8编码下是dUVWXYZ
            fos.write(b);//
            fos.write(b,2,2);//表示从下表为2的元素开始写入,一共写进去两个元素
            
            //记得刷新
            fos.flush();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }


    }
}

write()方法中可传入一个整形数字,一个byte[]数组,还可以指定从数组哪个部分开始,和输出的元素个数.

使用write()方法写入时,没有该文件会创建一个新的文件再写入。如果文件中原本有内容会清空后再写入。如果想要追加写入就要使用FileOutputStream的另一个构造方法:FileOutputStream(String path,boolean append),append为true代表追加写入
在连续使用write()方法时由于文件指针在移动,因此是在上一次写入的位置之后追加写入。

3、FileReader和FileWriter 

文件字符输入(输出)与文件字节输入(输出)流的主要区别在于,它们除了可以传一个byte[ ]数组用来读(写)外,还可以传入一个char[ ] 数组来读(写)。 

import java.io.*;
public class Test03 {
    public static void main(String[] args) {
       FileReader fr = null;
       FileWriter fw = null;
        try {
            fw = new FileWriter("streamtest.txt");

            //传入一个char数组写
            char[] c1 = new char[]{'n','i',',','h','a','o'};
            fw.write(c1);//ni,hao

            //还可以直接传字符串写,也可以指定读(写)的开始下标和长度
            fw.write(c1,1,2);//ni,haoi,
            
            fw.write("hello");//ni,haoi,hello

            fw.flush();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

三、带有缓冲区的流、数据专属流和标准流

1、带有缓冲区的流

       就是BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter这四种。顾名思义,就是该流会自己创建一个缓冲区来存放读取的元素,不用在传入一个数组了。

不过该构造方法需要传入对应的四大家族的对象,如BufferInputStream的构造方法需要传入一个InputStream类型的参数。一般把这种参数就是流的特殊流,叫做包装流或处理流,把作为参数传递的叫做节点流。

关闭时,只需要关闭包装流,关闭了包装流会自动关闭节点流。

import java.io.*;
public class  Test04{
    public static void main(String[] args) {
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //BufferedWriter需要传入一个Writer类型的参数
            bw = new BufferedWriter(new FileWriter("streamtest.txt"));

            bw.write("利用write( )方法写入\n");
            bw.write("换一行写入\n");

            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        try {
            br = new BufferedReader(new FileReader("streamtest.txt"));

            //readLine()方法读一行
            String info = br.readLine();
            System.out.println(info);//利用write( )方法写入
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally{
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

}

2、数据流 

        可连数据类型一起写入文件,但是用该流写进去数据的文件为特殊文件,记事本没法读取。只能用DataInputStream去读出来。数据流也是包装流,需要传入一个对应的InputStream类型的参数和OutputStream类型的参数。

import java.io.*;
public class Test05 {
    public static void main(String[] args) {
        DataInputStream dis = null;
        DataOutputStream dos = null;

        try {
            dos = new DataOutputStream(new FileOutputStream("datatest.txt"));

            //利用write+类型()的方式写入数据
            dos.writeInt(1);
            dos.writeBoolean(true);

            dos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally{
            if(dos != null){
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        try {
            dis = new DataInputStream(new FileInputStream("datatest.txt"));

            //利用read+类型()的方式读=数据
           int i = dis.readInt();
           System.out.println(i);//1
           boolean j = dis.readBoolean();
            System.out.println(j);//true

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(dis != null){
                try {
                    dis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

 3、标准流

        标准输出流不需要手动刷新和关闭。 

mport java.io.*;
public class Test06 {
    public static void main(String[] args) {
        PrintStream ps = System.out;//向控制台输出
        ps.println("haha");//haha

        //改变输出方向
        try {
            ps = new PrintStream(new FileOutputStream("streamtest.txt"));
            System.setOut(ps);
            System.out.println("向该文件输出");//不再在控制台输出
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

四、对象专属流

        对象专属流是用来将对象向文件中写和读取的。对象的存和取有个特殊的名称,叫序列化和反序列化。从内存向硬盘输出对象叫做序列化,从硬盘向内存读对象就是反序列化。

ObjectOutputStream和ObjectInputStream也是需要传入节点流,使用对应的writeObject( )和readObject( )去写和读对象,其中readObject( )方法返回一个Object类型的对象。但是要求改类要继承Serializable接口,该接口只是一个标志,没有任何方法。用于JVM看到该标志后生成一个序列化版本号,主要是针对属性。一旦该类有修改,序列化版本号就会不同。

 

import java.io.*;
public class Test07 {
    public static void main(String[] args) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;

        try {
            oos = new ObjectOutputStream(new FileOutputStream("objectstream.txt"));

            oos.writeObject("object1");//存多个对象用集合
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在属性类型前添加transient关键字可以让该属性没有序列化版本号,不过不参与序列化也就取不出来 。

可手动序列化版本号:

        格式:

                private static final long serialVersionUID = 编写的数字;

 

五、File类

        File是文件和文件夹路径的抽象表示,继承自Object,它不是用来完成文件的读和写的,主要是与文件相关的一些操作。可以当做路径传入流的构造方法中。

它有几个常用方法:

public boolean exists( ):判断该文件是否存在

public boolean createNewFile( ):不存在文件时,创建该文件

public boolean mkdir( ):创建指定目录

public boolean mkdirs( ):创建指定路径上的一系列目录

public String getParent( ):获取上一级目录名,如果没有指定上一级目录名,返回null

public String getAbsoluteFile( ):获取绝对路径

publlic String getName( ):获取文件名

public long lastModified( ):该文件最后一次修改时间(获取的是从标准基准时间到当前系统时间的总毫秒数)

public File[ ] listFiles( ):获取当前目录下所有的子文件夹

import java.io.File;
import java.io.IOException;
public class Test08 {
    public static void main(String[] args) {
        File f1 = new File("streamtest.txt");
        System.out.println(f1.exists());//true

        //在文件不存在时创建文件,该方法会报异常
        try {
            System.out.println(f1.createNewFile());//false
        } catch (IOException e) {
            e.printStackTrace();
        }

        File f2 = new File("BlogTest03");
        //如果不存在创建该文件夹
        if(!f2.exists()){
            f2.mkdir();
        }

        //获取上一级路径
        System.out.println(f2.getParent());//
        //获取该文件绝对路径
        System.out.println(f2.getAbsoluteFile());//D:\Javatest\BlogTest03

        //获取当前目录下所有的子文件
        File[] fs2 = f2.listFiles();
        System.out.println(fs2.length);//0,当前目录为空
    }
}

如有错误,希望能批评指正,不胜感激。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值