文件IO操作

日升时奋斗,日落时自省 

目录

1、文件基本认知

1.1、文件路径

1.2、相对路径

1.3、文件类型

2、Java的文件操作

2.1、文件操作类File

3、数据流读写

3.1字节流读文件

3.2、字节流写文件

3.3、字符流读操作

3.4、字符流写操作

4、文件操作案例

4.1、删除文件

4.2、普通文件复制(就是不能复制目录)

4.3、查找包含某字符的文件


1、文件基本认知

谈到文件无疑是从我们知道的开始说,狭义认知针对硬盘这种持久化存储的IO设备,当我们进行数据保存时,往往不是以以这个整体(一块内容)来保存的,而是单独保存的,这个独立的单位就在计算机中被抽象为文件的概念。

狭义:简单说就是硬盘上的文件 和  目录

文件除了有数据内容之外,还有一部分信息,例如文件名,文件类型,文件大小等并不作为文件数据类型而存在,这类信息就是文件的元信息。

广义:计算机中的软硬件资源

文件类似树结构一个文件下包含多个文件,当前文件有包含多个子文件,像树枝一样

文件的基本就是以上,没有什么特别的;

文件主要跟我们写代码有关系,之前我们写的代码,存储数据,主要是靠变量,变量是在内存中的。文件是在硬盘上的,本话题主要是如何实现代码与文件交接

1.1、文件路径

每个文件,在硬盘上都有一个具体的“路径”;

 test.txt文件的路径 ,叫做E:/Test/test.txt表示一个文件的具体位置路径,就可以使用/来分割不同的目录级别.

这里注意细节的友友们,会看到图片上使用的是反斜杠(\)但是我上面打出来是 斜杠(/)

问题为什么不一样?这样写的意义是什么?

(1)其实两种写法都可以,都是对的,可以尝试一下斜杠

(2)其次就是在java中尽量写 斜杠表示法 。为什么???

因为代码去写反斜杠的不方便

例如 :java中代码:String path="E:\Test\test.txt";     现在的\T就以个转义字符

斜杠与反斜杠肯定是有由来的 ,最早期的DOS系统使用过反斜杠 ,后来又改成了斜杠再后来Windows也继承了这样的设定。

刚刚事例中的文件路径开头都有一个大写字母C:、D:或者E:都叫做“盘符”,当然写小写也是可以的,都能起作用,盘符是通过“硬盘分区”来的,每个盘符可以单独的占一个硬盘,也可以若干个盘符占一个硬盘。

有个稀奇的问题,为啥没有a:,b:盘符?

有,但是出现的比较早,现在已经淘汰了,这样的盘符在之前叫做软盘,存储空间对于现在来说太小了只有几MB,所以喜欢了可以买个收藏

1.2、相对路径

因为绝对路径就是在“文件路径”标题下,以盘符开头的路径

相对路径:以当前所在的目录为基准,或者以..开头(也可以以.开头),找到指定路径

当前目录也称为工作目录,每个程序运行的时候,都有一个工作目录,这里来看一下相对路径是个啥,在控制台执行 打开控制台 win+r 然后输入cmd 

 这就是绝对路径因为它是默认的工作目录,那相对路径呢?

 这俩就是相对路径了,执行程序运行的目录。(这是两个简单Windows操作系统命令,想了解更多,可以百度稍微科普一下,记几个常用就行了)

相对路径有带点的表示方式 这个可能友友们也会有困惑

先解释大体的概念 : 点+斜杠(./)就是当前所在目录,点+点+斜杠(../)就是上级目录

现在理解相对路径就不难了,以idea为例

 当你打开idea的时候,这个路径就是你当前所在目录(这里是我的哈,这里用作解释,你肯定跟我是不一样的) 当前文件路径:D:/java使用/first/IO_Operations

以IO_Operations文件定位

所在目录 :D:/java使用/first

现在使用点+斜杠的方式表示一下当前所在目录 :

相对路径: ./IO_Operations     工作目录 :D:/java使用/first/

 相对路径: ./first/IO_Operations  工作目录:D:/java使用

 相对路径: ./java使用/first/IO_Operations  工作目录: D:/

多个例子之后就不难找到 点+ 斜杠表示的规律 不管在那个目录下都表示是当前所在目录。

