likes
comments
collection
share

傻傻分不清-IO流及转换

作者站长头像
站长
· 阅读数 22

Hi,大家好,我是抢老婆酸奶的小肥仔。

我们在操作文件时,需要将其转化成各种流来进行操作,然而很多时候我们并不知道各种流的作用,也不清楚流与流之间的相互转换。下面来具体说说各种流及流之间的相互转换。

希望对大家有所帮助。

1、I/O流

I/O流:即InputStream/OutputStream的缩写,即计算机调度数据写入写出的过程。

1.1 分类

I/O可以根据不同维度进行分类,主要根据:1、流向 2、操作颗粒度 3、角色来进行划分。

1.1.1 按照流向分类

  • 输出流:只能向其写入数据,主要使用:OutputStream和Writer为基类。
  • 输入流:只能从中读取数据,主要使用:InputStream和Reader为基类。

1.1.2 按照操作颗粒度分类

  • 字节流:以字节为单元,即byte[],8位字节,主要使用:InputStream、OutputStream为基类。
  • 字符流:以字符为单元,即char[],16位字符,主要使用:Writer、Reader为基类。

1.1.3 按照角色分类

  • 节点流:即对端点进行读写数据,例如:磁盘,网络等
  • 处理流:即对已存在的流的连接和封装,通过封装流的功能来调用实现数据读写。例如:缓存流。

1.2 原理

java提供了一个记录指针来记录流的读取情况。

当创建一个流对象时,记录指针就会标记流的开始位置,每当程序从InputStream或Reader里面取出一个或多个字节或字符时,记录指针也会自动向后移动。我们在写入文件时就会使用,如下代码。

傻傻分不清-IO流及转换

int temp;
byte[] bt = new byte[1024*10];
while((temp = bais.read(bt))!= -1) {
    fos.write(bt,0,temp);
}

2、常用流及使用

java为我们提供了很多流的子类,我们常用的也就那么几个,例如FileInputStream等,下面我们来汇总看下各流及其使用。

分类字节输入流字节输出流字符输入流字符输出流
基类InputStreamOutputStreamReaderWriter
文件FileInputStreamFileOutputStreamFileReaderFileWriter
数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
字符串StringReaderStringWriter

2.1 文件流操作

从上面表格中可以看到,文件操作输入流使用:FileInputStream/FileReader,文件输出流使用:FileOutputStream/FileWriter

我们看看实现代码:

创建一个test.txt文件,并随意写入内容。例如:在D:\file下创建test.txt,输入:今晚打老虎。

2.1.1 FileInputStream读取文件内容

