[Java学习日记]基本IO流

目录

一.FileInputStream,FileOutputStream:操作本地文件的字节输入输出流

二.使用输出流续写,输出字符串,换行

三.读取整个文件:一个一个字节读取

四.拷贝文件

五.案例:使用read一次读取一个字节数组的数据,每次读取尽量把数组装满

六.文件拷贝改进:快速拷贝大文件

七.finally:捕获异常完整形态

八.AutoCloseable:JDK7出现:特定情况下自动释放资源

九.使用使用String与byte数组进行编码解码

十.FileReader与FileWriter:操作本地文件的字符输入输出流

十一.案例:拷贝文件夹,包括其子文件夹

十二.案例:文件加密与解密

十三.案例:修改文件中的数据,再排序数据


一.FileInputStream,FileOutputStream:操作本地文件的字节输入输出流

1.IO流能够读写什么?
读写文件、网络中的数据

2.IO流主如何分类?
分为输入流(读),输出流(写)
又能分为字节流(所有文件)与字符流(文本)

3.主要哪一些抽象类?
InputStream,OutputStream操作字节,Reader,Writer操作字符

4.创建字节输出流时,如果路径不对会怎样?
5.如果文件已存在会怎样?
6.使用write方法写入文件的时候写入的数字代表的是什么?
7.除了写入单个字节,如何写入多个字节?
8.使用完字节输出流之后,最后一步是什么?
public class Demo281 {
    public static void main(String[] args) throws IOException {
        String str = "JAVA基础\\src\\Day28\\MyText\\a.txt";
        System.out.println("4.如果路径不正确会报错");

        System.out.println("5.如果文件已经存在,会清空文件");
        FileOutputStream fos = new FileOutputStream(str);

        System.out.println("6.写的是97,实际写到本地文件的是ascii码表上的字符");
        for (int i = 'a'; i <= 'z'; i++) fos.write(i);

        System.out.println("7.定义数组写入文件,后面的参数代表截取的位置,在后面定义写入内存的时候会用到");
        byte[] arr = new byte[26];
        for (int i = 0; i < arr.length; i++) arr[i] = (byte) ('A' + i);
        fos.write(arr, 0, 26);

        System.out.println("8.最后一步释放资源");
        fos.close();
    }
}

  


二.使用输出流续写,输出字符串,换行

1.如何续写?
2.如何输入字符串?
3.在使用字节输出流输出成文件时,如何换行?
public class Demo282 {
    public static void main(String[] args) throws IOException {
        String str = "JAVA基础\\src\\Day28\\MyText\\a.txt";
        System.out.println("1.续写只要在定义字节输出流的时候把第二个参数设置true即可");
        FileOutputStream fos = new FileOutputStream(str,true);

        System.out.println("2.把字符串变成字节数组换行操作");
        System.out.println("3.使用\\r\\n都可以换行(三个操作系统的换行符都不一样,java帮忙处理了)");
        fos.write("\nHello IO!".getBytes());
        fos.write("\r666".getBytes());
        fos.close();
    }
}


三.读取整个文件:一个一个字节读取

1.使用read方法读取数据时,返回的参数代表什么?
2.如何使用while循环读取整个文件?
public class Demo283 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("JAVA基础\\src\\Day28\\MyText\\a.txt");
        int i;
        System.out.println("1.使用read方法读取资源,返回值为int类型的读到的字节,到最后返回-1");
        System.out.println("2.在while循环里面使用赋值语句,注意在这里赋值的语句优先级较低,需要加括号");
        while ((i=fis.read()) != -1)  System.out.print((char) i);
        fis.close();
    }
}


四.拷贝文件

1.如何拷贝文件?
2.一次只读写一个字节有什么缺点?
3.对于输入流与输出流的关闭顺序有什么规范吗?
public class Demo284 {
    public static void main(String[] args) throws IOException {
        String str = "JAVA基础\\src\\Day28\\MyText\\";
        System.out.println("1.同时使用fis与fos可以拷贝文件");
        FileInputStream fis = new FileInputStream(str+"a.txt");
        FileOutputStream fos = new FileOutputStream(str+"aCopy.txt");

        System.out.println("2.一次只读写一个字节,速度非常慢");
        int b;
        while ((b = fis.read())!=-1){
            System.out.print(b+" ");
            fos.write(b);
        }
        System.out.println();
        System.out.println("3.先开的资源后关闭");
        fos.close();
        fis.close();
    }
}


