Java基础入门18:File、IO 流1(方法递归、字符集、IO流-字节流)

File和IO流

File

File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)。

IO流

用于读写数据的(可以读写文件,或网络中的数据...)

File代表文件 IO流用来读写数据

File

创建对象

创建File类的对象

注意:

File对象既可以代表文件、也可以代表文件夹。
Fil封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。

绝对路径和相对路径

绝对路径从盘符开始:

相对路径不带盘符,默认直接到当前工程下的目录寻找文件:

java 复制代码
package com.itchinajie.d1_file;

import java.io.File;

/*
*目标掌握File创建对象,代表具体文件的方案
* */
public class FileTest1 {
    public static void main(String[] args) {
        //1、创建一个File对象,指代某个具体文件
        //路径分隔符
        //File file1 = new File("\u202AE:/Java/resource/ab.txt");
        //File file1 = new File("\u202AE:\\Java\\resource\\ab.txt");
        File file1 = new File("E:" + File.separator + "Java" + File.separator + "resource" + File.separator + "ab.txt");
        System.out.println(file1.length());//文件大小(字节)

        File file2 = new File("E:/Java");

        System.out.println(file2.length());

        //注意:File对象可以指代一个不存在的文件路径
        File f3 = new File(  "D:/resource/aaaa.txt");
        System.out.println(f3.length());

        System.out.println(f3.exists()); // false

        //如果要定位的文件在模块中,直接右键可以复制文件路径
        //绝对路径
        //File file4 = new File("E:\\Java\\code\\file-io-app\\src\\itchinajie.txt");
        //相对路径(重点):不带盘符,默认是直接去工程下找文件
        File file4 = new File("file-io-app\\src\\itchinajie.txt");

        System.out.println(file4.length());


    }
}

判断文件类型和获取文件信息功能

源码展示:

java 复制代码
 //1.创建文件对象,指代某个文件
        File f1 = new File( "E:\\Java\\code\\file-io-app\\src\\itchinajie.txt");
        //File f1 = new File("D:/resource/");

        //2、public boolean exists():判断当前文件对象,对应的文件路径是否存在,存在返回true.
        System.out.println(f1.exists());

        //3、public boolean isFile():判断当前文件对象指代的是否是文件,是文件返回true,反之。
        System.out.println(f1.isFile());

        //4、public boolean isDirectory():判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。
        System.out.println(f1.isDirectory());

        //5.public String getName():获取文件的名称(包含后缀)
        System.out.println(f1.getName());

        //6.public long length():获取文件的大小,返回字节个数
        System.out.println(f1.length());

        //7.publicLongLastModified():获取文件的最后修改时间。
        long time = f1.lastModified();
        SimpleDateFormat sdf = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss");
        System.out.println(sdf.format(time));

        //8.public String getPath():获取创建文件对象时,使用的路径
        File f2  = new File( "E:\\Java\\code\\file-io-app\\src\\itchinajie.txt");
        File f3 = new File( "src/itchinajie.txt");
        System.out.println(f2.getPath());
        System.out.println(f3.getPath());

        //9.public String getAbsolutePath():获取绝对路径
        System.out.println(f2.getPath());
        System.out.println(f3.getPath());

创建和删除文件

File类创建文件功能

File类删除文件的功能

注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。

源码展示:

java 复制代码
package com.itchinajie.d1_file;

import java.io.File;
import java.io.IOException;

/*
* 目标:掌握File提供的创建和删除文件相关的方法
* */
public class FileTest3 {
    public static void main(String[] args) throws IOException {
        //1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
        File f1 = new File( "E:\\Java\\code\\file-io-app\\src\\abcd.txt");
        System.out.println(f1.createNewFile());

        //2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
        File f2 = new File( "E:\\Java\\code\\file-io-app\\src\\ddd");
        System.out.println(f2.mkdir());

        //3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
        File f3 = new File( "E:\\Java\\code\\file-io-app\\src\\aaa\\bbb\\ccc");
        System.out.println(f3.mkdirs());

        //3、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
        System.out.println(f1.delete());
        System.out.println(f2.delete());
        File f4 = new File( "E:\\Java");
        System.out.println(f4.delete());
    }
}

遍历文件夹

File类提供的遍历文件夹的功能