现在使用点+点+斜杠的方式表示一下 :../IO_Operations

IO_Operations文件的当前层目录是first所以只需要表示一个上层目录就行了,这里的java使用就是根目录 所以表示如上。

再举一个事例:D:/java使用/first/IO文件/IO_Operations (稍作修改)

同样以IO_Operations文件定位

现在使用点+点+斜杠的方式表示一下 :../../IO_Operations

这里只需要到到达根目录就行,当前层目录是IO文件 根目录是Java使用,相当于连跳两级,两个../就可以解决问题

1.3、文件类型

文件类型我们看见过很多种,word文件 ,exe程序,图片,视频等,虽然很多种但是文件还是分为两个大类;

(1)文本文件 (存的是文本,字符串)

字符串是由字符构成,字符是怎么写上去的,通过数字表示,能存储的一定都是合法的字符,因为会按照你指定的字符编码表进行查找对应的数字,然后进行存储

(2)二进制文件(存的是二进制数据,不一定是字符串了) 

没有限制是不是字符都可以存,(光脚的不怕穿鞋的)

区分两种文件:能看的懂的就是文本文件(主要特征不乱),看不懂的就是二进制文件(乱)

2、Java的文件操作

2.1、文件操作类File

java标准库提供的一个File类,用于创建文件对象,这里叙述只三个构造方法(当然还有很多,有兴趣的友友,idea中查看或者API官方文档)

该构造方法带有两个参数 第一个参数是父目录 +孩子文件路径 两者都是用路径表示

 该构造方法带有两个参数,第一个参数是父目录 +孩子文件路径,父目录就不需要路径了,直接放就行。

该构造方法就一个参数==>路径  

说到路径这里解释一个问题,就是写路径的时候写斜杠还是反斜杠,由于的话就写separator针对Windows(是File里的一个静态变量)斜杠还是反斜杠就可以不用担心了,它会跟随系统

File file=new File("e:"+File.separator+"test.txt");

 如上写法就行,把斜杠或者反斜杠换成该静态方法

(1)再提一些File类中简单方法 以下方法相关 文件名 ,父目录,,文件路径,绝对路径,相对路径

 public static void main(String[] args) throws IOException {
        File file=new File("e:"+File.separator+"test.txt");
        System.out.println(file.getName());  //获取文件名字
        System.out.println(file.getParent());  //获取文件父目录
        System.out.println(file.getPath());  //获取文件路径
        System.out.println(file.getAbsoluteFile());  //获取绝对路径
        System.out.println(file.getCanonicalFile());   //获取相对路径 此时 要抛出异常 快捷键 alt+enter(也就是回车)
    }

代码中只有相对路径比较特殊需要抛出异常 快捷键 alt+enter(enter也就是回车)。

提示:文件路径不用敲出来,直接复制粘贴就行,在同一个系统上的话不会错,如果不同系统也不放心的情况下使用 刚刚的静态方法就可以了(它会自己对应不同系统)

(2)以下代码解释方法 :文件存在,是否是文件 ,是否是目录 ,创建我呢间

public static void main(String[] args) throws IOException {
        File file=new File("./test.txt");
        System.out.println(file.exists());   //当前文件是否存在
        System.out.println(file.isFile());   //是不是文件
        System.out.println(file.isDirectory());   //是不是目录
        file.createNewFile();                //创建文件
        System.out.println(file.exists());   //当前文件是否存在
        System.out.println(file.isFile());   //是不是文件
        System.out.println(file.isDirectory());   //是不是目录
    }

File类创建对象的时候,本身是不会创建文件,这里有专门的方法创建文件,这里是以相对路径创建文件的所以会在idea的目录上显示(以下是过程及问题解决)

 (3)以下是 删除文件,创建目录,还有替换文件名称

删除方法:delete 这个就没有过多的解释了

删除临时文件:deleteOnExit 方法 程序退出的时候,自动删除,临时文件程序有时候也会用到,啥是临时文件,咋没有见过???

public static void main(String[] args) {
        //创建文件目录
        File dir=new File("./test/aaa/bbb");
        /*
        * 创建多级目录的时候就需要  mkdirs
        * */
        dir.mkdirs();  //如果是创建一个目录的话 就使用 mkdir
    }
