javaSE------5.IO流

1.File 类

1.1 File类概述和构造方法

File 类介绍:

它是文件和目录路径名的抽象表示

文件和目录是可以通过 File封装成对象的

对于 File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。

它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的

File 类的构造方法:

File(String pathname)   通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
示例:
import java.io.File;
public class FileDemo {
    public static void main(String[] args) {
    //File(String pathname)   通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
        File f1=new File("D:\\itcast\\java.txt");
        System.out.println(f1);

    //File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
        File f2=new File("D:\\itcast","java.txt");
        System.out.println(f2);
    //File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
        File f3=new File("D:\\itcast");
        File f4=new File(f3,"java:txt");
        System.out.println(f4);
    }
}

1.2 File类创建功能

方法分类:

public boolean createNewFile()    当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir()     创建由此抽象路径名命名的目录
public boolean mkdirs()    创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
示例:
import java.io.File;
import java.io.IOException;

public class FileDemo02 {
    public static void main(String[] args) throws IOException {
//public boolean createNewFile()    当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
        //需求1:我要在D:\\itcast目录下创建一个文件java.txt
        File f1=new File("D:\\itcast\\java.txt");
        System.out.println(f1.createNewFile());

//public boolean mkdir()     创建由此抽象路径名命名的目录
        //需求2:我要在D:\\itcast目录下创建一个目录JavaSE
        File f2 = new File("D:\\itcast\\javaSE");
        System.out.println(f2.mkdir());

//public boolean mkdirs()    创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
        //需求3:我要在D:\\itcast目录下创建一个多级目录JavaWEB\\HTML
        File f3=new File("D:\\itcast\\JavaWEB\\HTML");
        System.out.println(f3.mkdirs());

        //需求4:我要在D:\\itcast目录下创建一个文件javase.txt
        File f4=new File("D:\\itcast\\javase.txt");
        System.out.println(f4.createNewFile());
    }
}

1.3 File类判断和获取功能

判断功能:

public boolean isDirectory()     测试此抽象路径名表示的File是否为目录
public boolean isFile()        测试此抽象路径名表示的File是否为文件
public boolean exists()       测试此抽象路径名表示的File是否存在

获取功能:

public String getAbsolutePath()   返回此抽象路径名的绝对路径名字符串
public String getPath()   将此抽象路径名转换为路径名字符串
public String getName()   返回由此抽象路径名表示的文件或目录的名称
public String[] list()    返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles()   返回此抽象路径名表示的目录中的文件和目录的File对象数组  (带绝对路径,File改写了toString方法)
import java.io.File;
public class FileDemo03 {
    public static void main(String[] args) {
        //创建一个File对象
        File f1=new File("myFile\\java.txt");//java.txt是已经创建好的

//    public boolean isDirectory()     测试此抽象路径名表示的File是否为目录
        System.out.println(f1.isDirectory());
//    public boolean isFile()        测试此抽象路径名表示的File是否为文件
        System.out.println(f1.isFile());
//    public boolean exists()       测试此抽象路径名表示的File是否存在
        System.out.println(f1.exists());
        System.out.println("--------");

//    public String getAbsolutePath()   返回此抽象路径名的绝对路径名字符串
        System.out.println(f1.getAbsolutePath());
//    public String getPath()   将此抽象路径名转换为路径名字符串
        System.out.println(f1.getPath());
//    public String getName()   返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f1.getName());
        System.out.println("--------");

        //数组
        //创建一个File对象
        File f2=new File("D:\\itcast");
//    public String[] list()    返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
        for (String strArr:f2.list()) {
            System.out.println(strArr);
        }
        System.out.println("--------");
//    public File[] listFiles()   返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File[] files = f2.listFiles();
        for (File fileArr:files) {
            //System.out.println(f);
            //System.out.println(f.getName());
            if (fileArr.isFile()) {
                System.out.println(fileArr.getName());
            }
        }
    }
}

1.4 File类删除功能

public boolean delete()   删除由此抽象路径名表示的文件或目录

绝对路径和相对路径的区别:

绝对路径:完整的路劲名,不需要任何其他信息就可以定位它所表示的文件,例如:E:\itcast\java.txt

相对路径:必须使用取自其他路径名的信息进行解释。例如:myFile\java.txt

示例:
import java.io.File;
import java.io.IOException;

public class FileDemo04 {
    public static void main(String[] args) throws IOException {

        //需求1:在当前模块目录下创建java.txt文件
        File file=new File("myFile\\java.txt");
        //需求2:删除当前模块目录下的java.txt文件
        System.out.println(file.delete());
        System.out.println("--------");

        //需求3:在当前模块目录下创建itcast目录
        File f2 = new File("myFile\\itcast");
        System.out.println(f2.mkdir());
        //需求4:删除当前模块目录下的itcast目录
        //f2.delete();
        System.out.println(f2.delete());
        System.out.println("--------");

        //需求5:在当前模块下创建一个目录itcast,然后在该目录下创建一个文件java.txt
        File f3 = new File("myFile\\itcast");
        System.out.println(f3.mkdir());
        File f4 = new File("myFile\\itcast\\java.txt");
        System.out.println(f4.createNewFile());

        //需求6:删除当前模块下的目录itcast(只能先删除目录再删文件)
        System.out.println(f4.delete());
        System.out.println(f3.delete());
    }
}

2. 递归

2.1 递归

递归的介绍:
以编程的角度来看,递归指的是方法定义中调用方法本身的现象

把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算

递归的注意事项:
递归一定要有出口。否则内存溢出

递归虽然有出口,但是递归的次数也不宜过多。否则内存溢出

public class DiGuiDemo {
    public static void main(String[] args) {
        //不死神兔
        //1.普通方法
        int arr[]=new int[20];

        for (int i = 0; i < arr.length; i++) {
            if (i == 0||i==1) {
                arr[i]=1;
            }else {
                arr[i]=arr[i-1]+arr[i-2];
            }
        }
        System.out.println(arr[19]);
        //调用递归方法:
        System.out.println(show(20));
    }

        //2.递归方法:
        /*
        递归解决问题,首先就是要定义一个方法:
        定义一个方法f(n):表示第n个月的兔子对数
        那么,第n-1个月的兔子对数该如何表示呢?f(n-1)
        同理,第n-2个月的兔子对数该如何表示呢?f(n-2)
        StackOverflowError:当堆栈溢出发生时抛出一个应用程序递归太深
        */
        public static int show(int n) {
            if (n==1||n==2) {
                return 1;
            }else {
               return show(n-1)+show(n-2);
            }
        }
}

2.2 递归求阶乘

案例需求:
用递归求5的阶乘,并把结果在控制台输出
public class JieChengDemo {
    public static void main(String[] args) {
        System.out.println(jC(5));
    }
    
    //5的阶乘:5!=5*4*3*2*1  
    //n的阶乘:n!=n*(n-1)!
    //出口:   1!=1
    public static int jC(int n) {
        if (n == 1) {
            return 1;
        }else {
            return n*jC(n-1);
        }
    }
}

2.3 递归遍历目录

案例需求:
给定一个路径(E:\itcast),通过递归完成遍历该目录下所有内容,并把所有文件的绝对路径输出在控制台