public static void main(String[] args) {
        String filePath = "D:\file\test.txt";
        FileInputStream fis = null;
        try {
            //使用FileInputStream读取文件信息
             fis = new FileInputStream(filePath);
             //一次性将文件内容读出
             byte[] bytes = new byte[fis.available()];
             int item = 0;
             while ((item = fis.read(bytes)) != -1){
                 String str = new String(bytes, 0, item);
                 System.out.println("读取文件内容:"+str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关流
            try {
                if (Objects.nonNull(fis)) {
                    fis.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

执行结果:

傻傻分不清-IO流及转换

:在创建byte数组时,如果文件保存的是中文,则需要指定available(),即返回此输入流在不受阻塞情况下能读取的字节数(该方法在本地时不会遇到问题,如果用于网络操作,则会出现问题,这是因为网络存在间断性,文件内容分几次传输,从而导致 available()数值不固定), 否则读出的文件内容有问题。例如:将byte大小指定5,则一次读取5个字节,则结果如图:

傻傻分不清-IO流及转换

方法:

方法描述
read()从文件中读取一个字节
read(byte[] array)从文件中读取字节并存储到array中
read(byte[] array,int start,int length)从文件中读取从start开始,长度为length的字节保存到array中
available()一次性读取文件可用字节数
skip(long n)跳过指定的字节数
close()关闭文件输入流,如果不关闭流,这个流就会一直占用,会导致文件句柄被占用,可能导致资源泄露,导致CPU和RAM占用居高,甚至打不开新的文件进行读写。
finalize()确保close()方法被调用

2.1.2 FileReader读取文件内容

public static void main(String[] args) {

        String filePath = "D:\file\test.txt";
        FileReader fr = null;
        try {
            //使用FileReader读取文件数据
            File file = new File(filePath);
            fr = new FileReader(file);
            char[] chars = new char[1024];
            int frLen = 0;
            while ((frLen = fr.read(chars)) != -1){
                String str = new String(chars,0,frLen);
                System.out.println("FileReader读取文件内容:"+str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(fr)) {
                    fr.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

执行结果

傻傻分不清-IO流及转换

方法:

方法描述
read()从文件中读取一个字符
read(char[] array)从文件中读取字符并存储到array中
read(char[] array,int start,int length)从文件中读取从start开始,长度为length的字符保存到array中
mark()标记流中已读数据的位置,即记录指针的位置
skip(long n)跳过指定的字节数
close()关闭字符流

2.1.3 FileOutputStream写入内容

public static void main(String[] args) {

        String filePath = "D:\file\test.txt";
        FileOutputStream fout = null;
        try {
            //使用FileOutputStream输入内容到文件
            String content = "只是输入的内容";
            fout = new FileOutputStream(filePath,Boolean.FALSE);
            fout.write(content.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(fout)) {
                    fout.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

执行结果:

打开文件,可以看到内容被修改成:只是输入的内容。

傻傻分不清-IO流及转换

在创建FileOutputStream流时,我们可以通过设置该构造方法中的append参数值来指定是追加文件内容还是重写文件。true:表示追加文件内容,false:表示重写文件内容。

2.1.4 FileWriter写入内容

public static void main(String[] args) {

        String filePath = "D:\file\test.txt";
        FileWriter fw = null;
        try {
            //使用FileWriter写入文件内容
            String appendContent = "FileWriter写入的数据";
            fw = new FileWriter(filePath,Boolean.FALSE);
            fw.append(appendContent);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(fw)) {
                    fw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

执行结果:

傻傻分不清-IO流及转换

文件的内容被覆盖,在创建FileWriter时跟FileOutputStream一样,可以指定对文件内容的写入方式。

2.2 数组流操作

数组流是字节数组流,主要是解决频繁读写文件,效率较低的问题,它会将内容以字节的形式保存到内存中。它将所有数据全部缓存到自身,然后一次性将数据输出。

2.2.1 ByteArrayInputStream读取文件内容

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
        ByteArrayInputStream bais = null;
        try {
            //使用FileInputStream读取文件信息
            //一次性将文件内容读出
            byte[] bytes = new byte[1024*10];
            int item = 0;
            bais = new ByteArrayInputStream(FileUtils.readFileToByteArray(new File(filePath)));
            while ((item = bais.read(bytes)) != -1){
                String str = new String(bytes, 0, item);
                System.out.println("读取文件内容:"+str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(bais)) {
                    bais.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行结果:

傻傻分不清-IO流及转换

ByteArrayInputStream构建的时候提供了两种构造方法:ByteArrayInputStream(byte buf[]) ByteArrayInputStream(byte buf[], int offset, int length) 。都是将byte转换成ByteArrayInputStream。

ByteArrayInputStream提供的方法参见2.1.1。

2.2.1 CharArrayReader读取文件内容

在创建CharArrayReader时,是将char[]进行转化的,因此我们在读取文件内容时,则需要将文件内容转化成char[]。方法如下:

private static char[] fileToChar(String filePath){
        FileReader fr = null;
        try {
            fr = new FileReader(filePath);
            char[] chars = new char[1024];
            int frLen = 0;
            StringBuilder sb = new StringBuilder();
            while ((frLen = fr.read(chars)) != -1){
                sb.append(new String(chars,0,frLen));
            }
            return sb.toString().toCharArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(fr)) {
                    fr.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

CharArrayReader读取文件内容,代码:

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
        CharArrayReader car = null;
        try {
            //CharArrayReader读取文件内容
            char[] chars = fileToChar(filePath);
            assert chars != null;
            car = new CharArrayReader(chars);
            int charNum = 0;
            while ((charNum = car.read(chars)) != -1){
                String str = new String(chars, 0, charNum);
                System.out.println("CharArrayReader:读取文件内容:"+str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(bais)) {
                    bais.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行结果:

傻傻分不清-IO流及转换

2.2.3 ByteArrayOutputStream写入文件内容

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
        ByteArrayOutputStream baos = null;
        FileOutputStream fos = null;
        try {
            //ByteArrayOutputStream写入文件内容
            baos = new ByteArrayOutputStream();
            baos.write("ByteArrayOutputStream写入的文件内容".getBytes(StandardCharsets.UTF_8));
            fos = new FileOutputStream(filePath);
            baos.writeTo(fos);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(baos)) {
                    baos.close();
                }
                if (Objects.nonNull(fos)) {
                    fos.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行结果:

傻傻分不清-IO流及转换

从上面代码中,首先将内容转存到ByteArrayOutputStream的缓冲区,然后写入FileOutputStream实现写入文件内容。

writeTo(OutputStream outSt) :将字节数组流的全部内容写入指定的输出流中。

2.2.3 CharArrayWriter写入文件内容

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
        CharArrayWriter caw = null;
        FileWriter fw = null;
        try {
            //CharArrayWriter写入文件内容
            caw = new CharArrayWriter();
            caw.write("这是测试CharArrayWriter");
            fw = new FileWriter(filePath);
            caw.writeTo(fw);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (Objects.nonNull(caw)) {
                    caw.close();
                }if (Objects.nonNull(fw)) {
                    fw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行结果:

傻傻分不清-IO流及转换

2.3 缓冲流操作

缓冲流它的作用与数组流设计初衷一样,也是为了提高数据输出效率而设计的。它是缓存一部分数据后,一次一次的输出。

2.3.1 BufferedInputStream读取文件内容

BufferedInputStream是继承了FileInputStream,也提供了两个构造方法创建BufferedInputStream,BufferedInputStream(InputStream in)\ BufferedInputStream(InputStream in, int size)

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
        BufferedInputStream bis = null;
        try{
            bis = new BufferedInputStream(new FileInputStream(filePath));
            int itm = 0;
            byte[] bytes = new byte[bis.available()];
            while ((itm = bis.read(bytes)) != -1){
                System.out.println("读取文件内容:" + new String(bytes,0,itm));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (Objects.nonNull(bis)) {
                    bis.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行结果:

傻傻分不清-IO流及转换

我们将文件转换成FileInputStream,然后在转换成BufferedInputStream实现文件内容读取。

2.3.2 BufferedReader读取文件内容

BufferedReader读取文件内容与FileReader,只不过需要将Reader转换成BufferedReader,然后遍历读取内容。

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
         BufferedReader br = null;
        try{
            br = new BufferedReader(new FileReader(filePath));
            int itm2 = 0;
            char[] chars = new char[1024];
            while ((itm2 = br.read(chars)) != -1){
                System.out.println("BufferedReader读取文件内容:" + new String(chars,0,itm2));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (Objects.nonNull(br)) {
                    br.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

2.3.3 BufferedOutputStream写入文件内容

BufferedOutputStream集成了FilterOutputStream,也提供了两个构造方法创建BufferedInputStream,BufferedOutputStream(OutputStream out)\ BufferedOutputStream(OutputStream out, int size)

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
         BufferedOutputStream bdos = null;
        try{
            //BufferedOutputStream写入文件内容
            bdos = new BufferedOutputStream(new FileOutputStream(filePath));
            bdos.write("BufferedOutputStream写入文件内容".getBytes(StandardCharsets.UTF_8));
            bdos.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (Objects.nonNull(bdos)) {
                    bdos.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

执行结果:

傻傻分不清-IO流及转换

2.3.3 BufferedWriter写入文件内容

public static void main(String[] args) {
        String filePath ="D:\file\test.txt";
        BufferedWriter bw = null;
        try{
            //BufferedWriter写入文件内容
            bw = new BufferedWriter(new FileWriter(filePath));
            bw.write("BufferedWriter写入文件内容".toCharArray());
            bw.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (Objects.nonNull(bw)) {
                    bw.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

上面就是常用到的流对文件进行的操作,其实各流对文件的操作方法基本一致,只是效率不同而已,只要知道一种,其他依葫芦画瓢就好。

3、IO转换

我们在日常应用中,常常会使用到各种流的转换,例如:File转InputStream等等,下面我们来看看各种流之间的转换。

3.1 File转InputStream/OutputStream

//file转InputStream
InputStream is = new FileInputStream(file);
//file转OutputStream
OutputStream os = new FileOutputStream(file);

在appache提供了一个FileUtils工具类,也可以对文件进行转换。

//file转InputStream
FileInputStream fis = FileUtils.openInputStream(file);
//file转OutputStream
FileOutputStream fos = FileUtils.openOutputStream(file);

3.2 InputStream/OutputStream转byte[]

//InputStream转byte[]
InputStream is = new FileInputStream(file);
byte[] bytes = new byte[is.available()];
is.read(bytes);
is.close();

//OutputStream转byte[]
OutputStream os = new FileOutputStream(file);
byte[] bytes = new byte[1024 * 10];
os.write(bytes);
os.close();

在appache提供了一个IOUtils工具类,也可以将InputStream转换成byte[]。

byte[] bytes = IOUtils.toByteArray(is);

3.3 String转byte[]/char[]

String content = "231212121212";
byte[] bytes1 = content.getBytes(StandardCharsets.UTF_8);
char[] chars1 = content.toCharArray();

3.4 File转char[]

FileReader reader = new FileReader(file);
char[] chars = new char[1024];
reader.read(chars);

3.5 Outputstream 转 Inputstream

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());

3.6 byte[]转InputStream/OutputStream

String content = "测试一波";
byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
//byte[]转InputStream
InputStream input = new ByteArrayInputStream(bytes);

//byte[]转OutputStream
OutputStream os = new ByteArrayOutputStream();
os.write(bytes);
os.flush();

上述就是我对IO的总结,可能不是特别深入,希望对大家有帮助,在开发过程中能提高效率。谢谢!也期待大家在评论区发表自己的理解,相互学习。

转载自:https://juejin.cn/post/7237115019275927613
评论
请登录