五.案例:使用read一次读取一个字节数组的数据,每次读取尽量把数组装满

1.使用read读取数组时,返回值是什么?
2.在读完数据之后,再次读取数据会替代之前的老数据,老数据会被全部清空吗?
3.全部读取完之后会返回什么?
4.如何解决掉多余的老数据呢?
public class Demo285 {
    public static void main(String[] args) throws IOException {
        String str = "JAVA基础\\src\\Day28\\MyText\\a.txt";
        FileInputStream fis = new FileInputStream(str);
        byte[] bytes = new byte[50];

        System.out.println("1.使用read读取数组的返回值代表本次读取的数据个数");
        int len = fis.read(bytes);
        String MyStr = new String(bytes);
        System.out.println("本次读取到的数据:"+MyStr);
        System.out.println("本次读取的数据量:"+len);

        System.out.println("2.读完的数据会覆盖之前的数据:但是不会全部清除");
        len = fis.read(bytes);
        MyStr = new String(bytes);
        System.out.println(MyStr);
        System.out.println("本次读取了数据量:"+len);

        System.out.println("3.全部读取完之后再读取会返回-1,数据依旧是老数据");
        len = fis.read(bytes);
        MyStr = new String(bytes);
        System.out.println(MyStr);
        System.out.println("本次读取了数据量:"+len);

        System.out.println("解决办法:使用len进行参数传递,如new String(bytes,0,len)");
        fis.close();
    }
}


六.文件拷贝改进:快速拷贝大文件

public class Demo286 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("C:\\Users\\33428\\Videos\\haniwa\\いつだって戦ってる.mp4");
        FileOutputStream fos = new FileOutputStream("C:\\Users\\33428\\Desktop\\Haniwa.mp4");
        byte[] bytes = new byte[1024 * 1024*10];
        int len;
        while ((len = fis.read(bytes)) != -1) fos.write(bytes, 0, len);
        fos.close();
        fis.close();
    }
}


七.finally:捕获异常完整形态