import java.io.File;
public class DirectoryDemo {
    public static void main(String[] args) {
        //创建File的对象
        File f=new File("D:\\itcast");

        //调用方法
        show(f);
    }

    public static void show(File f) {
        //调用  返回File对象数组的方法
        File[] fileArray = f.listFiles();
        //先判断fileArray数组是否为空
        if (fileArray != null) {
            //遍历fileArray数组
            for (File s:fileArray) {
                //判断集合中的对象是否为目录
                if (s.isDirectory()) {
                    //是,递归调用
                    show(s);
                }else {
                    //不是,获取文件绝对路径名,并输出在控制台
                    System.out.println(s.getAbsolutePath());
                }
            }
 	}

3. IO流(字节流)

3.1 IO流概述和分类

(1)IO 流介绍
IO :输入/输出(Input/Output)

:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输

IO 流就是用来处理设备间数据传输问题的。

常见的应用:文件复制;文件上传;文件下载

(2)IO 流的分类
按照数据的流向:

输入流:读数据

输出流:写数据

按照数据类型来分:
字节流:字节输入流,字节输出流

字符流:字符输入流,字符输出流

(3)IO 流的使用场景
如果操作的是纯文本文件,优先使用字符流

如果操作的是图片、视频、音频等二进制文件。优先使用字节流

如果不确定文件类型,优先使用字节流。字节流是万能的流

3.2 字节流写数据

字节流抽象基类:
InputStream :这个抽象类是表示字节输入流的所有类的超类

OutputStream :这个抽象类是表示字节输出流的所有类的超类

子类名特点:子类名称都是以其父类名作为子类名的后缀

字节输出流:

FileOutputStream(String name)   :创建文件输出流以指定的名称写入文件

使用字节输出流写数据的步骤:
(1)创建字节输出流对象 (调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)

(2)调用字节输出流对象的写数据方法

(3)释放资源 (关闭此文件输出流并释放与此流相关联的任何系统资源)

3.3 字节流写数据的三种方式

void write(int b)       将指定的字节写入此文件输出流 一次写一个字节数据
void write(byte[] b)    将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据
void write(byte[] b, int off, int len)     将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据
示例:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class ByteStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建IO流对象
        //此过程包含了: 调用系统功能创建了文件        创建字节输出流对象      让字节输出流对象指向文件)
        FileOutputStream fos = new FileOutputStream("myIO\\fos.txt");


        //void write(int b):将指定的字节写入此文件输出流
//        fos.write(97);
//        fos.write(98);
//        fos.write(99);
//        fos.write(100);
//        fos.write(101);

        //void write(byte[] b)   将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据
//         byte[] bys = {97, 98, 99, 100,101};
//         fos.write(bys);

         //还可以调用String类中的方法
//        byte[] by = "12345".getBytes();
//        fos.write(by);


        //void write(byte[] b, int off, int len)   将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据
        byte[] by = "abcde".getBytes();
        //fos.write(by,0,by.length);
        fos.write(by,2,3);

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

3.4 字节流写数据的两个小问题

字节流写数据如何实现换行:
windows:\r\n

linux:\n

mac:\r

字节流写数据如何实现追加写入:

public FileOutputStream(String name,boolean append)
创建文件输出流以指定的名称写入文件。如果第二个参数为 true ,则字节将写入文件的末尾而不是开头
举例:
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建输出流对象
        FileOutputStream fos=new FileOutputStream("myIO\\fos.txt",true);

        //写数据
        for (int i = 0; i < 10; i++) {
            fos.write("hello".getBytes());
            fos.write("\r\n".getBytes());
        }

        //关闭资源
        fos.close();
    }
}

3.5 字节流写数据加异常处理

异常处理格式:try-catch-finally

try {
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}finally{
	执行所有清除操作;
}

finally 特点
被 finally控制的语句一定会执行,除非JVM退出

示例:
public static void main(String[] args) {
        //加入finally来实现释放资源
        FileOutputStream fos=null;
        try{
            fos=new FileOutputStream("myIO\\fos.txt");
            fos.write("hello".getBytes());

        }catch (IOException io){
            io.printStackTrace();
        }finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        }
    }
}

3.6 字节流读数据(一次读一个字节数据)

字节输入流:

FileInputStream(String name)   :通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文件系统中的路径名name命名

字节输入流读取数据的步骤:
(1)创建字节输入流对象

(2)调用字节输入流对象的读数据方法

(3)释放资源

import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamDemo01 {
    public static void main(String[] args) throws IOException {

        //根据数据源创建输入流对象
        FileInputStream fis=new FileInputStream("myIo\\fos.txt");

        //读数据
        int bys;
        while ((bys=fis.read())!=-1) {
            /*这一步包含了:
            1.fis.read():读数据
            2.by=fis.read():把读取到的数据赋值给by
            3.by != -1:判断读取到的数据是否是-1*/
            System.out.print((char) bys);
        }
    }
}

3.7 字节流复制文本文件

/*案例需求
把“E:\itcast\窗里窗外.txt”复制到模块目录下的“窗里窗外.txt”
实现步骤
复制文本文件,其实就把文本文件的内容从一个文件中读取出来 (数据源),然后写入到另一个文件中(目的地)
数据源:
E:\itcast\窗里窗外.txt --- 读数据 --- InputStream --- FileInputStream
目的地:
myByteStream\窗里窗外.txt --- 写数据 --- OutputStream --- FileOutputStream*/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputDemo02 {
    public static void main(String[] args) throws IOException {
        //根据数据源创建输入流对象
        FileInputStream fis=new FileInputStream("D:\\itcast\\窗里窗外.txt");

        //根据目的地创建输出流对象
        FileOutputStream fos=new FileOutputStream("myIo\\窗里窗外.txt");

        //先读后写,(一次读取一个字节,一次写入一个字节)
        int by;
        if ((by=fis.read())!=-1) {
            fos.write(by);
        }

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

3.8 字节流读数据(一次读一个字节数组数据)

一次读一个字节数组的方法:

public int read(byte[] b) :从输入流读取最多b.length个字节的数据,返回的是读入缓冲区的总字节数 ,也就是实际的读取字节个数
示例:
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamDemo03 {
    public static void main(String[] args) throws IOException {
        //创建输入流对象
        FileInputStream fis=new FileInputStream("myIo\\fos.txt");

        //读数据
        /*
        hello
        world

        hello\r\n
        world\r\n

        第一次读取:hello
        第二次读取:\r\nwor
        第三次读取:ld\r\n   准备读取5个,但是只剩四个
        */

        //一次性读取一个字节数组的方法
        //public int read(byte[] b) 从该输入流读取最多 b.length个字节的数据到一个字节数组。

        //先定义一个动态字节数组
        byte[] byt = new byte[1024];  //一般为1024的整数倍

        int len;  //len就是实际的读取字节个数
        if ((len=fis.read(byt))!=-1){
        //将字节数组里面的内容转化为字符串内容
            System.out.println(new String(byt,0,len));
        }
    }
}

3.9 字节流复制图片

/*
案例需求:
把“E:\itcast\mn.jpg”复制到模块目录下的“mn.jpg”
实现步骤:
根据数据源创建字节输入流对象
根据目的地创建字节输出流对象
读写数据,复制图片 (一次读取一个字节数组,一次写入一个字节数组)
释放资源*/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputStreamDemo04 {
    public static void main(String[] args) throws IOException {
        //创建数据输入流对象
        FileInputStream fis = new FileInputStream("D:\\itcast\\mn.jpg");
        //创建数据输出流对象
        FileOutputStream fos = new FileOutputStream("myIo\\mn.jpg");

        //读一个写一个
        byte[] byt = new byte[1024];

        int len;  //实际读取到的字节内容
        while ((len=fis.read())!=-1){
            fos.write(len);
        }

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

4. IO流(字节缓冲流)

4.1 字节缓冲流

4.1.1 字节缓冲流构造方法

字节缓冲流介绍:

BufferedOutputStream :该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用

BufferedInputStream :创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法:

BufferedOutputStream(OutputStream out) 创建字节缓冲输出流对象
BufferedInputStream(InputStream in) 创建字节缓冲输入流对象
示例:
import java.io.*;

public class BufferedStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //创建字节缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myBufferedStreamDemo\\bos.txt"));

        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());

        //释放资源
        bos.close();


        //创建字节缓冲输出流对象
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("myBufferedStreamDemo\\bos.txt"));

        //读数据,一次只读一个字节
//        int by;
//        while ((by=bis.read())!=-1){
//            System.out.println((char)by);
//        }

        //读数据,一次读一个字节数组
        byte byt[]=new byte[1024];
        int len;
        while ((len=bis.read(byt))!=-1){
            System.out.println(new String(byt,0,len));
        }
        bis.close();
    }
}

