Java基础学习(六)-- 递归以及文件I/O流基础详解

时间:2021-08-20 11:43:51

递归

1、递归的概念: 在函数自身内部,调用函数本身的方式,称为递归。

2、递归的注意事项:包括递进去,归出来两步。
   即:首先依次执行【函数调自身语句】上半部分的代码,知道最里层。(递进去),然后 ,再从最里层开始,依此执行【函数调自身语句】下半部分代码。(归出去)

3、递归必须通过合适的语句及时的跳出,否则容易造成死循环。

Java基础学习(六)-- 递归以及文件I/O流基础详解

使用递归计算阶乘:

 1 public class Demo01_digui {
 2 
 3     public static void main(String[] args) {
 4 
 5         Scanner in = new Scanner(System.in);
 6         System.out.print("请输入一个数:");
 7         int i = in.nextInt();
 8         System.out.println(jiecheng(i));
 9         ;
10 
11     }
12 
13     public static long result = 1;
14 
15     public static long jiecheng(int num) {
16         result *= num;
17         num -= 1;
18         if (num > 0) {
19             jiecheng(num);
20         }
21         return result;
22     }
23 
24 }

File--文件

1.File的基本概念:Java文件类以抽象的方式代表文件名和目录路径。File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象。

2.作用:主要用于文件和目录的创建、文件的查找和文件的删除等

3.文件的分割(写法):可以使用"/"(通常用于Linux系统,widows也使用),"\\"(通常用于widows),注意一个"\"需要转义。

4.构造函数:

1     //1.直接传入一个路径,拿到一个文件或者一个文件夹
2     File file1 = new File("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\tes.txt");
3     //2.第一个参数传入父路径,第二个参数传入子路径或者文件
4     File file2 = new File("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14", "tes.txt");
5     //3.第一个参数传入file对象,第二个参数传入子路径或者文件
6     File file3 = new File(file1, "tes.txt");

5.创建File对象成功后,可以使用以下列表中的方法操作文件。

(1)file.canRead():判断文件是否可读.返回true/false
(2)file.canWrite():判断文件是否可写.返回true/false
(3)file.equals():判断两个文件是否相等
(4)file.exists():检测文件是否存在
(5)file.getAbsolutePath():获取文件的绝对路径。
(6)file.getName():取到一个文件名或者文件夹名
(7)file.getPath():取到当前文件或者文件夹的父路径
(8)file.isAbsolute():判断当前文件是否是绝对路径
(9)file.isDirectory():检测当前文件是否是个目录(文件夹)。
(10)file.isFile():检测当前路径是否是文件。
(11)file.delete():删除文件。返回true/false(文件夹中包含内容的时候不可以删除)
(12)file.android():创建新的文件。返回true/false
(13)file.mkdir():创建新的一层路径(文件夹),只有当文件夹不存在时才能创建成功。如果file中有一层不存在就没法往下创建。
(14)file.mkdirs():创建多层路径。只要有没有的就可以创建。
(15)file.getTotalSpace():获得文件分区的总大小。
(16)file.getUsableSpace():获得文件分区的可用大小。
(17)file.lenght():返回当前文件或文件夹的大小。
(18)file.list():返回当前目录中的文件和文件夹的名字,返回值类型为String类型的数组。
(19)file.list(FilenameFilter filenameFilter):它传入的是个接口重写accept()方法,返回true显示所有,返回false全不显示。
(20)file.listFiles():返回当前目录中的文件和文件夹的目录,返回值类型是File类型的数组。同样可以对其进行过滤:FilenameFilter 和FileFilter两种过滤方法。
(21)file.renameTo(file2):重命名一个文件,要求传入一个心的.

练习:删除磁盘规定文件目录下的文件夹及其所有文件

public class Demo02_File {

    public static void main(String[] args) {

        File file = new File("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test");

        search(file);
        
    }
    
    //删除文件夹及其所有的文件
    public static void search(File file) {
    
        if(file.isFile()){
            file.delete();
        }else if(file.isDirectory()){
            
            File[] f = file.listFiles();
            
            for (File file2 : f) {
                search(file2);
            }
            file.delete();
        }
    }
    
}

I/O流

I/O流概述

1.概念:IO流简单来说就是Input和Output流,IO流主要是用来处理设备之间的数据传输,Java对于数据的操作都是通过流实现,而java用于操作流的对象都在IO包中。

2.分类:

根据流的方向:输入流和输出流。
根据读取文件的大小:字节流和字符流。
根据读取的方式:结点流和缓存流。

3.输入流和输出流:

所有输入流类都是抽象类InputStream(字节输入流),或者抽象类Reader(字符输入流)的子类;
所有输出流都是抽象类OutputStream(字节输出流),或者抽象类Writer(字符输出流)的子类。
字节流按字节读取,只能读取字符,读取中文会乱码。字符流读取中文。