使用listFiles方法时的注意事项:

当主调是文件,或者路径不存在时,返回null;

当主调是空文件夹时,返回一个长度为0的数组;

当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回;

当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件;

当主调是一个文件夹,但是没有权限访问该文件夹时,返回null。

源码展示:

java 复制代码
package com.itchinajie.d1_file;

import java.io.File;
import java.util.Arrays;

/*
* 目标:掌握File提供的遍历文件夹方法
* */
public class FileTest4 {
    public static void main(String[] args) {
        //1、publicString[] list():获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
        File f1 = new File("E:\\Java\\code");
        String[] names = f1.list();
        for (String name : names) {
            System.out.println(name);
        }
        //2、public File[]listFiles():(重点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
        File[] files = f1.listFiles();
        for (File file : files) {
            System.out.println(file.getAbsolutePath());
        }

        File f = new File("D:/resource/aaa");
        File[] files1 = f.listFiles();
        System.out.println(Arrays.toString(files1));
        //使用listFile方法时的注意事项:
        //当主调是文件,或者路径不存在时,返回null
        //当主调是空文件夹时,返回一个长度为0的数组
        //当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
        //当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
        //当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
    }
}

方法递归

认识递归的形式

什么是方法递归?

递归是一种算法,在程序设计语言中广泛应用。

从形式上说:方法调用自身的形式称为方法递归(recursion)。

递归的形式

直接递归:方法自己调用自己。

间接递归:方法调用其他方法,其他方法又回调方法自己。

使用方法递归时需要注意的问题:

递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。

java 复制代码
package com.itchinajie.d2_recursion;

/*
* 目标:认识一下递归的形式
* */
public class RecursionTest1 {
    public static void main(String[] args) {
        test1();
    }

    //直接方法递归
    public static void test1(){
        System.out.println("---test1---");
        test1();
    }

    //间接方法递归
    public static void test2(){
        System.out.println("---Test2---");
        test3();
    }
    public static void test3(){
        System.out.println("---Test3---");
        test2();//间接递归
    }
}

递归的应用、执行流程、算法思想

java 复制代码
package com.itchinajie.d2_recursion;
/*
*目标:掌握递归的应用,执行流程和算法思想
* */
public class RecursionTest2 {
    public static void main(String[] args) {
        System.out.println(f(5));
    }
    public static int f(int n){
        //终结点
        if (n == 1){
            return 1;
        }else {
            return f(n-1) * n;
        }
    }
}



package com.itchinajie.d2_recursion;
/*
*掌握递归的应用2
* */
public class RecursionTest2_1 {
    public static void main(String[] args) {
        //计算1 - n 的和的结果,用递归的思想解决
        System.out.println(f(10));
    }
    public static int f(int n){
        if (n == 1){
            return 1;
        }else {
            return n + f(n -1);
        }
    }
}

递归算法的三大要素

递归的公式:f(n)=f(n-1)*n;

递归的终结点:f(1)

递归的方向必须走向终结点:

java 复制代码
package com.itchinajie.d2_recursion;
/*
*掌握递归的应用3
* */
public class RecursionTest2_2 {
    public static void main(String[] args) {
    //猴子吃桃
    //猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了个
    //第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又多吃了一个
    //以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个
    //等到第10天的时候发现桃子只有1个了。
    // 需求:请问猴子第一天摘了多少个桃子?
    //公式:f(x) - f(x) / 2  - 1 = f(x + 1)
        //变形:f(x) = 2f(x + 1) + 2
        System.out.println(f(1));
        System.out.println(f(2));
        System.out.println(f(3));
    }
    public static int f(int n){
        if (n == 10){
            return 1;
        }else {
            return 2*f(n + 1) +2;
        }
    }
}

其他应用:文件搜索

java 复制代码
package com.itchinajie.d2_recursion;

import java.io.File;
import java.io.IOException;

