IO流(一)

IO流

一、IO流的分类

在这里插入图片描述

字节流

字节流可以操作任意类型的文件

字符流

字符流只能操作纯文本文件

总结

在这里插入图片描述

二、字节 输入输出流

输出流,使用FileOutputStream举例

在这里插入图片描述
在这里插入图片描述
FileOutputStream是一个字节输出流(一般情况下,output代表输出,stream代表字节流。FileWriter就是字符输出流。

写出

下面的代码就是简单的写出操作

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:
 *  演示: 字节输出流 FileOutputStream
 *  实现需求:写出一段文字到本地
 *  1.创建输出流对象
 *      细节1:参数是字符串表示的路径或者是File对象都是可以的
 *      细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。.
 *      细节3:如果文件已经存在,则会清空文件
 *  2.写数据
 *      细节: write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
 *  3.释放资源
 *      每次使用完流,都需要关闭流对象,防止资源占用
 */
public class ByteStreamDemo1 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("a.txt");
        fileOutputStream.write(97);
        fileOutputStream.close();
    }
}
换行写出,续写

有时我们不止要写出一行,可能有换行的需求,还有不覆盖原文件内容,在原文件内容上面追加。

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:
 * 文件输出流实现换行写,续写
 * 换行写:
 * 只需要在两行数据之间添加一个换行符
 * windows: \r\n
 * linux: \n
 * mac: \r
 * java底层对windows操作系统的换行做了补全,只写\n或者\r都可以实现换行,但是建议还是要写全
 * 续写
 */
public class ByteSteamDemo3 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("a.txt",true);
        String str = "helloworld";
        byte[] bytes = str.getBytes();
        fileOutputStream.write(bytes);
        String wrap = "\r\n";
        byte[] bytes1 = wrap.getBytes();
        fileOutputStream.write(bytes1);
        String str2 = "666";
        byte[] bytes2 = str2.getBytes();
        fileOutputStream.write(bytes2);
        fileOutputStream.close();
    }
}

想要续写,在创建文件输出对象时只需要选择带有append形参的构造器就行下·
在这里插入图片描述

输入流,使用FileInputStream举例

读入

read()方法每次只能读取一个字节,当读到文件末尾时,read()方法会返回 -1

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:
 * 文件输入流FileInputStream
 *
 * 字节输入流的细节:
 * 1.创建字节输入流对象
 * 细节1:如果文件不存在,就直接报错。
 * 2.写数据
 * 细节1:一次读-一个字节,读出来的是数据在ASCII上对应的数字
 * 细节2:读到文件末尾了,read方法返回-1。
 * 3.释放资源
 * 细节:每次使用完流之后都要释放资源
 */
public class ByteStreamDemo {
    public static void main(String[] args) throws IOException {

        FileInputStream fileInputStream = new FileInputStream("a.txt");
        int read1 = fileInputStream.read();
        System.out.println((char) read1);//可以使用强转讲数字转为原本的内容
        int read2 = fileInputStream.read();
        System.out.println(read2);
        int read3 = fileInputStream.read();
        System.out.println(read3);
        int read4 = fileInputStream.read();
        System.out.println(read4);
        int read5 = fileInputStream.read();//读到文件末尾read()方法会返回-1
        System.out.println(read5);
        fileInputStream.close();
    }
}
循环读入

根据read()方法读到末尾会返回-1,使用while循环进行循环读取

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:循环读取
 */
public class ByteStreamDemo3 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        int b =0;
        while((b = fis.read()) != -1){
            System.out.println((char)b);
        }
        fis.close();
    }
}
使用循环读入完成拷贝文件
/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:、
 * 这种方式只适合拷贝小文件,因为read()方法一次只能读取一个文件
 */
public class ByteStreamDemo4 {
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("a.txt");
        FileOutputStream fos = new FileOutputStream("b.txt");
        int b = 0;
        while((b = fis.read()) != -1){//读一个字节
            fos.write(b);//写一个字节
        }
        //先开启的流后关闭
        fos.close();
        fis.close();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

这样进行文件拷贝会有一个问题,因为我们每次都读入的是一个字节,如果一个文件的大小有几百万字节,那么我们就需要循环几百万次,这样的效率是很低的。
在这里插入图片描述

使用循环读入完成拷贝文件,一次读入多个字节

下面的代码和上面的代码的区别就是:这段代码可以一次性读入1024个字节,使用的是 read(byte[] bytes) 方法,该方法也会在读到末尾时返回-1,在读到末尾之前每次返回读到的字节数

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:
 * 使用read(Byte[] byte)可以一次性读取多个字节
 */
public class ByteStreamDemo5 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        FileOutputStream fos = new FileOutputStream("b.txt");
        byte[] bytes = new byte[1024];
        int len;
        while((len = fis.read(bytes)) != -1){
            fos.write(bytes,0,len);
        }
        fos.close();
        fis.close();
    }
}