4.2 字节流复制视频

/*案例需求(用四种方法实现,对比时间)
把“E:\itcast\字节流复制图片.avi”复制到模块目录下的“字节流复制图片.avi”
实现步骤
根据数据源创建字节输入流对象
根据目的地创建字节输出流对象
读写数据,复制视频
释放资源*/
import java.io.*;
public class CopyAvi {
    public static void main(String[] args) throws IOException {

        long startTime = System.currentTimeMillis();//开始时间

        //调用方法:
        //method01();   //共耗时:109744毫秒
        //method02();   //共耗时:207毫秒
        //method03();   //共耗时:429毫秒
        //method04();   //共耗时:73毫秒

        long endTime = System.currentTimeMillis();//结束时间

        System.out.println("共耗时:"+(endTime-startTime)+"毫秒");
    }

    //字节流(一次一个字节)
    public static void method01() throws IOException {
        FileInputStream fis = new FileInputStream("D:\\itcast\\字节流复制图片.avi");
        FileOutputStream fos=new FileOutputStream("myBufferedStreamDemo\\字节流复制图片.avi");

        //先读后写
        int by;
        while ((by=fis.read())!=-1){
            fos.write(by);
        }
        //释放资源
        fis.close();
        fos.close();
    }

    //字节流(一次一个数组)
    public static void method02() throws IOException {
        FileInputStream fis = new FileInputStream("D:\\itcast\\字节流复制图片.avi");
        FileOutputStream fos=new FileOutputStream("myBufferedStreamDemo\\字节流复制图片.avi");
        //先读后写
        byte[] byt = new byte[1024];
        int len;
        while ((len=fis.read(byt))!=-1){
            fos.write(byt,0,len);
        }
        //释放资源
        fis.close();
        fos.close();
    }

    //字节缓冲流(一次一个字节)
    public static void method03() throws IOException {
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\itcast\\字节流复制图片.avi"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("myBufferedStreamDemo\\字节流复制图片.avi"));

        //先读后写
        int by;
        while ((by=bis.read())!=-1){
            bos.write(by);
        }
        //释放资源
        bis.close();
        bos.close();
    }

    //字节缓冲流(一次一个数组)
    public static void method04() throws IOException {
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\itcast\\字节流复制图片.avi"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("myBufferedStreamDemo\\字节流复制图片.avi"));

        //先读后写
        byte[] byt = new byte[1024];
        int len;
        while ((len=bis.read(byt))!=-1){
            bos.write(byt,0,len);
        }
        //释放资源
        bis.close();
        bos.close();
    }
}

5. IO流(字符流)

5.1 为什么会出现字符流

字符流的介绍:

由于字节流操作中文不是特别的方便,所以Java就提供字符流

字符流 = 字节流 + 编码表(可以看出字符流的底层原理还是字节流)

中文的字节存储方式:

用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

5.2 编码表

什么是字符集:

是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。

常见的字符集:

(1)ASCII 字符集
ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、
换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)

基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

(2)GBXXX 字符集
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等

(3)Unicode 字符集:
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码

编码规则:
128个US-ASCII字符,只需一个字节编码

拉丁文等字符,需要二个字节编码

大部分常用字(含中文),使用三个字节编码

其他极少使用的Unicode辅助字符,使用四字节编码

5.3 字符串中的编码解码问题

相关方法:

byte[] getBytes() 使用平台的默认字符集将该 String编码为一系列字节
byte[] getBytes(String charsetName) 使用指定的字符集将该 String编码为一系列字节
String(byte[] bytes) 使用平台的默认字符集解码指定的字节数组来创建字符串
String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来创建字符串
示例:
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class ConversionStreamDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {

        //编码(默认字符集UTF-8)
        byte[] byt1 = "中国".getBytes();
        System.out.println(Arrays.toString(byt1));
        //编码(指定字符集----GBK)
        byte[] byt2 = "中国".getBytes("GBK");
        System.out.println(Arrays.toString(byt2));


        //解码(默认字符集UTF-8)
        String s = new String(byt1);
        System.out.println(s);
        //编码(指定字符集----GBK)
        System.out.println(new String(byt2,"GBK"));
    }
}

5.4 字符流中的编码解码问题(转换流)

字符流中和编码解码问题相关的两个类:

(1)InputStreamReader:是从字节流到字符流的桥梁

它读取字节,并使用指定的编码将其解码为字符

它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

(2)OutputStreamWriter:是从字符流到字节流的桥梁

它使用指定的编码将写入的字符编码转换为字节

它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

InputStreamReader(InputStream in)   使用默认字符编码创建InputStreamReader对象
InputStreamReader(InputStream in,Stringchatset)   使用指定的字符编码创建InputStreamReader对象
OutputStreamWriter(OutputStream out)   使用默认字符编码创建OutputStreamWriter对象
OutputStreamWriter(OutputStream out,Stringcharset)   使用指定的字符编码创建OutputStreamWriter对象
示例:
import java.io.*;

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建字符流对象(默认字符集)
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\java.txt"));
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\java.txt"));
        
        //创建字符流对象(指定字符集)
       OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\java.txt"),"GBK");
       InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\java.txt"),"GBK");
       
        //写数据
        osw.write("中国");

        //释放资源
        osw.close();

        //读数据(一次读一个字节)
        int ch;
       while ((ch= isr.read())!=-1){
           System.out.print((char)ch);   //把读出来的数据转化为字符显示在控制台
       }

        //释放资源
        isr.close();
    }
}

5.5 字符流写数据的5种方式

方法介绍:

void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组
void write(char[] cbuf, int off, int len) 写入字符数组的一部分
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分