/*
* 目标:掌握文件搜索的实现
* */
public class RecursionTest3 {
    public static void main(String[] args) throws IOException {
        searchFile(new File("E:/"),"QQ.exe");
    }
    /**
     * 去目录下搜索某个文件
     * @param dir
     * @param fileName
     */
    public static void searchFile(File dir,String fileName) throws IOException {
        //1、把非法的情况拦截住
        if (dir == null || !dir.exists() || dir.isFile()){
            return;
        }

        //2、dir不是null,存在,一定目录对象
        //获取当前目录下的以及文件对象
        File[] files = dir.listFiles();

       //3、判断当前目录下是否存在一级对象,以及是否可以拿到一级文件对象
        if (files != null && files.length > 0){
            //4、遍历全部一级文件对象
            for (File f : files) {
                //5、判断文件是否是文件还是文件夹
                if (f.isFile()){
                    //判断这个文件名是否是我们要找的
                    if (f.getName().contains(fileName)){
                        System.out.println("找到了:" + f.getAbsolutePath());
                        Runtime runtime = Runtime.getRuntime();
                        runtime.exec(f.getAbsolutePath());
                    }
                }else {
                        //是文件夹,继续重复这个过程(递归)
                        searchFile(f,fileName);
                }
            }
        }
    }
}

字符集

常见字符集

ASCLL、Unicode、UTF-8

其中UTF-8 是Unicod字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节 ;英文字符、数字等只占1个字节(兼容标准ASCLL编码),汉字字符占用3个字节。

注意:技术人员在开发时都应该使用UTF-8编码!

注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。
注意2:英文,数字一般不会乱码,因为很多字符集都兼容了ASCLL编码。

字符集的编码、解码操作

编码:把字符按照指定字符集编码成字节。

解码:把字节按照指定字符集解码成字符。

java 复制代码
package com.itchinajie.d4_charset;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/*
*目标:掌握如何使用Java代码完成对字符的编码和解码
* */
public class Test {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //1、编码
        String data = "a我b";
        byte[] bytes = data.getBytes();//默认是按照平台字符集(UTF-8)进行编码的
        System.out.println(Arrays.toString(bytes));

        //按照指定字符集进行编码
        byte[] gbks = data.getBytes("GBK");
        System.out.println(Arrays.toString(gbks));

        //2、解码
        String string = new String(bytes);//按照平台默认编码(UTF-8)解码的
        System.out.println(string);

        String string1 = new String(gbks,"GBK");
        System.out.println(string1);

    }
}

IO流

IO流简单描述

IO流的分类

流的四大类:

字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流 。

字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。

字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流。

字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。

IO流的体系

IO流-字节流

FilelnputStream(文件字节输入流)

每次读取一个字节

作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。

java 复制代码
package com.itchinajie.d5_byte_stream;

import java.io.*;

/*
* 目标掌握文件字节输入流,每次读取一个字节
* */
public class FileInputStreamTest1 {
    public static void main(String[]  args) throws IOException {
        //1、创建文件字节输入流管道,与源文件接通
        //InputStream is = new FileInputStream(new File("src/itchinajie01.txt"));
        //简化写法,推荐使用
        InputStream is = new FileInputStream(("file-io-app/src/itchinajie01.txt"));

        //2、开始读取文件的字节数据
        //public int read();每次读取一个字节返回,如果没有数据了,返回-1
//        int read = is.read();
//        System.out.println((char)read);
//
//        int read1 = is.read();
//        System.out.println((char ) read1);
//
//        int read2 = is.read();
//        System.out.println( read2);

        //3、使用循环改造上面的代码
        int b;//用于记住读取的字节
        while ((b = is.read()) != -1){
            System.out.print((char)b);
        }

        //读取数据的性能很差
        //读取汉字会输出乱码,无法避免
        //流使用完之后,必须关闭,释放系统资源
        is.close();
    }
}

注意:使用FilelnputStream每次读取一个字节,读取性能较差,并且读取汉字输出会乱码。

每次读取多个字节

作用:以内存为基准,把文件中的数据以字节的形式读入到内存中去。

java 复制代码
package com.itchinajie.d5_byte_stream;

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