思考题:

在这里插入图片描述

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:观察read(byte[] bytes)是如何读取文件中的字节的
 */
public class ByteStreamDemo6 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        byte[] bytes = new byte[2];//一次性可以读入两个字节
        int len1 = fis.read(bytes);
        String str1 = new String(bytes);
        System.out.println(str1);//ab

        int len2 = fis.read(bytes);
        String str2 = new String(bytes);
        System.out.println(str2);//cd

        int len3 = fis.read(bytes);
        String str3 = new String(bytes);
        System.out.println(str3);//ed
        //这里只读取了一个字节e,但是bytes数组中还有上一次读取的数据cd,所以e将c覆盖了
        //输出bytes中的内容,为ed
    }
}

请想一想,这段代码的执行结果是什么?
在这里插入图片描述
答案:
在这里插入图片描述
可以看到当我们使用大小为2的字节数组去读取内容为abcde的文件时,第一次读取到的内容为ab,第二次为cd,第三次为ed。
这是因为第三次读取时,字节数组中还保存了第二次读取的数据cd,第三次读取程序发现,内容只剩下e了,它就拿着e去覆盖了字节数组中的第一个字节c,于是我们输出字节数组的内容时,就出现了ed。
为了防止这种情况,我们可以利用read(byte[] bytes)方法每次读取返回的读取到的字节数量len。例如:

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:观察read(byte[] bytes)是如何读取文件中的字节的
 */
public class ByteStreamDemo6 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        byte[] bytes = new byte[2];
        int len1 = fis.read(bytes);
        String str1 = new String(bytes,0,len1);
        System.out.println(str1);//ab

        int len2 = fis.read(bytes);
        String str2 = new String(bytes,0,len2);
        System.out.println(str2);//cd

        int len3 = fis.read(bytes);
        String str3 = new String(bytes,0,len3);
        System.out.println(str3);//ed
        //这里只读取了一个字节e,但是bytes数组中还有上一次读取的数据cd,所以e将c覆盖了
        //输出bytes中的内容,为ed
    }
}

在这里插入图片描述

三、try-resource

释放流的资源时,我们通常需要将close方法写在finally中。
jdk7和jdk9为我们提供了新的写法:
在这里插入图片描述
try-catch-finally写法

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:
 */
public class ByteStreamDemo7 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("a.txt");
            fos = new FileOutputStream("b.txt");
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        //如果在new流对象的时候出现了fileNotFound异常,则fis或者fos不会被初始化,那么fos.close fis.close就会报空指针异常
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

try-resource写法

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:jdk7 try-resource
 */
public class ByteStreamDemo8 {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("a.txt"); FileOutputStream fos = new FileOutputStream("b.txt")) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

需要注意的是,能使用try-resource结构的类必须实现AutoCloseable接口(如果你没看见这个接口被实现,有可能是他的父类实现了)

四、字符集与编码方式

Ascll字符集与编码方式

一个Ascll字符集中的字符占1byte(8个bit)。
在编码时,在字符集中查出要存储的字符的十进制编码,转成二进制,不足8bit的在最高位补0,再存入计算机。
在解码时,将二进制数字转为十进制,在字符集中查询对应的字符。
在这里插入图片描述

GBK字符集与编码方式

GBK字符集是完全兼容Ascll码的,GBK在存储英文字符时也是使用的1个byte,不足8bit的在高位补0。

在这里插入图片描述
GBK编码在存储汉字时会使用2个byte,不需要进行补0。
解码时只需要将高位为1开头的8bit和后面连着的8bit一共16bit转换为一个汉字就行。
在这里插入图片描述
GBK在进行解码时只需要将2byte二进制数转换为一个十进制数就好。
在这里插入图片描述

思考题

在这里插入图片描述
根据GBK字符集的规则,汉字高位二进制一定以1开头,汉字由两个byte存储,兼容的ascll码是以0开头,所以这段二进制数是一个汉字,一个英文字符。
在这里插入图片描述
可以用下面两个问题对比一下。
在这里插入图片描述

总结

在这里插入图片描述

五、UTF-8编码

UTF-8是指unicode字符集的一种编码风格,它是一种可变长度的编码方式
在这里插入图片描述
例如英文编码:
在这里插入图片描述
中文编码:
在这里插入图片描述

