Java学习笔记------IO流(六)

该学习笔记是根据阿玮老师《黑马程序员Java零基础视频教程》总结出来的,非常感谢阿玮老师。

一. File类

  1. 简单介绍
    • 路径分为两种:相对路径和绝对路径。相对路径不带盘符,默认到当前项目下去找;绝对路径带盘符。
      路径

    • java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。
      (1)File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。Java-File类详解(一篇讲透)
      (2)想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。File对象可以作为参数传递给流的构造器,指明读取或写入的"终点"。
      (3) File类的对象表示一个路径,可以是文件的路径、也可以是文件夹的路径,其中这个路径可以是存在的,也可以是不存在的。File类常见的构造方法有三个,如下:
      FIle类构造方法

//第一种构造方法
        String str = "D:\\JAVA\\project\\SImpleTest\\data1.txt";
        File file1 = new File(str); //创建File对象file1.
        System.out.println(file1);

        // 第二种构造方法
        String parent = "D:\\JAVA\\project\\SImpleTest";
        String child = "data1.txt";
        File file2 = new File(parent,child);
        System.out.println(file2);

        //第三种构造方法
        File parent1 = new File(parent);
        File file3 = new File(parent1,child);
        System.out.println(file3);
/*
输出:
D:\JAVA\project\SImpleTest\data1.txt
D:\JAVA\project\SImpleTest\data1.txt
D:\JAVA\project\SImpleTest\data1.txt
*/
* 关于File类常见的方法大家可以自行网上查询,反正大致上分为五类:判断、获取、创建、删除、获取并遍历。

二. IO流

  1. 简单介绍
    • 由于File类只能对文件本身进行操作,不能读写文件里面存储的数据,因此我们需要借助IO流来实现文件数据的读写操作。"I"表示input输入流,"O"表示output输出流,"IO"流就是输入输出流。我们可以把IO流看成是程序(内存)和文件之间,用于传输数据的通道。那有一个问题,什么是输入流呢?什么是输出流呢?
      在这里插入图片描述

    • 输入流:从文件中读取数据到程序(内存)中,这个就是输入流;输出流:从程序(内存)中写出数据到文件中,这个就是输出流。我们可以这样区分输入流和输出流:数据读取到程序中---输入流;把数据写出文件--输出流。关于输入流和输出流的划分如下图所示,其中字节流一次读取一个字节(byte)的数据;字符流一次读取一个字符的数据。字节流是万能的,什么类型的文件都可以读取,而字符流只能读取纯文本文件。
      在这里插入图片描述

三. 字节流

  1. FileOutputStream(字节输出流):操作本地文件的字节输出流,可以把程序中的数据写出到本地文件中。书写步骤:(1)首先创建字节输出流对象;(2)然后写出数据;(3)最后释放资源。
    三种数据方式
// FileOutputStream:操作本地文件的字节输出流,可以把程序中的数据写到本地文件中.
        String path1 = ".\\data1.txt";
        File file = new File(path1);
        System.out.println(file.exists());
        FileOutputStream fos = new FileOutputStream(path1);//会让程序和path1路径下的文件之间产生传输通道
        fos.write(97);
        fos.write(98);// 在上面通道中写出数据
        byte[] bt = {99,100,101,102,103,104};
        fos.write(bt);
        fos.write(bt,1,2);//从索引为1开始写出数据,然后一共写出2个.
        fos.close(); // 关闭上述通道

        // 字节输出流的细节:
        //1.创建字节输出流对象.细节(1)传递的参数可以是字符串表示的路径,也可以是File对象
        //                   细节(2)如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的;
        //                   细节(3)如果文件已经存在,则会清空文件(也就是把原有的数据覆盖了).
        //2.写出数据. 细节(1)如果write方法传递的参数是整数,那么实际上写到本地文件中的是ASCII上整数对应的字符
        //3.释放资源: 细节(1)每次使用完输出流之后都要释放资源--关闭通道

        //换行写. Windows系统:\r\n--回车换行--换行符; linux系统: \n--换行符;  Mac: \r-换行符
        // 在Windows操作系统中,java对回车换行进行了优化,虽然完整是\r\n,但是我们只写其中一个\r或者\n也可以实现换行,
        // 因为java会在底层实现补全.但是还是建议写全
        String path2 = ".\\data2.txt";
        FileOutputStream fos1 = new FileOutputStream(path2);
        String str = "helloWorld";
        byte[] bytes = str.getBytes(); // getBytes()获取字符串对应的字节数组(也就是将字符串转换为字节数组)
        System.out.println(Arrays.toString(bytes));
        fos1.write(bytes);
        // 写换行符
        String str1 = "\r\n";
        fos1.write(str1.getBytes());

        String str2 = "666";
        fos1.write(str2.getBytes());
        fos1.close();
        // 续写(追加写):
        // 如果想要续写,打开续写开关即可.开关位置:创建对象的第二个参数,默认false表示关闭续写,此时创建对象会清空原有的文件;
        // 手动传递true,表示打开续写,此时创建对象不会清空原有的文件
        FileOutputStream fos2 = new FileOutputStream(path2,true); // 后面写true表示续写,默认是false
        fos2.write("\r\n".getBytes());
        fos2.write("111".getBytes());