/*
* 目标:掌握使用FileInputStream每次读取多个字节
* */
public class FileInputStreamTest2 {
    public static void main(String[]  args) throws IOException {
        //1、创建一个字节输入流对象代表字节输入流管道与源文件接通
        FileInputStream is = new FileInputStream("file-io-app\\src\\itchinajie02.txt");

        //2、开始读取文件中的字节数据,每次读取多个字节
//        public int read(byte b [ ])throws IOException
//        每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1.
/*        byte[] buffer = new byte[3];

        int len = is.read(buffer);
        String rs = new String(buffer);
        System.out.println(rs);
        System.out.println("当次读取的字节数量:" + len);

        int len2 = is.read(buffer);
        //注意:读取多少,就倒多少
        String rs2 = new String(buffer,0,len2);
        System.out.println(rs2);
        System.out.println("第二次读取的字节数:" + len2);

        int len3 = is.read(buffer);
        String rs3 = new String(buffer);
        System.out.println(rs3);
        System.out.println("第二次读取的字节数:" + len3);*/

        //3、使用循环改造
        byte[] buffer = new byte[3];
        int len;//记住每次读了多少个字节
        while((len = is.read(buffer)) != -1){
            //注意:读取多少,就倒多少
            String rs = new String(buffer, 0, len);
            System.out.print(rs);
        }
        //性能得到了明显的提升!!
        //这种方案也不能避免读取文字出现乱码的问题!!
        is.close();
    }
}

一次性读取完全部字节

方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节。

方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回。

java 复制代码
package com.itchinajie.d5_byte_stream;

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

/*
* 目标:使用文件字节输入流一次读完全部字节
* */
public class FileInputStreamTest3 {
    public static void main(String[]  args) throws IOException {
        //1、一次性读取完文件的全部字节到一个字节数组中去。
        //创建一个字节输入流管道与源文件接通
        FileInputStream is = new FileInputStream("file-io-app\\src\\itchinajie03.txt");

        //方法一:
        //2、准备一个字节数组,大小与文件的大小正好一样大
       /* File f = new File("file-io-app\\src\\itchinajie03.txt");
        long size = f.length();
        byte[] buffer = new byte[(int)size];

        int len = is.read(buffer);
        System.out.println(new String(buffer));

        System.out.println(size);
        System.out.println(len);*/

        //方法二:
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));


    }
}

注意:直接把文件数据全部读取到一个字节数组可以避免乱码,但如果文件过大,创建的字节数组也会过大,可能引起内存溢出,所以读写文本内容更适合用字符流,而字节流适合故数据的转移,如:文件复制等。

FileOutputStream(文件字节输出流)

作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去。

java 复制代码
package com.itchinajie.d5_byte_stream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/*
* 目标:掌握文件字节输出流FileOutputStream的使用
* */
public class FileOutputStreamTest4 {
    public static void main(String[]  args) throws IOException {
        //1、创建一个字节输出流管道与目标文件接通
        //覆盖管道:覆盖之前的数据
//        OutputStream os =
//                new FileOutputStream("file-io-app\\src\\itchinajie04out.txt");

        //追加数据的管道
        OutputStream os =
                new FileOutputStream("file-io-app\\src\\itchinajie04out.txt",true);

        //2、开始写字节数据出去了
        os.write(97);//97就是一个字节,代表a
        os.write('b');//'b'也是一个字节
        //os.write('杰');//[ooo]默认只能写出去一个字节
        byte[] bytes = "我爱你中国abc".getBytes();

        os.write(bytes);

        os.write(bytes,0,15);

        //换行操作
        os.write("\r\n".getBytes());
        os.close();//关闭流
    }
}

案例:文件复制

字节流非常适合做一切文件的复制操作

任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!

java 复制代码
package com.itchinajie.d5_byte_stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;

/*
* 目标:使用字节流完成对文件的复制操作
* */
public class CopyTest5 {
    public static void main(String[] args) throws Exception {
        //需求:复制照片
        //1、创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("E:\\Java\\tupian\\meinv.jpg");

        //2、创建一个字节输出流管道与目标文件接通
        FileOutputStream os = new FileOutputStream("C:\\data\\meinv1.jpg");
 
        //3、创建一个字节数组,负责转移字节数据
        byte[] buffer = new byte[1024];//1kB
        //4、从字节输入流中读取字节数据,写出到字节输出流中。读多少写出去多少。
        int len;//用来记住每次读取了多少个字节
        while((len = is.read(buffer)) != -1){
            os.write(buffer,0,len);
        }
        os.close();
       is.close();//后创建的六先关掉,先创建的流后关掉
        System.out.println("复制完成~~");
    }
}

释放资源的方式

try-catch-finally

finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非VM终止。

作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)。