public static void main(String[] args) {
        //修改文件名称
        File file=new File("./test");
        File file1=new File("./testnow");
        file.renameTo(file1);   //修改昵称
    }

3、数据流读写

使用“流对象”进行操作 如何理解流???

“流”字联想起来跟水有关系,水流 连绵不断,没有固定形状,那就可以划分多次,也可以不划分。以接水为例: 一家人需要水是固定量的,但是接水的次数是不定的

(1)可以一次接完

(2)也可以先接一半

(3)还可以将需要水分5次来接

这就是水流的提点,为什么会以流来解释到水,因为读字节 与 写字节也是如此

从文件中读取字节情况很多,可能一次读完,可能一次读不完,像水一样

(1)可以直接一次性读(写)完

(2)分两次读(写)完

(3)分多次读(写)完

流类型上分为两类 :字节流 、字符流

(1)字节流 相关类   FileInputStream ->(继承) InputStream 、FileOutputStream->OutputStream

(2)字符流 相关类   Reader ->(继承)FileReader  、  Writer->(继承)FileWriter

 为什么会有继承这一说?

 是因为这里InputStream/OutputStream/Reader/Writer都是抽象类是不能创建对象的。

3.1字节流读文件

读文件操作使用InputStream和FileInputStream两个类进行。

 InputStream inputStream=new FileInputStream("e:/test.txt");

创建对象,赋予文件路径即可

//进行读操作
        while(true){
            //获取字节对应的数字
            int n=inputStream.read();
            if(n==-1){  //文件读到末尾了也就是结束 此时read返回-1
                break;
            }
            //因为获取的是数字,所以这里需要进行转换byte类型 
            System.out.println("字节流打印 "+(byte)n);
            //如果是文字的话 就该以十六进制来打印了 可以去查字符表就能知道是什么了
            System.out.printf("%x \n",(byte)n);
        }

以上两个写在一个main方法中就可以尝试了,这里说一下read方法在写的时候会抛出异常;有友友肯定疑惑这里的read读的返回值为啥是int,首先是方法这么定的,然后就是手动转化成byte类型就行;InputStream提供了三个重载方法read;

(1)read无参数版本一次读一个字节

(2)read有一个参数的版本 把内容一次填充提到byte数组中(这里相当于“输入型参数”)

(3)read 三个参数版本 其实就比(2)多了个范围从第几个开始多长

注:字节对于打印汉字可以使用16进制,对照编码表查找针对不同的(例如utf8,gbk,BIG5)根据自己需求对照即可(所以说字节流也是可读文本文件的)

这里再写一下read两个参数的代码(三个参数与两个参数大体相同就不在展示),前面创建对象是一样的,以下部分不同

 //read带有一个参数时进行读取
        while(true){
            //首先需要准备一个数组 这里的字节数 可以随心所欲设置(有点夸张)意思明白即可。
            byte[] buffer=new byte[1024];
            //这里的传参操作就是把刚才的数组传进去, 计算的当前多少个字节
            int len = inputStream.read(buffer);
            System.out.println("len "+len);
            if(len==-1){
                break;
            }
            //读取就结果同样时转换成byte 
            for(int i=0;i<len;i++){
                System.out.printf("%x \n",buffer[i]);
            }
        }

上面给出的数组长度是1024,read就会尽可能的读取1024个字节,填到数组里,但是实际上,文件剩余长度是有限的,如果文件剩余长度超过了1024此时就只能接收到1024个字节,同时并进行打印,然后再次执行while循环,如果当前剩余的长度不足1024,此时有多少就返回多少。

注:读文件的时候,文件在磁盘上内容可能比较多,甚至超出内存容量,一次读完是不显示的,对此类文件操作都是一边读一边处理,处理好了一部分,再处理下一个部分

有一个问题,这里的数组名为什么刚好叫做buffer???

答案:buffer翻译为缓冲区,存在的意义就是提高IO操作的效率,单次IO操作,是要访问硬盘IO设备,单次操作是比较消耗时间的,如果频繁进行这样的IO操作,同样要耗费不少时间。这里很像mysql的插入操作,插入一组传给服务器也是消耗时间的,不如一次插入多组。