Java基础学习(六)-- 递归以及文件I/O流基础详解

基本流--FileInputStream/FileOutputStream

FileInputStream的单个字节读取:FileInputStream in = new FileInputStream("text.txt");
FileOutputStream的单个字节写入:FileOutputStream out = new FileOutputStream("text2.txt"));
int a=fis.read();//read()一次读取一个字节
fos.write(101);//write()一次写一个字节

写法:

1.使用整形,对文件中的字节一个一个的读取

 1     public static void main(String[] args) {
 2         
 3         try {
 4             //字节流读取
 5             FileInputStream in = new FileInputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test\\test.txt");
 6             int n = -1;
 7             StringBuffer sb = new StringBuffer();
 8             while ((n = in.read())!=-1) {
 9                 sb.append((char)n);
10             }
11             System.out.println(sb);
12 
13         } catch (Exception e) {
14             // TODO Auto-generated catch block
15             e.printStackTrace();
16         }
17         
18     }

2.使用byte数组直接声明为输入流的长度,一次性读出所有文字

 

        public static void main(String[] args) {
        
        try {
            //字节流读取
            FileInputStream in = new FileInputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test\\test.txt");
        
            //使用byte数组直接声明为输入流的长度,一次性读出所有文字
            byte[] bytes = new byte[1024];
            in.read(bytes);
            StringBuffer sb = new StringBuffer();
            sb.append(new String(bytes));
            System.out.println(sb);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        

 

练习:1.读取文件中的文字然后倒序写入新文件

    public static void main(String[] args) {
        
        try {
            //字节流读取
            FileInputStream in = new FileInputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test\\test.txt");
            //FileOutputStream()后面加true指文件后面可追加,而不是从文件开头写入。(可以省略不写,不写默认false)
            FileOutputStream out = new FileOutputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test\\out.txt");
            int n = -1;
            StringBuffer sb = new StringBuffer();
            while ((n = in.read())!=-1) {
                sb.append((char)n);
            }
            sb.reverse();
            out.write(sb.toString().getBytes());//将字符串转换成byte数组,并写入文件
            
            in.close();
            out.close();
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }

 

 

2.复制一个文件夹中所有的文件(不包含文件夹)

 1     public class Test02_CopyFiles {
 2 
 3         public static void main(String[] args) {
 4             /**
 5              * 将一个文件夹中的所有文件,全部复制到一个新的文件夹。
 6              */
 7             File oldDir = new File("F:/test");
 8             File newDir = new File("F:/test2");
 9             try {
10                 copyDir(oldDir, newDir);
11             } catch (IOException e) {
12                 e.printStackTrace();
13             }
14         }
15         
16         public static void copyDir(File oldDir,File newDir) throws IOException{
17             if(!oldDir.exists() || !oldDir.isDirectory()){
18                 System.out.println("原路径不存在或不是目录!");
19                 return;
20             }
21             if(!newDir.exists() || !newDir.isDirectory()){
22                 System.out.println("新路径不存在或不是目录!");
23                 return;
24             }
25             if(oldDir.equals(newDir)){
26                 System.out.println("两个路径相同,无法复制!");
27                 return;
28             }
29             File[] files = oldDir.listFiles(new FileFilter() {
30                 @Override
31                 public boolean accept(File pathname) {
32                     if(pathname.isFile()){
33                         return true;
34                     }
35                     return false;
36                 }
37             });
38             
39             FileInputStream fis = null;
40             FileOutputStream fos = null;
41             
42             for (File file : files) {
43                 fis = new FileInputStream(file);
44                 String newPath = newDir.getAbsolutePath()+"\\"+file.getName();
45                 System.out.println(newPath);
46                 fos = new FileOutputStream(newPath);
47                 int n = -1;
48                 while ((n = fis.read()) != -1) {
49                     fos.write(n);
50                 }
51             }
52             
53             fis.close();
54             fos.close();
55             
56             System.out.println("copy成功!!!");
57             
58         }
59         
60 
61     }

 缓存流

BufferedInputStream/BufferedOutputStream

1.基本概念:在基本流的基础上进行包装,在读取和写入时,通过缓存进行:先将内容写入到缓存区,缓存区满后再进行读取或写入操作。

2.优点:优点:可以大大减少文件的操作次数,提高写入效率。

3.使用:基本用法与基本流相同,方法也相同。

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("text.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("text2.txt"));
这种写法,我们称之为IO流,IO关闭时只需要关闭最外层流,内层流自动关闭。
bis.close();
bos.flush();//用来刷新缓冲区的,刷新后可以再次写出(字节缓冲流内置缓冲区,如果没有读取出来,可以使用flush()刷新来) bos.close();//用来关闭流释放资源的的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出

4.具体写法:

 1 public class Demo04_BufferInputStream_BufferOutputStream {
 2 
 3     public static void main(String[] args) {
 4 
 5         try {
 6             FileInputStream fis = new FileInputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test");
 7             FileOutputStream fos = new FileOutputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day14\\test2");
 8             BufferedInputStream bis = new BufferedInputStream(fis);
 9             BufferedOutputStream bos = new BufferedOutputStream(fos);
10             
11             int i = -1;
12             while ((i=bis.read())!=-1) {
13                 bos.write(i);
14             }
15             
16             bis.close();
17             bos.flush();
18             bos.close();
19             
20             
21         } catch (Exception e) {
22             // TODO Auto-generated catch block
23             e.printStackTrace();
24         }
25 
26     }
27 }

DataInputStream/DataOutputStream

采用二进制对文件进行读写操作。
与基本流相比,可以直接抄写Java中的基本数据类型。
另外,如果操作的文件是一个二进制文件,需要使用DataInputStream/DataOutputStream替代FileInputStream/FileOutputStream
同样,Data系列的流也有read()和wirte()方法。
注意:使用DataInputStream写入的文件为二进制文件,那么读取的使用就必须要用DataOutputStrea来读。

public class Demo05_DataInputStream_DataOutputStream {

    public static void main(String[] args) {
        /**
         *  DataInputStream/DataOutputStream
         * 
         *     采用二进制对文件进行读写操作。
         *     与基本流相比,可以直接抄写Java中的基本数据类型。
         * 
         */
        
        String name = "aaa";
        int age = 12;
        double height =123.1;
        

        DataInputStream dis = null;
        DataOutputStream dos = null;
        
        try {
            dos = new DataOutputStream(new FileOutputStream("text.txt"));
            
            dos.writeUTF(name);//写入一个字符串格式
            dos.writeInt(age);//写入整形
            dos.writeDouble(height);//写入浮点型
            
            dis.close();
       dos.flush(); dos.close(); }
catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

 

ObjectInputStream/ObjectOutputStrea

直接继承java.io.OutputStream/InputStream
1.与基本流相同,可以直接使用read()和write()方法进行读写。
2.与DataInputStream/DataOutputStream相同,可以对Java基本数据直接进行读写。readInt()/writeInt();
3.可以只用readObject()和writeObject(),直接对对象进行操作。

[对象的序列化和对象的反序列化]

1.对象的序列化:将程序中的对象,持久化的保存在文件中的过程。ObjectOutputStream
2.对象的反序列化:将文件中保存的对象,重新读取得到程序中的过程。ObjectInputStream
注意:如果要将对象进行序列化操作,那么实体类必须实现可序列化接口,即 implements Serializable。添加序列化版本ID(private static final long serialVersionUID = 1L;),只要版本号相同,表示序列化和反序列化时操作的对象是同一个对象,那么对实体类进行增加属性或者减少属性之后进行序列化和反序列化不会报错。
如果不添加版本号,那么系统就会认为增加后的实体类和原来的实体类不是一个实体类。

 1 public class Demo06_ObjectInputStream_ObjectOutputStream {
 2 
 3     
 4     public static void main(String[] args) {
 5         Person zhangsan = new Person("张三", 12, 180);
 6         
 7         ObjectInputStream ois = null;
 8         ObjectOutputStream oos = null;
 9         
10         
11         try {
12             //对象的序列化
13             oos = new ObjectOutputStream(new  FileOutputStream("E:\\Workspaces\\test.txt"));
14             oos.writeObject(zhangsan);
15             //对象的反序列化
16             ois = new ObjectInputStream(new FileInputStream("E:\\Workspaces\\test.txt"));
17             Person p = (Person) ois.readObject();
18             
19             
20             System.out.println(p.getName());
21             
22             ois.close();
23             oos.flush();
24             oos.close();
25             
26         } catch (Exception e) {
27             // TODO Auto-generated catch block
28             e.printStackTrace();
29         }
30         
31     }
32     
33 }
34 //实体类,实现序列化接口
35 class Person implements Serializable{
36     /**
37      * 
38      */
39     private static final long serialVersionUID = 1L;
40     private String name;
41     private int age;
42     private double height;
43     public Person(String name, int age, double height) {
44         super();
45         this.name = name;
46         this.age = age;
47         this.height = height;
48     }
49     public String getName() {
50         return name;
51     }
52     public void setName(String name) {
53         this.name = name;
54     }
55     public int getAge() {
56         return age;
57     }
58     public void setAge(int age) {
59         this.age = age;
60     }
61     public double getHeight() {
62         return height;
63     }
64     public void setHeight(double height) {
65         this.height = height;
66     }
67     @Override
68     public String toString() {
69         return "Person [name=" + name + ", age=" + age + ", height=" + height + "]";
70     }
71     
72     
73 }

字符流

1.概念:在处理数据单元时,以一个字符作为单位,而字节流,是以一个字节流作为单位。父类是Reader和Writer,这两个类也是一个抽象类。

Reader 是所有的输入字符流的父类,它是一个抽象类。
Writer 是所有的输出字符流的父类,它也是一个抽象类。

基类FileReader/FileWriter:

在使用读写操作的时候,只能使用系统的默认的编码格式,无法指定编码,如果文件格式与系统默认格式不一致,那使用这两个方法读写的时候会导致中文乱码。

public class Demo01_FileReader_FileWriter {

    
    /**
     *  在处理数据单元时,以一个字符作为单位,而字节流,是以一个字节流作为单位
     *  
     *  字符流的基类是:Reader和Writer
     *  
     */
    public static void main(String[] args) {
        FileWriter fw = null;
        FileReader fr = null;
        try {
            fw = new FileWriter("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day15\\io.txt");
            fr = new FileReader("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day15\\test.txt");
            fw.write("dddd");
            //写入过程中必须刷新后才能读出(或者关闭)
            fw.flush();
            
            int num = 0 ;
            StringBuffer sb = new StringBuffer();
            while ((num = fr.read())!=-1) {
                sb.append((char)num);
            }
            System.out.println(sb);
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                fw.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }
}

InputStreamReader/OutputStreamWriter

将字节输出流转为字符输入/输出流,是字符流通向字节流的桥梁,可使用指定的 charset 将要写入流中的字符编码成字节

编码:

ASCII码:美国标准信息码。
ISO8859-1:欧洲码。
Unicode编码,万国码,可以分为:UTF-6,UTF-8,UTF-16
ANSI编码,可以分为:GB2312/GBK:简体中文,big-5:繁体中文

 1 public class Demo02_InputStreamReader_OutputStreamWriter {
 2 
 3     public static void main(String[] args) {
 4         InputStreamReader isr = null;
 5         OutputStreamWriter osw = null;
 6         
 7         try {
 8             isr = new InputStreamReader(new FileInputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day15\\io.txt"),"GBK");
 9             osw = new OutputStreamWriter(new FileOutputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day15\\test.txt"),"utf-8");
10             
11             osw.write("啊大撒旦撒大帝发");
12             //必须要刷新
13             osw.flush();
14             
15             int n = 0;
16             StringBuilder sb = new StringBuilder();
17             while ((n=isr.read())!=-1) {
18                 sb.append((char)n);
19             }
20             System.out.println(sb);
21             
22         } catch (Exception e) {
23             // TODO Auto-generated catch block
24             e.printStackTrace();
25         }finally {
26             try {
27                 isr.close();osw.close();
28             } catch (IOException e) {
29                 // TODO Auto-generated catch block
30                 e.printStackTrace();
31             }
32         }
33         
34     }
35 
36 }

BufferedReader/BufferedWriter:缓存流存储。

 1 public class Demo03_BufferedReader_BufferedWriter {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         //与字节流的缓存流使用相同
 6         BufferedReader br = null;
 7         BufferedWriter bw = null;
 8         
 9         try {
10             br = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day15\\io.txt"),"utf-8"));
11             bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:\\Workspaces\\javaSE\\src\\com\\jianglai\\day15\\test.txt"),"utf-8"));
12             
13             bw.write("dasdd哈哈哈");
14             bw.flush();
15             
16             int n = 0;
17             StringBuilder sb = new StringBuilder();
18             while ((n=br.read())!=-1) {
19                 sb.append((char)n);
20             }
21             System.out.println(sb);
22             
23             /**
24              *    原来读取到的字符串是UTF-8格式
25              *    使用s.getBytes("utf-8"):表示用utf-8对字符串进行解码为字节数组。
26              *    
27              *    s = new String(s.getBytes("utf-8"),"GBK");
28              *    表示将解码后的字节数组,重新使用GBK的解码,组合成字符串。
29              *    
30              *    最终,一个UTF-8的字符串,经过解码编码转换成GBK格式的字符串。
31              */
32             String s = sb.toString()+"dasdada发发散发啊";
33             s = new String(s.getBytes("utf-8"),"GBK");
34             bw.write(s);
35             
36         } catch (Exception e) {
37             // TODO Auto-generated catch block
38             e.printStackTrace();
39         }finally {
40             try {
41                 br.close();
42                 bw.close();
43             } catch (IOException e) {
44                 // TODO Auto-generated catch block
45                 e.printStackTrace();
46             }
47         }
48         
49         
50     }
51 
52 }