1.finally后面的代码块的执行特点?
2.如何在try-catch之后使用finally关闭流?
public class Demo287 {
    public static void main(String[] args) {
        System.out.println("1.finally一定会执行:除非虚拟机停止");
        String str = "JAVA基础\\src\\Day28\\MyText\\a.txt";

        System.out.println("2.在try-catch代码块外设置io流为null");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(str);
            fis.read();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("在finally中,只有建立了传输通道(IO流不为null)才关闭");
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


八.AutoCloseable:JDK7出现:特定情况下自动释放资源

实现这个接口的类可以在try-catch后自动释放资源
在try-catch中具体应该如何实现自动释放资源?
public class Demo288 {
    public static void main(String[] args) {
        String str1 = "JAVA基础\\src\\Day28\\MyText\\a.txt";
        String str2 = "JAVA基础\\src\\Day28\\MyText\\aCopy.txt";
        System.out.println("在try后加入括号(),在括号中写入需要定义的对象,对象用分号隔开");
        System.out.println("JDK9之后就可以在外面创建对象,括号里面只写变量名");
        try (FileInputStream fis = new FileInputStream(str1);
             FileOutputStream fos = new FileOutputStream(str2)) {
            fis.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 


 

九.使用使用String与byte数组进行编码解码

1.字符集详解
Windows中文系统使用的编码方式是什么?系统显示为什么?
windows中文系统使用的就是GBK(国家标准扩展,是一种编码方式),系统显示为ANSI

2.在GBK编码中,汉字用多少个字节存储?一般以0开头还是1开头?
在GBK中一个汉字用两个字节存储,英文二进制0开头,中文1开头

3.UniCode字符集:包含世界大多数文字

4.UTF-数字,后面的数字代表什么意思,在UTF-8中,中日韩文一般用多少个字节存储?
UTF-16:(UniCode Transfer Format)最常用的就是转成16比特位(两字节)
UTF-32:统一32字节保存
UTF-8:用1-4字节保存,使用的最多,英文一个字节,中日韩三个字节

5.在UTF-8中,1-4位字节的数据的每个字节的开头有什么特点?
一个字节的第一位是0(留下7位自由选择)
两个字节的前两位是110,后面字节的全是10开头(留下11位自由选择)
三个字节前两位是1110,后面字节全是10开头(留下16位自由选择)
上面这样做是为了区别一个字符开始的字节在何处

6.UTF-8如何对汉字进行编码?
汉字要先查询Unicode,再转换成UTF-8编码

7.乱码的原因大多数是因为什么?
乱码原因,很大原因是编码解码方式不一样:如GBK一次读汉字读两个字节,而UTF-8一次读三个字节

8.如何避免乱码?
避免乱码:不要用字节流读取文本文件,编码解码使用同一字符集与同一编码方式


使用使用String与byte数组进行编码解码
1.如何把字符串编码变成字节数组?
2.如何把字节数组解码变成字符串?
3.上述两个操作如何指定编码与解码方式?
public class Demo289 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "元神,启动!";
        System.out.println("1.使用String的getBytes方法,把要存储的数据进行编码:以默认方式(UTF-8)编码");
        byte[] bytes = str.getBytes();
        System.out.println(Arrays.toString(bytes));

        System.out.println("2.在字符串中的构造方法中传入字节数组解码:把字节数据变成想要查看的内容,默认UTF-8");
        System.out.println(new String(bytes,"UTF-8"));

        System.out.println("3.getBytes方法中传入参数代表编码方式");
        bytes = str.getBytes("GBK");
        System.out.println(Arrays.toString(bytes));

        System.out.println("4.传入第二个参数代表解码方式");
        System.out.println(new String(bytes,"GBK"));
    }
}

 


 

十.FileReader与FileWriter:操作本地文件的字符输入输出流

字符流
1.字符流的底层是?
底层就是字节流,添加了字符集的概念,适合操作纯文本文件

2.字符输入流与输出流每一次读取或写出多少数据?
输入流:按照规则读取,如果是英文就读一个字节,如果是中文就读三字节(根据不同编码方式)
输出流:按指定编码格式进行编码并且写到文件当中

3.一般使用什么类进行字符输入与输出?
使用Reader,Writer的实现类:FileReader与FileWriter来读写文件

读写缓存区
在字符流输入流底层,在-内存区-创建了一个8KB的缓冲区来存储数据,在第一次读数据的时候尽量装满,每次读取都从缓冲区中读取
每次读取都会判断缓冲区是否有数据可以读,没有数据读了就在文件中继续找数据放进去,新的数据替代老的数据(多出来的老数据不会清空)
在字符输出流底层,也会在-内存区-创建8KB的byte数组缓存数据

4.在读写缓存区中,数据什么时候会进行传输?有哪三种情况?
只有当:   数组满了 || flush()  ||  close()      才会把数据放进去

5.读写缓存区的位置在哪里?
区别读缓存区与写缓存区:读是一次性先拿,写是一次性后给,都是在内存中创建的空间!

FileReader与FileWriter:操作本地文件的字符输入输出流
使用reader与writer的操作与fis与fos情况相似,不同点:
1.字符输入与输出读取与写入的是字符还是字节?
2.字符输出流可以除了写入字符以及字符数组,还能写入什么?
3.在使用输入流的无参read方法时,返回的整数代表什么?
public class Demo2810 {
    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("JAVA基础\\src\\Day28\\MyText\\b.txt");
        FileWriter fileWriter = new FileWriter("JAVA基础\\src\\Day28\\MyText\\bCopy.txt");
        System.out.println("1.使用字符数组读取与写入");
        char[] chars = new char[1024];
        int len;
        System.out.println("2.除了传递char[],还能传递string去写入");
        while ((len = fileReader.read(chars)) != -1) {
            fileWriter.write(chars, 0, len);
        }
        fileWriter.close();
        fileReader.close();

        fileReader = new FileReader("JAVA基础\\src\\Day28\\MyText\\b.txt");
        int i;
        System.out.println("3.返回的整数表示字符集上的数据,强转即可变成字符");
        while ((i = fileReader.read()) != -1) {
            System.out.print((char) i);
        }
        fileReader.close();
    }
}

 


 

十一.案例:拷贝文件夹,包括其子文件夹

public class Demo2811 {
    public static void main(String[] args) throws IOException {
        File file1 = new File("D:\\Java基础\\Java基础-资料");
        File file2 = new File("D:\\实验文件夹");
        copy(file1, file2);
    }
    public static void copy(File file1, File file2) throws IOException {
        //创建新的文件名字,看情况创建文件或者文件夹,这里使用getName获取文件名或者是文件夹名,不需要使用split方法
        File file1Copy = new File(file2, file1.getName());
        if (file1.isFile()) {
            //是文件,所以要拷贝,这里不需要创建文件:输出流自动创建!
            FileInputStream fis = new FileInputStream(file1);
            FileOutputStream fos = new FileOutputStream(file1Copy);
            byte[] bytes = new byte[1024 * 1024];
            int len;
            if ((len = fis.read(bytes)) != -1)fos.write(bytes,0,len);
            fos.close();
            fis.close();
        }else {
            //不是文件:所以要创建文件夹
            file1Copy.mkdirs();
            //遍历file1
            for (File file : file1.listFiles()) {
                copy(file,file1Copy);
            }
        }
    }
}

 


 

十二.案例:文件加密与解密

a^b^b之后依然是a:如100^10
1100100    a
0001010    b
—————————
1101110    密文
0001010    b
—————————
1100100    a

这里我们只看一位:
1^0^0:在这里1一直不变
1^1^1:在这里1取反变0再取反变1
0也是这样的结果。
奇妙比喻:1碰到0:不变即可,1碰到1:总得有一方变0

结论:计算机中的数据经过两次相同的异或运算之后,数据不变
public class Demo2812 {
    public static void main(String[] args) throws IOException {
        encryptAndDecrypt("a.jpg", "b.jpg");
        encryptAndDecrypt("b.jpg", "c.jpg");
    }

    public static void encryptAndDecrypt(String str1, String str2) throws IOException {
        String str = "Java基础\\src\\Day28\\MyPic\\";
        FileInputStream fis = new FileInputStream(str + str1);
        FileOutputStream fos = new FileOutputStream(str + str2);
        byte[] bytes = new byte[1024];
        int len;
        while ((len = fis.read(bytes)) != -1) {
            for (int i = 0; i < bytes.length; i++) bytes[i] ^= 66;
            fos.write(bytes, 0, len);
        }
        fos.close();
        fis.close();
    }
}

 


 

十三.案例:修改文件中的数据,再排序数据

public class Demo2813 {
    public static void main(String[] args) throws IOException {
        FileReader reader = new FileReader("D:\\IDEACode\\demo1\\JAVA基础\\src\\Day28\\MyText\\c.txt");
        StringBuilder sb= new StringBuilder();
        int i;
        //如果是用数组的方式读取,一定要记得要限制范围
        while((i=reader.read())!=-1) sb.append((char)i);
        reader.close();
        //可以先把read的操作全部做完再创建writer
        FileWriter writer = new FileWriter("D:\\IDEACode\\demo1\\JAVA基础\\src\\Day28\\MyText\\cSort.txt");
        String str= Arrays.toString(Arrays.stream(sb.toString().split("-"))
                .map(Integer::parseInt).sorted().toArray(Integer[]::new))
                //这里对于数据只用改动部分(只需要替换字符与去除第一个与最后一个字符),无需StringBuilder再遍历了,尽量简化你的操作
                .replace(", ","-");
        writer.write(str.substring(1,str.length()-1));
        writer.close();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值