单次IO时间是一定的,缩短IO次数就会提高整个程序效率,第一个版本的代代码一个一个read次数多时间长;第二个版本是一次read1024个字节,循环降低了很多,也就是IO次数下降很多。

3.2、字节流写文件

OutputStream类来进行字节流写文件

 public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("e:/test.txt");   //字节流写 也是会报一个找不到文件的操作的
        outputStream.write(97);
        outputStream.write(98);
        outputStream.write(99);
        outputStream.write(100);
        //记得关闭文件
        outputStream.close();
    }

下面的操作用图解释

 确实我们一般也都会续着写,当然不想清空,流对象还提供了一个“追加写”对象,通过这个就可以实现不清空文件把新内容写在后面。

解释一下:input(输入),output(输出)为什么在代码中input是写入程序,output是写文件??

字节流写入涉及到了关闭文件的操作 close操作(尽量不要忘记)

为什么要写文件结束的时候要close?

进程->在内核里,使用PCB这样的数据结构来表示进程 (这里也有介绍PCB)

一个线程对应一个PCB

一个进程可以对应一个PCB也可以对应多个

PCB中有一个重要的属性叫做文件描述符表(相当于一个数组)记录了该进程打开那些文件,(即使一个进程里有多个线程也会有多个PCB)

 如果真忘了写close操作会有什么问题?

针对java来说还好,但是其他语言不能保证,例如C语言自身就没有GC(Garbage collection)功能,在java中GC操作会回收这个OutputStream对象的时候去完成释放操作,但是GC不一定能准时回收,可能再我们下次一使用的时候GC还没有回收

所以,如果不入手动释放,意味着文件描述符表可以能会被占满(文件描述符表不能自动扩容言外之意就是会满,满了就会卡主,不能用了),文件描述符表不同系统长度不同,但是肯定不大,长度撑死就是几千,对于计算机对于几千几百还是太小了。

特殊情况:close一般情况是执行的,如果一个程序对这个文件一直都需要使用,那文件直到进程结束,PCB销毁,文件描述符表也就销毁了,文件资源会被自动回收(所以文件close之后,程序立即结束了,你忘了关闭,java会自动回收的)

注:虽然java有自动回收功能,但是尽可能手动回收

那出来手动结束,程序能不能自己来结束??答案: 能   所以有了更优雅的代码

try(OutputStream outputStream=new FileOutputStream("e:/test.txt")){
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);
            outputStream.write(100);
        }

使用try()这个写法虽然没有显示close,实际上是会执行的,try语句块执行结束就可以自动执行close操作,该语法被称为try with resources,但是不是说try中谁都可以放置,来看看为啥OutputStream可以?

 实现了Closeable接口就可以该接口提供了close方法

3.3、字符流读操作

与字节流差不多使用,就是读的时候是一个字符一个字符读的,读文本的时候方便(因为读了能看懂)以下代码简单的读取文件内容

//字符流读操作
    public static void main(String[] args) throws IOException {
        try(Reader reader=new FileReader("e:/test.txt")){
            while(true){
                int ch=reader.read();
                if(ch==-1){
                    break;
                }
                System.out.print(""+(char)ch);
            }
        }
    }