刷新和关闭的方法:

flush()  刷新流,之后还可以继续写数据
close()  关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
示例:
import java.io.*;

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException{
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\java.txt"));
//     1.void write(int c) 写一个字符
//        osw.write(97);
//        osw.write(98);
//        osw.write(99);

//     2.void write(char[] cbuf) 写入一个字符数组
//        char chs[]={'a','b','c','d','e'};
//        osw.write(ch);
//        osw.close();

//        void write(char[] cbuf, int off, int len) 写入字符数组的一部分
//            char chs[]={'a','b','c','d','e'};
//            osw.write(chs,2,3);
//            osw.close();

//        void write(String str) 写一个字符串
//              osw.write("hello");
//              osw.close();
//        void write(String str, int off, int len) 写一个字符串的一部分
              osw.write("hello",2,3);
              osw.close();
    }
}

5.6 字符流读数据的2种方式

方法说明:

int read() 一次读一个字符数据
int read(char[] cbuf) 一次读一个字符数组数据
示例:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
//        int read() 一次读一个字符数据

//        int ch;
//        while ((ch= isr.read())!=-1){
//            System.out.print((char) ch);
//        }

//        int read(char[] cbuf) 一次读一个字符数组数据
        char chs[]=new char[1024] ;
        int len;
        while ((len= isr.read(chs))!=-1){
            System.out.println(new String(chs,0,len));
        }
        isr.close();
    }
}

5.7 字符流复制Java文件

/*案例需求:
把模块目录下的“ConversionStreamDemo.java” 复制到模块目录下的“Copy.java”
实现步骤:
根据数据源创建字符输入流对象
根据目的地创建字符输出流对象
读写数据,复制文件
释放资源*/
import java.io.*;
public class CopyDemo {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\Copy.java"));

//        先读后写
        char chs[]=new char[1024];
        int len;
        while ((len= isr.read(chs))!=-1){
            osw.write(chs,0,len);
            System.out.println(new String(chs,0,len));
        }

        //释放资源
        isr.close();
        osw.close();
    }
}

5.8 字符流复制Java文件(改进版)

/*字符流复制Java文件改进版
案例需求
使用便捷流对象,把模块目录下的“ConversionStreamDemo.java” 复制到模块目录下的“Copy.java”

实现步骤
根据数据源创建字符输入流对象
根据目的地创建字符输出流对象
读写数据,复制文件
释放资源*/

import java.io.*;

public class CopyDemo02 {
    public static void main(String[] args)throws IOException {
//      创建便捷输入输出流对象
        FileReader fr = new FileReader("myCharStream\\ConversionStreamDemo.java");
        FileWriter fw = new FileWriter("myCharStream\\Copy02.java");

//        先读后写
        char[] chs = new char[1024];

        int len;
        while((len= fr.read(chs))!=-1){
            fw.write(chs,0,len);
        }
//        释放资源
        fw.close();
        fr.close();
    }
}

5.9 字符缓冲流

字符缓冲流介绍

BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途

BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途

构造方法:

BufferedWriter(Writer out)     创建字符缓冲输出流对象
BufferedReader(Reader in)      创建字符缓冲输入流对象
示例:
import java.io.*;
public class BufferedStreamDemo01 {
    public static void main(String[] args) throws IOException {
//        创建字符缓冲输出流对象
        BufferedWriter bw=new BufferedWriter(new FileWriter("myCharBufferedStream\\java.txt"));
//        写数据
        bw.write("hello\r\n");
        bw.write("world\r\n");
//        释放资源
        bw.close();

//        创建字符缓冲输入流对象
        BufferedReader br=new BufferedReader(new FileReader("myCharBufferedStream\\java.txt"));
//        读数据
//        int cha;
//        while ((cha= br.read())!=-1){
//            System.out.println((char) cha);
//        }

        char chs[]=new char[1024];
        int len;
        while ((len= br.read(chs))!=-1){
            System.out.println(new String(chs,0,len));
        }
//        释放资源
        br.close();
    }
}

5.10 字符缓冲流复制Java文件

/*案例需求
把模块目录下的BufferedStreamDemo01.java 复制到模块目录下的 Copy.java

实现步骤
根据数据源创建字符缓冲输入流对象
根据目的地创建字符缓冲输出流对象
读写数据,复制文件,使用字符缓冲流特有功能实现
释放资源*/
import java.io.*;

public class CopyDemo {
    public static void main(String[] args) throws IOException {
//        1.创建字符缓冲流对象
        BufferedReader br=new BufferedReader(new FileReader("myCharBufferedStream\\BufferedStreamDemo01.java"));
        BufferedWriter bw=new BufferedWriter(new FileWriter("myCharBufferedStream\\Copy02.java"));

//        2.读一个数组写一个数组
        char chs[]=new char[1024];
        int len;
        while ((len= br.read(chs))!=-1){
            bw.write(chs,0,len);
        }
//         3.释放资源
        br.close();
        bw.close();
    }
}

5.11 字符缓冲流特有功能

方法介绍:

BufferedWriter:

void newLine()     写一行行分隔符,行分隔符字符串由系统属性定义,为了适应不同系统

BufferedReader:

String readLine()    读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
示例:
import java.io.*;
public class OnlyMethod {
    public static void main(String[] args) throws IOException {
        BufferedWriter bw=new BufferedWriter(new FileWriter("myCharBufferedStream\\xunhuan.txt"));
        //写数据
        for (int i=1;i<=10;i++) {
            bw.write("hello"+i);
            bw.write("\r\n");  //只是用与Windows
            //bw.newLine();
            bw.flush();
        }
        bw.close();

        BufferedReader br=new BufferedReader(new FileReader("myCharBufferedStream\\xunhuan.txt"));
        //读数据
        String line;
        while ((line= br.readLine())!=null){
            System.out.print(line);  //次数需要让输出显示在一行
        }
        br.close();
    }
}

5.12 字符缓冲流特有功能复制Java文件

/*案例需求
使用特有功能把模块目录下的BufferedStreamDemo01.java 复制到模块目录下的 Copy.java

实现步骤
根据数据源创建字符缓冲输入流对象
根据目的地创建字符缓冲输出流对象
读写数据,复制文件,使用字符缓冲流特有功能实现
释放资源*/
import java.io.*;

public class CopyDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new FileReader("myCharBufferedStream\\BufferedStreamDemo01.java"));
        BufferedWriter bw=new BufferedWriter(new FileWriter("myCharBufferedStream\\Copy.java"));

//        读一行写一行
        String line;
        while ((line= br.readLine())!=null){
            bw.write(line);
            bw.newLine();  //缓冲字符流不换行,所以必须用bw.newLine()
            bw.flush();
        }

//        释放资源
        br.close();
        bw.close();
    }
}

5.13 IO流小结

字节流:
在这里插入图片描述
字符流:
在这里插入图片描述

6. 练习案例

6.1 文件到集合

/*案例需求:
把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个集合元素

实现步骤:
创建字符缓冲输入流对象
创建ArrayList集合对象
调用字符缓冲输入流对象的方法读数据
把读取到的字符串数据存储到集合中
释放资源
遍历集合*/
import java.io.*;
import java.util.ArrayList;