java 复制代码
package com.itchinajie.resource;
/*
* 目标:认识try-catch-finally
* */
public class Test1 {
    public static void main(String[] args) {
         try {
             System.out.println(10 / 0);
             //return;//跳出方法执行
             //System.exit(0);//虚拟机
         }catch (Exception e){
             e.printStackTrace();
         }finally {
             System.out.println("====~~牛逼~~====");
         }
        System.out.println(chu(10, 2));
    }
    public static int chu(int a,int b) {
        try {
            return a / b;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;//代表的是出现异常
        } finally {
            //千万不要在fina11y中返回数据!
            return 111;
        }
    }
}

try-with-resource

JDK7开始提供了更简单的资源释放方案:try-with-resource。

java 复制代码
package com.itchinajie.resource;

public class Myconnection implements AutoCloseable{
    @Override
    public void close() throws Exception {
        System.out.println("释放了与某个硬件的链接资源");
    }
}



package com.itchinajie.resource;

import java.io.*;

/*
* 目标:掌握释放资源的方式
* */
public class Test2 {
    public static void main(String[] args){
        InputStream is = null;
        OutputStream os = null;
        try {
            //1、创建一个字节输入流管道与源文件接通
            is = new FileInputStream("E:\\Java\\tupian\\meinv.jpg");
            //2、创建一个字节输出流管道与目标文件接通
             os = new FileOutputStream("C:\\data\\meinv1.jpg");
            //3、创建一个字节数组,负责转移字节数据
            byte[] buffer = new byte[1024];//1kB
            //4、从字节输入流中读取字节数据,写出到字节输出流中。读多少写出去多少。
            int len;//用来记住每次读取了多少个字节
            while((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }

            System.out.println("复制完成~~");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //释放资源操作
            try {
                if (os!= null)os.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                if (is != null)is.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
java 复制代码
package com.itchinajie.resource;

import java.io.*;

/*
* 目标:掌握释放资源的方式2
* */
public class Test3 {
    public static void main(String[] args) throws Exception {
        try(//1、创建一个字节输入流管道与源文件接通
            InputStream is = new FileInputStream("E:\\Java\\tupian\\meinv.jpg");
            //2、创建一个字节输出流管道与目标文件接通
            OutputStream os = new FileOutputStream("C:\\data\\meinv1.jpg");
            //注意:这里只能放置资源对象。(流对象)
            //int age=21;
            //什么是资源呢?资源都是会实现AutoCloseable.接口。资源都会有一个close方法,并且资源放到这里后
            //用完之后,会被自动调用其cL0se方法完成资源的有放操作。
            Myconnection conn = new Myconnection();
            ){
            //3、创建一个字节数组,负责转移字节数据
            byte[] buffer = new byte[1024];//1kB
            //4、从字节输入流中读取字节数据,写出到字节输出流中。读多少写出去多少。
            int len;//用来记住每次读取了多少个字节
            while((len = is.read(buffer)) != -1){
                os.write(buffer,0,len);
            }
            System.out.println(conn);
            System.out.println("复制完成~~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(本章图片均来自于黑马程序员视频)

相关推荐
爱编程的鱼1 小时前
OpenCV Python 绑定:原理与实战
c语言·开发语言·c++·python
这周也會开心1 小时前
云服务器安装JDK、Tomcat、MySQL
java·服务器·tomcat
hrrrrb2 小时前
【Spring Security】Spring Security 概念
java·数据库·spring
小信丶2 小时前
Spring 中解决 “Could not autowire. There is more than one bean of type“ 错误
java·spring
sdgsdgdsgc2 小时前
Next.js企业级应用开发:SSR、ISR与性能监控方案
开发语言·前端·javascript
周杰伦_Jay3 小时前
【Java虚拟机(JVM)全面解析】从原理到面试实战、JVM故障处理、类加载、内存区域、垃圾回收
java·jvm
晓风残月淡3 小时前
JVM字节码与类的加载(二):类加载器
jvm·python·php
西柚小萌新5 小时前
【深入浅出PyTorch】--上采样+下采样
人工智能·pytorch·python
rit84324996 小时前
基于MATLAB的模糊图像复原
开发语言·matlab
fie88896 小时前
基于MATLAB的声呐图像特征提取与显示
开发语言·人工智能