/*
输出:
true
[104, 101, 108, 108, 111, 87, 111, 114, 108, 100]
*/
  1. FileInputStream(字节输入流):操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。书写步骤:(1)首先创建字节输入流对象;(2)然后读取数据;(3)最后释放资源。
		// FileInputStream:操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来.
        String path = ".\\data1.txt"; // data1.txt对应的数据为:abcdefghde
        //1.创建对象
        FileInputStream fis = new FileInputStream(path);
        //2.读取数据
        int read = fis.read();
        System.out.println((char) read);
        //释放资源
        fis.close();

        // 字节输入流的细节:
        //1.创建字节输入流对象. 细节(1)如果文件不存在,就直接报错.
        //2.读取数据. 细节(1)一次读一个字节,读出来的是数据在ASCII码上对应的数字;
        //           细节(2)读到文件末尾了,read方法返回-1;
        //3.释放资源: 细节(1)每次使用完输入流之后都要释放资源--关闭通道

        // 字节输入流循环读取
        FileInputStream fis1 = new FileInputStream(path);
        int b;
        while ((b = fis1.read()) != -1){
            System.out.print((char) b);
        }
/*输出:
a
abcdefghde
*/

(1)文件拷贝代码练习:

		String path1 = ".\\data.txt"; // 已经存在的文件
        String path2 = ".\\copyData.txt"; //要拷贝的文件
        // 创建对象
        FileInputStream fis = new FileInputStream(path1); //将文件中的数据读取到程序中,需要创建输入流.
        FileOutputStream fos = new FileOutputStream(path2); //将程序中的数据写出到文件中,需要创建输出流.

        // 拷贝:边读边写
        int b;
        while ((b = fis.read()) !=-1){
            fos.write(b);
        }
        // 关闭资源:规则是先打开的最后关闭.
        fos.close();
        fis.close();

(2)FileInputStream一次读写一个字节,如果拷贝的文件过大,那么上述的文件拷贝方法速度会非常慢,因此我们需要一次读取多个字节数据。
读取字节
读取多个字节
(3)一次读取多个字节代码示例:

		String path1 = ".\\data.txt"; // 数据为:hello world java--16字节
        // 创建字节流对象
        FileInputStream fis = new FileInputStream(path1);
        // 读取数据
        byte[] bytes = new byte[10]; //每次读取尽可能把字节数组装满
        int len1 = fis.read(bytes); 
//一次读取多个字节数据,具体读取多少跟字节数组的长度有关.len表示本次读取了多少个字节数据.
// 第一次往字节数组bytes里面读取10个字节数据:hello worl,因此len1=10,bytes为[hello worl].
        System.out.println(len1); 
        String str = new String(bytes);
        System.out.println(str);

        int len2 = fis.read(bytes); 
// 因为一共有16字节大小的数据,第一次读取了10字节数据,还剩下6字节数据.所以第二次只能读取6字节数据,len2=6.
//但是第一次bytes里面为[hello worl],第二次读取的"d java"会将"hello "覆盖,但"worl"不会覆盖.因此第二次读取到bytes里面为[d javaworl]
        System.out.println(len2);
        System.out.println(new String(bytes));
        System.out.println(new String(bytes,0,len2)); // 这样写可以过滤上次没有被覆盖的元素,也就是读取多少就输出多少
        fis.close();
/*输出:
10
hello worl
6
d javaworl
d java
*/

(4)文件拷贝代码优化:

		String path1 = ".\\data.txt"; // 数据为:hello world java--16字节
        String path2 = ".\\dataCopy.txt";

        // 创建对象
        FileInputStream fis = new FileInputStream(path1);
        FileOutputStream fos = new FileOutputStream(path2);

        //拷贝
        int len;
        byte[] bytes = new byte[1024*1024*5]; //5MB大小
        while ((len = fis.read(bytes)) != -1){
            fos.write(bytes,0,len); //表示读多少写多少
        }

        //释放资源
        fos.close();
        fis.close();