思考题

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述

六、为什么会产生乱码?

原因一:读取字节不完整
例如:11100100 10111101 10100000 这3个字节表示一个汉字 “你”。但是在读取的时候,只读取了前两个字节,11100100 10111101。这样的话在字符集中就找不到对应的汉字字符,就会出现乱码。
原因二:解码的方式和编码的方式不统一
正常的情况:utf-8编码,utf-8解码
在这里插入图片描述
乱码情况:utf-8编码,gbk解码
utf-8是保存的三个字节为一个汉字,而GBK在获取到第一个字节11100110后,发现最高位是1,所以会连着10110001一起将这两个字节解释为汉字。11100110 10110001在GBK中表示姹,而10001001没有对应的字符,所以用问号表示,所以乱码了。
在这里插入图片描述

七、java中的编码和解码方法

/**
 * @author Watching
 * * @date 2023/5/21
 * * Describe:
 * java中的编码与解码
 */
public class CharsetDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        /**
         * 编码
         */
        String str = "ai你哟";
        byte[] bytes = str.getBytes();
        System.out.println("ai你哟 utf-8编码:"+Arrays.toString(bytes));//[97, 105, -28, -67, -96, -27, -109, -97]
        //idea默认的是utf-8编码所以ai你哟被编码成了8个字节(英文一个字节,汉字三个字节)

        byte[] bytes1 = str.getBytes("GBK");//可以手动指定编码方式,但是需要抛出一个异常(UnsupportedEncodingException,不支持的编码方式)
        System.out.println("ai你哟 GBK编码:"+Arrays.toString(bytes1));//[97, 105, -60, -29, -45, -76]
        //GBK编码方式,英文占一个字节,汉字占两个字节,所以得到了6个字节
        /**
         * 解码
         */
        //idea默认的解码方式是utf-8
        String s = new String(bytes);
        System.out.println(s);//ai你哟
        //指定为GBK解码,使用GBK的解码方式解UTF-8编码的字符,会出现乱码
        String s1 = new String(bytes,"GBK");
        System.out.println(s1);//ai浣犲摕
    }
}

八、字符流

================疑问

在这里插入图片描述
在这里插入图片描述
这个20320是怎么得到的?
解答:
使用图中的代码将 你 转为二进制数 100111101100000
在这里插入图片描述
在这里插入图片描述
将这个二进制数转换,就得到了20320。
将这段二进制数代入utf-8的编码中
汉字3字节:1110xxxx 10xxxxxx 10xxxxxx
得到:11101001 10111011 10000000
自行了解utf-8编码吧

FileReader

无参的read()方法

/**
 * @author Watching
 * * @date 2023/5/21
 * * Describe:
 * 第一步:创建对象
 * public FileReader(File file)
 * 创建字符输入流关联本地文件
 * public FileReader(String pathname)创建 字符输入流关联本地文件
 * 第二步:读取数据
 * public int read()
 * 读取数据,读到末尾返回-1
 * public int read( char[] buffer)  读取多个数据,读到末尾返回-1
 * 第三步:释放资源
 * public void close() 释放资源/关流
 */
public class CharStreamDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("a.txt");
        int i;
        while ((i = fr.read()) != -1) {//read()方法会将读取的字节转换为十进制
            System.out.println((char) i);
        }
        fr.close();
    }
}

带参的read(char[] c)方法

/**
 * @author Watching
 * * @date 2023/5/21
 * * Describe:
 * 第一步:创建对象
 * public FileReader(File file)
 * 创建字符输入流关联本地文件
 * public FileReader(String pathname)创建 字符输入流关联本地文件
 * 第二步:读取数据
 * public int read()
 * 读取数据,读到末尾返回-1
 * public int read( char[] buffer)  读取多个数据,读到末尾返回-1
 * 第三步:释放资源
 * public void close() 释放资源/关流
 */
public class CharStreamDemo1 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("a.txt");
        char[] chars = new char[2];
        int len;
        while ((len = fr.read(chars)) != -1) {
            System.out.print(new String(chars,0,len));
        }
    }
}

FileWriter

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码演示,还有其它的成员方法不做展示

/**
 * @author Watching
 * * @date 2023/5/21
 * * Describe:
 * 第一步:创建对象
 * public FileReader(File file)
 * 创建字符输入流关联本地文件
 * public FileReader(String pathname)创建 字符输入流关联本地文件
 * 第二步:读取数据
 * public int read()
 * 读取数据,读到末尾返回-1
 * public int read( char[] buffer)  读取多个数据,读到末尾返回-1
 * 第三步:释放资源
 * public void close() 释放资源/关流
 */