public class Test01 {
    public static void main(String[] args) throws IOException {
        //创建缓冲输入流对象
        BufferedReader br=new BufferedReader(new FileReader("myStreamTest\\array.txt"));

        //创建集合对象
        ArrayList<String> arrayList=new ArrayList<>();

        //读取数据,把读取到的数据进行遍历,添加到ArrayList集合中
        String line;
        while((line= br.readLine())!=null){
            arrayList.add(line);
        }
        //释放资源
        br.close();

        //遍历集合输出在控制台
        for (String s:arrayList) {
            System.out.println(s);
        }
    }
}

6.2 集合到文件

/*案例需求:
把ArrayList集合中的字符串数据写入到文本文件。要求:每一个字符串元素作为文件中的一行数据

实现步骤:
创建ArrayList集合
往集合中存储字符串元素
创建字符缓冲输出流对象
遍历集合,得到每一个字符串数据
调用字符缓冲输出流对象的方法写数据
释放资源*/
import java.io.*;
import java.util.ArrayList;

public class Test02 {
    public static void main(String[] args) throws IOException {
        //创建集合对象并添加
        ArrayList<String> arrayList=new ArrayList<>();
        arrayList.add("hello");
        arrayList.add("world");
        arrayList.add("javaSE");
        arrayList.add("100");

        //创建字符输出流对象
        BufferedWriter bw=new BufferedWriter(new FileWriter("myStreamTest\\array02.txt"));

        //遍历 ArrayList集合,把每个元素写入文件中
        for (String s:arrayList) {
            bw.write(s);
            bw.newLine();
        }
        //释放资源
        bw.close();
    }
}

6.3 点名器

/*案例需求:
        我有一个文件里面存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随点名器

        实现步骤:
        创建字符缓冲输入流对象
        创建ArrayList集合对象
        调用字符缓冲输入流对象的方法读数据
        把读取到的字符串数据存储到集合中
        释放资源
        使用Random产生一个随机数,随机数的范围在:[0,集合的长度)
        把第6步产生的随机数作为索引到ArrayList集合中获取值
        把第7步得到的数据输出在控制台*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class CallNameDemo {
    public static void main(String[] args) throws IOException {
        //创建输入流缓冲对象
        BufferedReader br=new BufferedReader(new FileReader("myStreamTest\\callName.txt"));

        //创建ArrayList集合
        ArrayList<String> arrayList=new ArrayList<>();

        //读取数据,保存到集合中
        String line;
        while ((line= br.readLine())!=null){
            //把读取到的字符串数据存储到集合中
            arrayList.add(line);
        }
        //释放资源
        br.close();

        //创建随机数
        Random sc=new Random();
        int r=sc.nextInt(12);

        //用随机数对象作为索引,去找对应的值
        String name = arrayList.get(r);
        System.out.println("被点到的幸运儿是:"+name);
    }
}

6.4 集合到文件(改进版)

学生类:
public class Student {
    private int sid;
    private String name;
    private int age;
    private String address;

    public Student() {
    }

    public Student(int sid, String name, int age, String address) {
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public int getSid() {
        return sid;
    }

    public void setSid(int sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
/*案例需求:
把ArrayList集合中的学生数据写入到文本文件。要求:每一个学生对象的数据作为文件中的一行数据

格式:学号,姓名,年龄,居住地
举例:itheima001,林青霞,30,西安

实现步骤:
定义学生类
创建ArrayList集合
创建学生对象
把学生对象添加到集合中
创建字符缓冲输出流对象
遍历集合,得到每一个学生对象
把学生对象的数据拼接成指定格式的字符串
调用字符缓冲输出流对象的方法写数据
释放资源*/
import java.io.*;
import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) throws IOException {
        //创建Arraylist对象
        ArrayList<Student> arrayList=new ArrayList<>();

        //创建Student对象
        Student s1=new Student(001,"郭靖",25,"桃花岛");
        Student s2=new Student(002,"黄蓉",20,"桃花岛");
        Student s3=new Student(003,"杨过",16,"古墓");
        Student s4=new Student(004,"小龙女",18,"古墓");

        //给集合中添加数据
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        arrayList.add(s4);

        //创建输出流缓冲对象
        BufferedWriter bw=new BufferedWriter(new FileWriter("myStreamTest\\Demo.txt"));

        //遍历集合,把每个元素写进文件里
        for (Student s:arrayList) {
            StringBuilder sb=new StringBuilder();
            StringBuilder sb2 = sb.append(s.getSid()).append(",").append(s.getName()).append(",").append(s.getAge()).append(",").append(s.getAddress());

            bw.write(sb2.toString());
            bw.newLine();
            bw.flush();
        }
        //释放资源
        bw.close();
    }
}

6.4 文件到集合(改进版)

Student类同上
/*案例需求:
把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个学生对象的成员变量值
举例:itheima001,林青霞,30,西安

实现步骤:
定义学生类
创建字符缓冲输入流对象
创建ArrayList集合对象
调用字符缓冲输入流对象的方法读数据
把读取到的字符串数据用split()进行分割,得到一个字符串数组
创建学生对象
把字符串数组中的每一个元素取出来对应的赋值给学生对象的成员变量值
把学生对象添加到集合
释放资源
遍历集合*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) throws IOException {

//        创建字符缓冲输入流
        BufferedReader br=new BufferedReader(new FileReader("myStreamTest\\Demo.txt"));

//        创建ArrayList集合
        ArrayList<Student> arrayList=new ArrayList<>();

        //读取数据,放入集合中
        String line;
        while ((line= br.readLine())!=null){
            //把读取到的字符串数据用split()进行分割,得到一个字符串数组
            String[] strArr = line.split(",");

                //创建学生对象
                Student s=new Student();
                //把字符串数组中的每一个元素取出来对应的赋值给学生对象的成员变量值
                s.setSid(Integer.parseInt(strArr[0])); //此处要把基本类变成包装类
                s.setName(strArr[1]);
                s.setAge(Integer.parseInt(strArr[2]));//此处要把基本类变成包装类
                s.setAddress(strArr[3]);

//                把学生对象添加进集合
                arrayList.add(s);
            }
                //释放资源
                br.close();

        //遍历,展示在控制台
        for (Student arr:arrayList) {
            System.out.println(arr.getSid()+","+arr.getName()+","+arr.getAge()+","+arr.getAddress());
        }
    }
}

6.5 集合到文件数据排序改进版

学生类:
public class Student {
    private String name;
    private int chinese;
    private int math;
    private int english;

    public Student() {
    }

    public Student(String name, int chinese, int math, int english) {
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getChinese() {
        return chinese;
    }

    public void setChinese(int chinese) {
        this.chinese = chinese;
    }

    public int getMath() {
        return math;
    }

    public void setMath(int math) {
        this.math = math;
    }

    public int getEnglish() {
        return english;
    }

    public void setEnglish(int english) {
        this.english = english;
    }

    public int sum() {
        return this.chinese+this.math+this.english;
    }
}
/*案例需求
        键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)。要求按照成绩总分从高到低写入文本文件
        格式:姓名,语文成绩,数学成绩,英语成绩 举例:林青霞,98,99,100

        分析步骤
        1. 定义学生类
        2. 创建TreeSet集合,通过比较器排序进行排序
        3. 键盘录入学生数据
        4. 创建学生对象,把键盘录入的数据对应赋值给学生对象的成员变量
        5. 把学生对象添加到TreeSet集合
        6. 创建字符缓冲输出流对象
        7. 遍历集合,得到每一个学生对象
        8. 把学生对象的数据拼接成指定格式的字符串
        9. 调用字符缓冲输出流对象的方法写数据
        10. 释放资源*/