四. 字符集

  1. ASCII码表
    ASCII表
  2. GBK字符集
    GBK字符集
    (1)GBK存储英文的规则
    GBK英文存储
    (2)GBK存储中文(汉字)的规则
    在这里插入图片描述
    规则
    规则122222
    (3)总结
    总结
  3. Unicode(万国码)。Unicode编码方式有:UTF-16编码规则----用2~4个字节进行存储;UTF-32编码规则----固定使用四个字节进行存储;UTF-8编码规则----使用1~4个字节进行存储;Unicode Transfer Format(Unicode转换格式)–UTF,其中UTF-8编码规则是实际开发中最为常见的。在UTF-8编码规则中文使用3个字节表示,英文使用1个字节表示。记住UTF-8不是字符集,而是Unicode字符集的一种编码方式
    1
    (1)Unicode存储英文的规则
    存储英文
    (2)Unicode存储中文(汉字)的规则
    存储汉字
    (3)总结
    总结
  4. 为什么会有乱码呢?
    答:(1)读取数据时没有读完整个汉字;(2)编码和解码的方式不统一。
    那如何不产生乱码呢?
    答:(1)不要使用字节流读取文本文件;(2)编码和解码使用同一个码表,同一种编码方式。
    原因1
    编码和解码的方式不统一
    原因2
  5. java中编码和解码
    编码和解码
		String str = "ai你哟";
        //默认方式进行编码
        byte[] bytes = str.getBytes(); 
//IDEA默认编码方式为UTF-8,中文3字节,英文1字节;eclipse默认编码方式为GBK,中文2字节,英文1字节.
        System.out.println(Arrays.toString(bytes)); //'a':1字节; 'i':1字节; '你':3字节; '哟':3字节,共8字节.
        System.out.println(bytes.length);

        // 指定编码方式
        byte[] gbk = str.getBytes("GBK"); //'a':1字节; 'i':1字节; '你':2字节; '哟':2字节,共6字节.
        System.out.println(Arrays.toString(gbk));
        System.out.println(gbk.length);

        //解码
        String str1 = new String(bytes);
        String str2 = new String(gbk,"GBK");
        System.out.println(str1);
        System.out.println(str2);
/*输出:
[97, 105, -28, -67, -96, -27, -109, -97]
8
[97, 105, -60, -29, -45, -76]
6
ai你哟
ai你哟
*/

五. 字符流

  1. FileReader(字符输入流)书写步骤:(1)创建字符输入流对象;(2)读取数据;(3))释放资源。
    创建字符流对象
    读取数据
    代码示例
//data.txt数据为: 你好世界
//               hello World
//               你好java
//               hello java
// 文件中的数据每一行末尾都有一个隐藏换行符(除了最后一行)--\r\n(两个字符'\r'和'\n'),其中回车符'\r'在打印的时候没有打印出来.
// 换行符'\n'打印的时候会直接换行.
        String path = ".\\data.txt";
        // 1.创建对象并关联本地文件
        FileReader fr = new FileReader(path);

        //空参读取的read.(1)read默认也是一个字节一个字节的读取,如果遇到中文就会一次读取多个字节;
        // (2)在读取之后,方法底层还会进行解码并转成十进制,最终把这个十进制作为返回值.
        int ch;
        while ((ch=fr.read()) != -1){
            System.out.print((char) ch);
        }
        fr.close();

        //1.创建对象
        FileReader fr1 = new FileReader(path);
        //2.带参数的read:把读取数据、解码、强转三步合并了,把强转之后的字符放到字节数组中.
        char[] chars = new char[6]; //一次读6个字符,'你'、'好'、'J'、'v'这些都是一个字符.
        int len;
        System.out.println();
        while ((len=fr1.read(chars)) != -1){
            System.out.print(new String(chars,0,len)); //把字节数组中的数据变成字符串再进行打印
        }
        fr1.close();
/*输出:
你好世界
hello World
你好java
hello java
你好世界
hello World
你好java
hello java
*/
  1. FileWriter(字符输出流)
    (1)构造方法
    构造方法
    (2)成员方法
    成员方法
    (3)细节处理
    细节处理
    (4)代码
		String path = ".\\data1.txt";
        //1.创建字符输出流对象.
        FileWriter fw = new FileWriter(path);
        //写一个字符:'我'--25105
        fw.write(25105);
        //写一个字符串 "hello world".
        fw.write("hello World");
        // 写一个字符串的一部分
        fw.write("!!!!!!",0,3);
        // 写一个字符数组
        char[] chars = {'你','好','世','界','\r','\n','A'};
        fw.write(chars);
        // 释放资源
        fw.close();
        //续写:FileWriter fw = new FileWriter(path,true);设置true

六. 缓冲流

  1. 字节缓冲流。
    字节缓冲流
  2. 字符缓冲流。
    字符缓冲流
    特有方法1
    特有方法1
    代码示例
		String path1 = ".\\data.txt";
        // 1.创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader(path1));
        // readLine方法在读取数据的时候,一次读取一行数据,遇到回车换行结束,但是该方法不会把回车换行读取到内存中.
        // (也就是readLine方法不会读取回车换行符)
        String s;
        while ((s= br.readLine()) != null){
            System.out.println(s);
        }
        br.close();

        //1.创建字符缓冲输出流对象
        String path2 = ".\\dataCopy.txt";
        BufferedWriter bw = new BufferedWriter(new FileWriter(path2));
        bw.write("你骚气的样子,我无法形容");
        bw.newLine();
        bw.write("但是我好喜欢");

        bw.close();
/*输出:
你好世界
hello World
你好java
hello java
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值