public class CharStreamDemo1 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("a.txt");
        FileWriter fw = new FileWriter("b.txt");
        char[] chars = new char[2];
        int len;
        //read() 读取数据,解码,转为十进制
        //read(chars) 读取数据,解码,转为十进制,强转三步合并,把强转之后的字符放到数组中
        while ((len = fr.read(chars)) != -1) {
            System.out.print(new String(chars,0,len));
            fw.write(chars,0,len);
//            fw.flush();//每次循环都将缓冲数组中的数据写出
			fw.write(97+"");//如果写出的是一个int型的数字,它会被转成字符集中对应的字符,如果就是要原样输出数字,可以加一个空字符串。
        }
        fw.close();
        fr.close();
    }
}

字符流的底层原理

字符流的底层存在一个缓冲数组,大小为8192(字节流没有缓冲数组)
字符输入流详解
字符输出流详解

练习题:

在这里插入图片描述
关键点:
①目的地文件夹
②源文件存在目录需要递归

/**
 * @author Watching
 * * @date 2023/5/22
 * * Describe:
 */
public class test1 {
    public static void main(String[] args) throws IOException {
        copyDir(new File("D:\\test\\source"),new File("D:\\test\\dest"));
    }
    /**
     *
     * @param source 源文件/目录
     * @param dest 目的地
     * @throws IOException
     */
    private static void copyDir(File source, File dest) throws IOException {
        dest.mkdirs();//防止出现FileNotFoundException
        DirectoryStream<Path> paths = Files.newDirectoryStream(Paths.get(source.getPath()));
        for (Path path : paths) {
            File file = new File(String.valueOf(path));
            if(file.isFile()){//如果是文件,则直接拷贝
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream fos = new FileOutputStream(new File(dest,file.getName()));
                byte[] b = new byte[1024];
                int len;
                while((len = fis.read(b)) != -1){
                    fos.write(b,0,len);
                }
                fos.close();
                fis.close();
            }else {
                //递归子目录
                copyDir(file,new File(dest,file.getName()));
            }
        }
    }
}

在这里插入图片描述
提示:使用异或,100 ^ 10 = 110; 110 ^ 10 = 100;
(是换算成二进制做的)

九、缓冲流

在这里插入图片描述

字节缓冲流

在这里插入图片描述

练习:

在这里插入图片描述

/**
 * @author Watching
 * * @date 2023/5/22
 * * Describe:
 * 需求:
 *  利用字节缓冲流拷贝文件
 *
 */
public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
        int len;
        while ((len = bis.read())!= -1){
            bos.write(len);
        }
        bos.close();
        bis.close();
    }
}
/**
 * @author Watching
 * * @date 2023/5/22
 * * Describe:
 * 需求:
 *  利用字节缓冲流拷贝文件,使用字节数组一次性读取多个字节
 */
public class BufferedStreamDemo2 {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
        int len;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes))!= -1){
            bos.write(bytes,0,len);
        }
        bos.close();
        bis.close();
    }
}

字节缓冲流提高效率的原理:

在这里插入图片描述
字节缓冲流是对基本流做了包装。
以输入流为例:在硬盘读取数据的时候,还是基本流在读取,不过与只用基本流相比,加了缓冲流的基本流可以一次性读8192个字节,因为缓冲流的底层维护了以一个大小为8192的缓冲数组,所以提高了速度。当缓冲区填满之后,它就会与缓冲输出流的缓冲区进行交换,因为是在内存中,所以会快很多,然后缓冲输出流的缓冲区填满之后,再一次性写出,这样就减少了写出的io操作。(减少了操作系统cpu从用户态到核心态的切换)

=================疑问

我使用了一个大小为3个g的视频作为源文件,分别用普通流和缓冲流进行拷贝,下面是代码:
普通流:

/**
 * @author Watching
 * * @date 2023/5/19
 * * Describe:
 * 使用read(Byte[] byte)可以一次性读取多个字节
 */
public class ByteStreamDemo5 {
    public static void main(String[] args) throws IOException {
        long l = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("a.mp4");
        FileOutputStream fos = new FileOutputStream("b.mp4");
        byte[] bytes = new byte[8192];
        int len;
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }
        fos.close();
        fis.close();
        long l1 = System.currentTimeMillis();
        System.out.println(l1 - l);
    }
}

缓冲流:

/**
 * @author Watching
 * * @date 2023/5/22
 * * Describe:
 * 需求:
 * 利用字节缓冲流拷贝文件,使用字节数组一次性读取多个字节
 */