import java.io.*;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

public class Demo {
    public static void main(String[] args) throws IOException {
        //创建TreeSet集合对象
        TreeSet<Student> ts=new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.sum() - s1.sum();
                int num2 = num == 0 ? s2.getChinese() - s1.getChinese():num;
                int num3 = num2 == 0 ? s2.getMath() - s1.getMath():num2;
                int num4 = num3 == 0 ? s2.getName().compareTo(s1.getName()):num3;

                return num4;
            }
        });

        for (int i = 0; i < 5; i++) {
            //创建学生对象
            Student s=new Student();
            //键盘录入学生信息
            Scanner sc=new Scanner(System.in);
            System.out.println("请输入第"+(i+1)+"位学生的姓名");
            String name=sc.nextLine();
            System.out.println("请输入语文成绩");
            int chinese=sc.nextInt();
            System.out.println("请输入数学成绩");
            int math=sc.nextInt();
            System.out.println("请输入英语成绩");
            int english=sc.nextInt();

            //把录入信息添加到学生对象
            s.setName(name);
            s.setChinese(chinese);
            s.setMath(math);
            s.setEnglish(english);

            //把学生对象添加到集合
            ts.add(s);
        }
        //调用方法
        copyToFile(ts);
    }
       public static   void copyToFile(TreeSet<Student> ts) throws IOException{
        //        创建字符缓冲输入流对象
        BufferedWriter bw=new BufferedWriter(new FileWriter("myCharStream\\Student.txt"));
        //遍历集合得到每一个元素,写入文件,按指定格式进行拼接
        for (Student s:ts) {
            StringBuilder sb=new StringBuilder();
            sb.append(s.getName()).append(",").append(s.getChinese()).append(",")
                    .append(s.getMath()).append(",").append(s.getChinese()).append(",").append(s.sum());
            bw.write(sb.toString());
            bw.newLine();
            bw.flush();
        }
        bw.close();
    }
}

6.5 复制单级文件夹

/*案例需求
        把“D:\itcastONE”这个文件夹复制到模块目录下

        分析步骤
        1.创建数据源目录File对象,路径是D:\itcastONE
        2. 获取数据源目录File对象的名称
        3. 创建目的地目录File对象,路径由(模块名+第2步获取的名称)组成
        4. 判断第3步创建的File是否存在,如果不存在,就创建
        5. 获取数据源目录下所有文件的File数组
        6. 遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件
        7. 获取数据源文件File对象的名称
        8. 创建目的地文件File对象,路径由(目的地目录+第7步获取的名称)组成
        9. 复制文件
        由于不清楚数据源目录下的文件都是什么类型的,所以采用字节流复制文件
        采用参数为File的构造方法*/
import java.io.*;
public class CopyOneFolderDemo {
    public static void main(String[] args) throws IOException {
        //创建数据源目录对象
        File souFolder=new File("D:\\itcastONE");
        //获取数据源目录名
        String souFolderName = souFolder.getName();
        //创建目的地目录对象,把获取的数据源目录名,添加到目的地里
        File desFolder=new File("myCharStream",souFolderName);

        //判断目的地itcastONE目录是否存在,不存在就创建
        if (!desFolder.exists()) {
            desFolder.mkdir();
        }
        //获取数据源目录下的所有文件的File数组
        File[] listFiles = souFolder.listFiles();//此方法得到的是File对象的绝对路径,而且 File[]类型的对象,还可以调用getName方法
        //遍历得到的File数组中的每个File对象,就是数据源中的文件
        for (File souFile :listFiles) { //遍历得到的list是File类型的对象,因此可以调用getName方法
            //调用getName方法,得到每一个数据源的文件名
            String souFileName = souFile.getName();

            //创建目的地文件File对象,目录名是desFileFolder,文件名是souFileName
            File desFile = new File(desFolder,souFileName);

            //调用 复制文件的方法
            copyFiles(souFile,desFile); //里面创建的对象,在for循环外面是不能使用的
        }
    }

    private static void copyFiles(File souFile, File desFile) throws IOException{
        //创建字节缓冲流对象
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream(souFile));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(desFile));

        //先读后写,一次读一个字节数组
        byte byt[]=new byte[1024];
        int len;
        while ((len= bis.read(byt))!=-1){
           bos.write(byt,0,len);
        }
        //释放资源
        bos.close();
        bis.close();
    }
}

6.6 复制多级文件夹

/*案例需求
把"D:\\itcastMORE"这个文件夹复制到 当前模块"myCharStream\\"目录下

分析步骤
1. 创建数据源File对象,路径是D:\\itcastMORE
2. 创建目的地File对象,路径是  myCharStream\\
3. 写方法实现文件夹的复制,参数为数据源File对象和目的地File对象
4. 判断数据源File是否是文件
是文件:直接复制,用字节流
不是文件:
在目的地下创建该目录
遍历获取该目录下的所有文件的File数组,得到每一个File对象
回到3继续(递归)*/

import java.io.*;

public class CopyMoreFolderDemo {
    public static void main(String[] args) throws IOException {
        //创建 数据源  File对象
        File souFile = new File("D:\\itcastMORE");

        //创建 目的地  File对象
        File desFile = new File("myCharStream\\");

        //调用复制目录的方法
        copyFolder(souFile,desFile);
    }
    //复制目录
    private static void copyFolder(File souFile, File desFile) throws IOException{
        //先判断数据源 File对象是不是文件夹
        if (souFile.isDirectory()) {
            //在目的地下创建和数据源File名称一样的目录
            String souFileName = souFile.getName();
            File newFolder = new File(desFile, souFile.getName());//  "myCharStream\\itcastMORE"

            //判断 新目的地newFolder   itcastMORE目录是否存在,不存在就创建
            if (!newFolder.exists()) {
                newFolder.mkdir();
            }

            //获取数据源File下所有文件或者目录的File数组
            File[] fileArray = souFile.listFiles();
            //遍历File[]数组,得到每一个File对象
            for (File list:fileArray) {
                //把该File作为数据源File对象,递归调用复制文件夹的方法
                copyFolder(list,newFolder);
            }
        }else{
            //如果不是目录那就是文件,创建 目的地  文件  File对象
            File newFile = new File(desFile,souFile.getName());
            copyFile(souFile,newFile);
        }

    }

    private static void copyFile(File souFile, File newFile) throws IOException{
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream(souFile));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(newFile));
//        先读后写,一次读取一个数组的字节
        byte byt[]=new byte[1024];
        int len;
        while ((len= bis.read(byt))!=-1){
            bos.write(byt,0,len);
        }
//        释放资源
        bis.close();
        bos.close();
    }
}

6.7 复制文件的异常处理

推荐使用JDK7改进方法