public static void main(String[] args) {
        // Scanner scanner=new Scanner(System.in);  该种输入方式 返回的是字节流 只是读取的键盘信息
        try(InputStream inputStream=new FileInputStream("e:/test.txt")){
            Scanner scanner=new Scanner(inputStream);

            //此时读取就是从文件中读取
            scanner.next();  //此处不建议使用nextLine
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

 借读操作来介绍Scanner ,其实该类是搭配流对象进行使用的,这就是为什么我们每次写Scanner创建对象的时候都会在参数里写 System.in ,这是一个输入流与键盘相连能接受键盘传来的信息。

同样Scanner本身就是字节流所以可以放字节流对象。

3.4、字符流写操作

//字符流写操作
    public static void main(String[] args) {
        try(Writer writer=new FileWriter("e:/test.txt")){
            writer.write("hello world");
            writer.flush();   //每次写入都需要耍新缓冲区 , 为缓冲区不能总发着会进行覆盖
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

writer写操作解释:写操作是先写在缓冲区里的,(缓冲区存在很多种形态,咱们自己的代码里也会有缓冲区;标准库里也可以有缓冲区,操作系统内核里也可以有缓冲区)

写操作执行完了,内容仍然可能在缓冲区里,还没有真的进入硬盘。

close操作,就会触发缓冲区的刷新,刷新后缓冲区将内容写到硬盘中,出来close之外还有别的方法,flush方法进行刷新,close方法一旦关闭文件后就不能在对文件操作了,flush方法进行刷新后仍然可以对文件操作。

4、文件操作案例

4.1、删除文件

扫描指定目录,并找到要删除的文件名称(不包含目录),并且后续访问到会问用户是否删除该文件(以下代码均有注释)

思路:

(1)第一次需要输入根目录   并且判断当前输入的是否是目录

(2)第二次需要输入你要删除的文件名称

(3)输入目录后不一定就是当前我们需要的目录,里面可能还包含了很多子目录,此时就需要递归了,文件是成树形结构的,所以次数采用深度优先进行遍历

(4)递归条件如果文件为空则返回,如果不为空 判断是否是目录如果是目录则继续递归,如果不是目录if判断当前文件中有是否包含删除文件名,包含再次判定是否需要删除即可

private static Scanner scanner=new Scanner(System.in);
    public static void main(String[] args) {
        //用户输入一个指定文件路径
        System.out.println("请输入要搜索的文件路径");
        String basepath=scanner.next(); // 提醒使用next就可以
        //针对用户输入路径简单判断
        File root=new File(basepath);
        if(!root.isDirectory()){
            //当前路径不存在或者不是一个文件 提醒一下
            System.out.println("用户输入文件有误!!");
            return;
        }
        //如果没有问题就进入下一步
        //输入要删除的文件
        System.out.println("请输入要删除的文件名称");
        String deletename=scanner.next();
        /*
        * 前面是输入一个目录但是不一定当前目录下没有子目录
        * 先从根本目录出发
        * 先判定一下,当前目录里,看看是否包含要删除的文件, 如果是就删除 否则就跳过下一个
        * 如果当前这里包含一些目录,针对目录进行递归
         * */
        scanDir(root,deletename);
    }
 private static void scanDir(File root, String deletename) {
        //列出root下的文件和目录
        File[] files=root.listFiles();  //数组接收了当前文件目录
        if(files==null){
            //当前文件是空 ,就没有判定的需要了直接返回
            //按递归的思想就是  这里不行这条路径就结束了
            return ;
        }
        //开始进行遍历
        for (File f:files) {
            if(f.isDirectory()){
                //如果是目录的话 就继续递归
                scanDir(f,deletename);
            }else{
                //另一种 不是目录的话,只要包含就可以删了
                if(f.getName().contains(deletename)){
                    System.out.println("已经找到要删除的文件是否要删除"+f.getAbsolutePath());
                    //找到之后 让用户确定是否要删除  如果删除 就输入 确认删除
                    String choic=scanner.next();
                    //用户输入后 进行判定
                    if(choic.equals("确认删除")){
                        f.delete();
                        System.out.println("删除成功");
                    }else{
                        System.out.println("删除取消");
                    }

                }
            }
        }
    }

 运行结果和执行过程

 

4.2、普通文件复制(就是不能复制目录)

思路:
(1)输入你要拷贝的文件路径包括当前你要拷贝的文件名(这先叫做被拷贝文件)

(2)输入你要拷贝在哪里这里还需要你写相同的文件名,因为是拷贝  (这里就叫做拷贝文件)

(3)两次输入完成之后 判定你要被拷贝的文件必须存在并且判定拷贝文件不能存在(要不这不就覆盖了)

(4)判定结束说明没有问题,字节流输入 输出创建 对象开始进行被拷贝文件输入拷贝文件输出(FileOutputStream会自动创建文件)

//拷贝文件
    public static void main(String[] args) {
        //输入两个路
        // 源文件 和  目标文件
        /*
        * 解释 一个 思路就 拷贝出来的文件肯定是不存在的
        * */
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入你要拷贝的文件路径");
        String srcPath=scanner.next();
        System.out.println("请输入你要拷贝到那个位置");
        String destPath=scanner.next();
        File srcfile=new File(srcPath);
        //首先就是你要拷贝的地方要有东西 ,所以这个文件他一定是要存在的
        if(!srcfile.isFile()){
            //如果文件不存在  ,也就不存在打印这一说了 可以结束了
            System.out.println("原文件路径有问题");
            return ;
        }
        File desfile=new File(destPath);
        //这个拷贝文件也需要判定,为什么呢,因为如果有重复就会产生覆盖
       if(desfile.isFile()){
           System.out.println("拷贝文件名重复");
           return ;
       }
       //进行拷贝  try()  里面是可以放多个 字节流对象的 分号隔开
        try(InputStream inputStream =new FileInputStream(srcfile);
            OutputStream outputStream=new FileOutputStream(desfile)){
            //进行文件读操作
            while(true){
                int b=inputStream.read();
                if(b==-1){
                    break;
                }
                outputStream.write(b);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);  //这个异常其实可以删除了,删除了也不会影响
        } catch (IOException e) {
            throw new RuntimeException(e);  //前面的异常继承该异常 所以都是同一个在起作用
        }
    }

 运行结果及执行过程

4.3、查找包含某字符的文件

扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)

思路:

(1)第一步输入需扫描的文件路径  判定路径是否是目录

(2)创建一个List集合用来装包含这些字符的文件路径

(3)写一个深度优先遍历  因为给的当前路径也可能包含多个子目录,这里需要文件数组来接收当前文件列表该方法是 (listFiles),然后进行判定如果数组为空或者数组长度为0就递归返回,然后操作将文件分别进行判定是目录的就继续递归,如果不是就进行扫描是否有我们需要的字符出现(这里需要写一个方法来判定是否有这些字符)

(4)判定是否有这些字符的方法 采用思路:使用StringBuilder 来接收文件中的所有字符,然后判定如果该字符在StringBuilder对象中就返回true

注:以下三个代码是写在一个类中的,后面里两个是第一个代码中调用的自定义方法

public static void main(String[] args) throws IOException {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入要扫描的的根目录");
        String rootDirPath=scanner.next();
        //输入路径直接使用文件创建对象
        File rootdir=new File(rootDirPath);
        //判定当前文件是否是目录
        if(!rootdir.isDirectory()){
            System.out.println("您输入的根目录不存在或者不是根目录");
            return ;
        }
        System.out.println("请输入要找出的文件的字符");
        //输入字符即可 
        String token=scanner.next();
        //创建一个List集合是为了  接收包含字符的路径
        List<File> result=new ArrayList<>();
        //文件成树形结构  深度优先遍历
        scanDirWithContent(rootdir,token,result);
        //以下就是基础的打印方法,就不多介绍了
        System.out.println("共找到了符合条件的文件" + result.size());
        for(File f:result){
            System.out.println(f.getCanonicalPath());
        }
    }
private static void scanDirWithContent(File rootdir, String token, List<File> result) {
        //这里是用了一个文件列表的方法  listFile 返回的是一个数组 用文件数组接收
        File[] files=rootdir.listFiles();
        //判定文件是 为空返回  文件长度为0返回也就是啥都没有写
        if(files==null||files.length==0){
            return ;
        }
        //如果有文件 将文件分开分别判断
        for (File file: files){
            //如果是目录的话就再递归
            if(file.isDirectory()){
                scanDirWithContent(file,token,result);
            }else{
                //如果是文件 就要进行字符查找了, 写一个方法进行字符查找
                if(isContentContains(file,token)){
                    //如果查找到了就添加路径
                    result.add(file.getAbsoluteFile());
                }
            }
        }
    }
private static boolean isContentContains(File file, String token) {
        //这里采用StringBuilder是因为可变性
        StringBuilder sb=new StringBuilder();
        //字节流输入中放入文件路径    Scanner可以放入字节流 使用更多方法
        try(InputStream inputStream=new FileInputStream(file);
           Scanner scanner=new Scanner(inputStream,"UTF-8")){
            //这下就完事了,正常将每个字符接收到 StringBuilder对象中
            while(scanner.hasNextLine()){
                sb.append(scanner.nextLine());
                sb.append("\r\n");
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //返回这里不要感觉难 其实不难,查找找的字符串如果存在的话sb返回值就是一个正数数值 !=-1也就是true
        return sb.indexOf(token)!=-1;
    }

运行结果及执行过程:

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值