public class BufferedStreamDemo2 {
    public static void main(String[] args) throws IOException {
        long l = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.mp4"));
        int len;
        byte[] bytes = new byte[8192];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bos.close();
        bis.close();
        long l1 = System.currentTimeMillis();
        System.out.println(l1 - l);
    }
}

分别对这两端代码进行测试,结果为:
普通流:17222ms、16455ms、15842ms
缓冲流:17533ms、14822ms、17523ms
可以看到差别不大,所以我暂时认为,缓冲流提升速度的原因是因为底层维护了一个数组,但是普通流的 read(byte[] b) 方法和 write(byte[] b) 方法也可以达到同样的目的,所以缓冲流的存在可能是还包装了其它方法,提供了便利。

字符缓冲流

在这里插入图片描述
字符流本身底层就维护了一个8192大小的数组,所以字符缓冲流的提升并不大,但是这并不意味着我们就可以不用学习这个高级流了。
字符缓冲流还为我们包装了两个重要的方法:
在这里插入图片描述
这个newLine()方法底层会先判断操作系统的类别,输出时根据操作系统对换行符做处理,就不用我们修改代码适配每个操作系统的换行符了。

字符缓冲流读入
/**
 * @author Watching
 * * @date 2023/5/23
 * * Describe:
 * 字符缓冲输入流
 */
public class BufferedStreamDemo4 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        /*
        readLine()方法每次读取都会读取一整行的数据,直到遇见回车换行符,但是它并不会将回车换行符读入。
        所以需要我们手动换行。
         */
//        String line1 = br.readLine();
//        System.out.println(line1);
//        String line2 = br.readLine();
//        System.out.println(line2);
//        String line3 = br.readLine();
//        System.out.println(line3);
        
        //循环读入的方法
        String s;
        while((s = br.readLine()) != null){
            System.out.println(s);
        }
        br.close();
    }
}
字符缓冲流输出
/**
 * @author Watching
 * * @date 2023/5/23
 * * Describe:字符缓冲输出流
 */
public class BufferedStreamDemo5 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt", true));
        String line1 = br.readLine();
        bw.write(line1);
        bw.newLine();//字符缓冲输出流的newLine()方法会帮我们对文件内容换行,所以搭配readLine()使用就可以完成基本拷贝功能
        String line2 = br.readLine();
        bw.write(line2);
        bw.newLine();
        String line3 = br.readLine();
        bw.write(line3);
        bw.newLine();
        bw.close();
        br.close();
    }
}

总结

在这里插入图片描述

===============前面忘记的细节

如果使用了任意输出流读取了一个文件,那么这个文件是无法被输入流读取到数据的,除非输出流的append参数为true
以下面的代码举例:

/**
 * @author Watching
 * * @date 2023/5/23
 * * Describe:
 */
public class test {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = new FileInputStream("c.txt");
        FileOutputStream fileOutputStream = new FileOutputStream("c.txt");
        int read = fileInputStream.read();//这里的read是读不到文件内容的,因为文件内容在创建输出流的时候被清空了
        System.out.println(read);
        fileOutputStream.close();
        fileInputStream.close();
    }
}

在这里插入图片描述

输出结果为:
在这里插入图片描述
设置输出流的append参数为true

/**
 * @author Watching
 * * @date 2023/5/23
 * * Describe:
 */
public class test {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = new FileInputStream("c.txt");
        FileOutputStream fileOutputStream = new FileOutputStream("c.txt",true);
        int read = fileInputStream.read();//这里的read是读不到文件内容的,因为文件内容在创建输出流的时候被清空了
        System.out.println(read);
        fileOutputStream.close();
        fileInputStream.close();
    }
}

在这里插入图片描述
输出结果为:
在这里插入图片描述
将输出流的位置放在输入流读取之后

/**
 * @author Watching
 * * @date 2023/5/23
 * * Describe:
 */
public class test {
    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream = new FileInputStream("c.txt");
        int read = fileInputStream.read();//这里的read是读不到文件内容的,因为文件内容在创建输出流的时候被清空了
        FileOutputStream fileOutputStream = new FileOutputStream("c.txt");
        System.out.println(read);
        fileOutputStream.close();
        fileInputStream.close();
    }
}

在这里插入图片描述
输出结果为:
在这里插入图片描述
发现这样就能读取到内容,但是因为我们创建输出流,但是没有输出内容,而且没有将append参数设置为true,所以文件内容被清除了。

所以,输出流创建的位置很重要,创建在不合适的位置可能会导致输入流读取不到数据而出错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值