import java.io.*;

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

    }
    
    //4.JDK9改进(需要抛出异常)
    /*
    public static void method03() throws IOException{
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("fr.txt"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("fw.txt"));
        try(bis;bos) {
            byte byt[]=new byte[1024];
            int len;
            while ((len= bis.read(byt))!=-1){
                bos.write(byt,0,len);
            }
            bis.close();
            bos.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
*/


    //3.JDK7改进(推荐使用,操作简单,不用抛出异常)
    public static void method03() {
        try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream("fr.txt"));
            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("fw.txt"));) {
            byte byt[]=new byte[1024];
            int len;
            while ((len= bis.read(byt))!=-1){
                bos.write(byt,0,len);
            }
            bis.close();
            bos.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    


    //2.try...catch...finally方法
    /*
    public static void method02() {
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;
        try {
            bis=new BufferedInputStream(new FileInputStream("fr.txt"));
            bos=new BufferedOutputStream(new FileOutputStream("fw.txt"));

            byte byt[]=new byte[1024];
            int len;
            while ((len= bis.read(byt))!=-1){
                bos.write(byt,0,len);
            }

        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if (bos == null) {

                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bis == null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    */

    //1.把异常都抛出去
    /*
    public static void method01() throws IOException {
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("fr.txt"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("fw.txt"));

        byte byt[]=new byte[1024];
        int len;
        while ((len= bis.read(byt))!=-1){
            bos.write(byt,0,len);
        }
        bis.close();
        bos.close();
    }
    */
}

7. IO特殊操作流

7.1 标准输入流

System类中有两个静态的成员变量

public static final InputStream in:  标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
public static final PrintStream out:    标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
示例:
import java.io.*;
import java.util.Scanner;
//标准输出流
public class InDemo {
    public static void main(String[] args) throws IOException {
//public static final InputStream in:  标准输入流。通常该流  对应于  键盘输入  或由主机环境或用户指定的另一个输入源
        InputStream is = System.in;  //以多态的形式完成了 is 对象的初始化


        //is的类型为InputStream,可以调输入流的方法
        //一次读一个字节
        /*
        int by;
        while ((by= is.read())!=-1){
            System.out.print((char) by);
        }

        //当输入 汉字时,读取不出来,应为此处使用的是字节输入流
        //所以要把字节输入流转换为 字符输入流------转换流
        InputStreamReader isr=new InputStreamReader(is);  //括号里面填入一个 字节输入流对象

        //为了用到每次读取一行的操作,我们还得创建字符缓冲流对象,为了调用它的方法
        BufferedReader br=new BufferedReader(isr);
        */

        //改进步骤
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in) );

        System.out.println("请输入一个字符串");
        String line = br.readLine();
        System.out.println("你输入的字符串是:"+line);

        System.out.println("请输入一个整数");
        int line2 = Integer.parseInt(br.readLine());
        System.out.println("你输入的整数是:"+line2);

        //自己实现键盘录入信息太繁琐,所要不断的转换数据类型,因此JAVA提供了一个包装类供我们使用
        Scanner sc=new Scanner(System.in);  //可以看出其底层还是包装了System.in

    }
}

7.2 标准输出流

/*输出语句的本质:是一个标准的输出流
        PrintStream ps = System.out;
        PrintStream类有的方法,System.out都可以使用*/
import java.io.PrintStream;
public class OutDemo {
    public static void main(String[] args) {
   //public static final PrintStream out:    标准输出流。通常该流对应于  显示输出  或由主机环境或用户指定的另一个输出目标
        PrintStream ps = System.out;  //OutputStream 是PrintStream的基类,所以可以调用OutputStream的一切方法
        //PrintStream是打印流,它有两个特有方法print和println,区别在于println自带换行功能
        ps.print("hello");
        ps.print("world");

        ps.println("hello");
        ps.println("world");

        //改进:
        System.out.println("hello");
        System.out.println("world");
    }
}

7.3 字节打印流

打印流分类:
字节打印流:PrintStream

字符打印流:PrintWriter

打印流的特点:
只负责输出数据,不负责读取数据

永远不会抛出IOException

有自己的特有方法

字节打印流:

PrintStream(String fileName):使用指定的文件名创建新的打印流
使用继承父类的方法写数据,查看的时候会转码;

使用自己的特有方法写数据,查看的数据原样输出

可以改变输出语句的目的地
public static void setOut(PrintStream out):  重新分配“标准”输出流
示例:
import java.io.IOException;
import java.io.PrintStream;

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
//        创建字节打印流对象
        PrintStream ps=new PrintStream("myOtherStream\\java.txt");        //参数可以是File也可以是String

        //写数据
        
        //1.继承父类OutPutStream的write方法写数据 (三种方法:1.一个字节、2.一个字节数组、3.一个字节数组的一部分)
        ps.write(97);  //----输出时会进行转码

        //2.特有方法
//        ps.print(97);       //----输出时不转码
//        ps.print(98);
//        ps.print(99);

        ps.println("hello");    //---自动换行
        ps.println("world");

//        释放资源
        ps.close();
    }
}

7.4 字符打印流

PrintWriter(String fileName) 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区
示例:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriteDemo {
    public static void main(String[] args) throws IOException {
       /*
        1.//PrintWriter(String fileName) 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新

        PrintWriter pw=new PrintWriter("myOtherStream\\java.txt");
        //写数据

        //继承父类Write的方法(五种方法)
        pw.write("hello");  //三部:写数据,加空行,刷新
        pw.write("\r\n");
        pw.flush();
        
        pw.write("world");
        pw.write("\r\n");
        pw.flush();

        //释放资源
        pw.close();
        */

        //2.PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter out:字符输出流 autoFlush:
        //一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区

        PrintWriter pw=new PrintWriter(new FileWriter("myOtherStream\\java.txt"));
        pw.println("hello");
        /*
        包含了:
        pw.write("hello");  //三部:写数据,加空行,刷新
        pw.write("\r\n");
        pw.flush();
        */
        pw.println("world");

        pw.close();
    }
}

7.5 复制Java文件打印流改进版

/*案例需求:
        把模块目录下的PrintStreamDemo.java 复制到模块目录下的Copy.java

        分析步骤:
        根据数据源创建字符输入流对象
        根据目的地创建字符输出流对象
        读写数据,复制文件
        释放资源*/
import java.io.*;
public class CopyDemo {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符缓冲输入流对象
        BufferedReader br=new BufferedReader(new FileReader("myOtherStream\\src\\com\\itheima_02\\PrintStreamDemo.java"));
        //根据 目的地 创建字符打印流对象
        PrintWriter pw=new PrintWriter(new FileWriter("myOtherStream\\Copy.java"),true);

//       先读后打印  一次读一行
        String line;
        while ((line= br.readLine())!=null){
            pw.println(line);
        }

        //释放资源
        pw.close();
        br.close();
    }
}

7.6 对象序列化流

对象序列化介绍:

对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象

这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息

字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

对象序列化流: ObjectOutputStream

将Java对象的原始数据类型和图形写入OutputStream。
可以使用ObjectInputStream读取(重构)对象。

可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象

构造方法:

ObjectOutputStream(OutputStream out)  创建一个写入指定的OutputStream的ObjectOutputStream

序列化对象的方法:

void writeObject(Object obj)   将指定的对象写入ObjectOutputStream

注意事项:
一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口

Serializable是一个标记接口,实现该接口,不需要重写任何方法

示例:
学生类:实现Serializable
import java.io.Serializable;
public class Student implements Serializable {//Serializable是一个标记接口,实现该接口,不需要重写任何方法
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {

        //创建对象序列化流
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));

        //创建学生对象
        Student s=new Student("令狐冲",20);
        //写数据
        oos.writeObject(s);     //NotSerializableException
        //一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口

        //释放资源
        oos.close();
    }
}

7.7 对象反序列化流

对象反序列化流: ObjectInputStream

ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象

构造方法:

ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream

反序列化对象的方法:

Object readObject()       从ObjectInputStream读取一个对象
示例:
import com.itheima_03.Student;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //创建反序列化流
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));

        //读数据
        Object obj = ois.readObject();

        Student s=(Student)obj;     //向下转型

        System.out.println(s.getName()+","+s.getAge());
        //释放资源
        ois.close();
    }
}

7.8 serialVersionUID&transient

serialVersionUID:

用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?

会出问题,会抛出InvalidClassException异常

如果出问题了,如何解决呢?

重新序列化
给对象所属的类加一个serialVersionUID
private static final long serialVersionUID = 42L;

transient:
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?

示例:
学生类:
import java.io.Serializable;
public class Student implements Serializable {

    //1.InvalidClassException异常怎样解决?
    private static final long serialVersionUID = 42L;

    //2.如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?

    private transient int age;  //给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
    //private int age;
    private String name;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.io.*;

public class ObjectIOStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
		//调用方法
        write();
        read();
//        InvalidClassException: com.itheima_05.Student;
//        local class incompatible:
//        stream classdesc serialVersionUID = -3516324088175766826,     //流的序列ID
//                local class serialVersionUID = 6821873905940546941  //类的序列ID
    }
    //序列化:
    private static void read() throws IOException, ClassNotFoundException {
        //创建反序列化流对象
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
        Object obj = ois.readObject();
        //向下转型
        Student s=(Student)obj;
        System.out.println(s.getName()+","+s.getAge());
    }

    //反序列化:
    private static void write() throws IOException{
        //创建序列化对象流
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
        //创建学生对象
        Student s=new Student("全智贤",27);
        //写数据
        oos.writeObject(s);
        oos.close();
    }
}

8. Properties集合

8.1 Properties作为Map集合的使用

Properties介绍:
是一个Map体系的集合类

Properties可以保存到流中或从流中加载

属性列表中的每个键及其对应的值都是一个字符串

示例:
import java.util.Properties;
import java.util.Set;

public class PropertiesDemo {
    public static void main(String[] args) {
        //Properties的Map集合用法

        Properties pro=new Properties();
        //调用Map集合的方法

        //1.添加键值元素
        pro.put("第一名","独孤求败");
        pro.put("第二名","王重阳");
        pro.put("第三名","扫地僧");

        //2.获取键的集合
        Set<Object> keySet = pro.keySet();
        for (Object key:keySet) {
            Object value = pro.get(key);
            System.out.println(key+","+value);
        }
    }
}

8.2 Properties作为Map集合的特有方法

特有方法:

Object setProperty(String key,String value)      设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
String getProperty(String key)    使用此属性列表中指定的键搜索属性
Set stringPropertyNames()   从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
示例:
import java.util.Properties;
import java.util.Set;

public class PropertiesDemo02 {
    public static void main(String[] args) {
        Properties pro=new Properties();

        //Properties的特有方法

        //1.添加键值元素
        pro.setProperty("第一名","小龙女");
        pro.setProperty("第二名","王语嫣");
        pro.setProperty("第三名","周芷若");

        //2.获取键的集合
        Set<String> keyList = pro.stringPropertyNames();
        for (String key:keyList) {
            String value = pro.getProperty(key);
            System.out.println(key+","+value);
        }
    }
}

8.3 Properties和IO流相结合的方法

void load(InputStream inStream)   从输入字节流读取属性列表(键和元素对)
void load(Reader reader)   从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)   将此属性列表(键和元素对)写入此 Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments)  将此属性列表(键和元素对)写入此 Properties表中,以适合使用load(Reader)方法的格式写入输出字符流
示例:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDemo03 {
    public static void main(String[] args) throws IOException{
        //storeMethod();
        loadMethod();
    }

    
    //2.文件加载到集合
    private static void loadMethod() throws IOException{
        Properties pro=new Properties();
        FileReader fr=new FileReader("myOtherStream\\Properties.txt");

        pro.load(fr);

        System.out.println(pro);  //测试
    }
    
    //1.集合保存到文件
    private static void storeMethod() throws IOException {
        Properties pro=new Properties();

        FileWriter fw=new FileWriter("myOtherStream\\Properties.txt");

        pro.setProperty("001","小龙女");
        pro.setProperty("002","赵敏");
        pro.setProperty("003","周芷若");

        pro.store(fw,null);//没有备注信息就填null

        fw.close();
    }
}

8.4 游戏次数案例

游戏:
import java.util.Random;
import java.util.Scanner;
public class GameRule {
    public static void play() {
        Random r = new Random();
        int sys = r.nextInt(100)+1;  //范围:1-100
        for (;;) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入你猜的数字");
            int men = sc.nextInt();

            if (sys > men) {
                System.out.println("你猜的数小了");
            } else if (sys <men) {
                System.out.println("你猜的数大了");
            } else{
                System.out.println("恭喜猜对了");
                break;
            }
        }
    }
}
/*案例需求:
        实现猜数字小游戏只能试玩3次,如果还想玩,提示:游戏试玩已结束,想玩请充值(www.itcast.cn)

        分析步骤:
        1. 写一个游戏类,里面有一个猜数字的小游戏
        2. 写一个测试类,测试类中有main()方法,main()方法中写如下代码:
        从文件中读取数据到Properties集合,用load()方法实现
        文件已经存在:game.txt
        里面有一个数据值:count=0
        通过Properties集合获取到玩游戏的次数
        判断次数是否到到3次了
        如果到了,给出提示:游戏试玩已结束,想玩请充值(www.itcast.cn)
        如果不到3次:
        次数+1,重新写回文件,用Properties的store()方法实现玩游戏*/
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class Demo {
    public static void main(String[] args) throws IOException {
        GameRule.play();

//        创建Properties集合
        Properties prop=new Properties();
//        创建字符输出流对象
        FileReader fr=new FileReader("myOtherStream\\game.txt");

        prop.load(fr);
        fr.close();

        //通过Properties集合获取到玩游戏的次数
        String count = prop.getProperty("count");
        //String转为int
        int number = Integer.parseInt(count);

        //判断玩游戏的次数
        if (number>=3) {
            System.out.println("提示:游戏试玩已结束,想玩请充值(www.itcast.cn)");
        }else {
            //次数+1,重新写回文件,用Properties的store()方法实现
            GameRule.play();
            //次数+1
            number++;
            //重新写回文件
            prop.setProperty("count",String.valueOf(number));
            FileWriter fw=new FileWriter("myOtherStream\\game.txt");
            prop.store(fw,null);
            fw.close();
        }
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值