文件的IO

一、文件的定义

狭隘的文件:指你的硬盘上的文件和目录.
广义的文件:泛指计算机中的硬件资源,操作系统中,把很多硬件设备和软件资源都抽象成了文件,按照文件的形式统一管理.比如网卡,操作系统也是把网卡抽象成了文件资源,所以说操作网卡其实和操作文件的方式是基本一样的.

而我们本章节只考虑狭义的文件.

二、路径

路径分为:绝对路径和相对路径

    • 绝对路径:C:\Program Files\Java\jdk1.8.0_192

这样的路径就叫做绝对路径.

2.相对路径:以当前目录为基准,以.或者..开头(.有时候可以省略),找到指定路径.

当前目录在程序运行中被称为工作目录.

打开控制台,默认的工作路径就是:

如这个:想要定位111这个文件夹,我们就可以使用相对路径定位法.

此时工作目录就是"d:/tmp"

则111文件夹的相对路径就是:"./111".

但如果工作目录是"d:/tmp/222"

那么相对路径就是"../111"(注意:这里的".."指的是返回上一级目录)

三、文件的类型

现在的市面上有众多的文件:word、exe、图片、视频、音频......

这些不同的文件,可以归到两类的文件里去:
    • 文本文件(存的是文本,字符串)
    • 二进制文件(存的是二进制文件,不再是字符串了)

检验方式:直接用记事本打开文件,如果乱码了就是二进制文件,如果能够正常读取,就是文本文件.(因为记事本是以文本文件的方式进行存储)

另外,文本文件和二进制文件的操作方式是不同的.

四、Java对于文件的基本操作

1.

这个就相当于路径中的"/",如果代码需要进行多语言的运行,有的语言没有"/"的识别,则需要pathSeparator进行分割.

2.构造方法

最常见的构造方法指定路径的方法是第二个:使用文件的直接路径进行调用.

3.常用方法

构造方法中的文件路径不需要真实存在,因为File中有方法可以对文件进行手动创建文件.

就是这个方法:

绝对路径:

File类的方法都是"人如其名"

另外,在文件IO这块很容易抛出异常,因为文件是存放在硬盘中的,而硬盘是电脑中最容易出问题的部分了(如坏了或者说硬盘满了).

相对路径:

注意:这里的文件路径是在Jvm包中的test.txt,也就是在

这个工作路径下的"test.txt"

这里着重说一下getAbsolutePath()与getCanonicalPath()两个方法,他们都是获取文件的绝对路径,只不过

getAbsolutePath()是获取不加修饰的文件绝对路径,而getCanonicalPath()是获取经过修饰的绝对路径.

在此时,Idea的目录下面没有创建"test.txt",所以说判断是否存在是否是文件是否是目录都是false

在手动创建完文件后,是否存在,是否是文件都是true是否是目录都是false.

我们可以创建文件当然也可以删除文件:

另外,还有一个deleteOnExit作用是:能够在程序结束的时候将这个文件删除.

(被称为临时文件)

比如我们在打开word文档时就会生成一个临时文件:

关闭目录后就会消失.

这个临时文件相当于实时保存了你文件中的内容,如果硬盘损坏或者断电了,没有保存的内容就没了.

目录的创建:

运用file.mkdirs()

mkdirs()可以创建多级目录.

文件重命名:

这样就可以把之前的"test"文件夹改名为testAAAAAAAA.

五、"流"对象

1."流"的概念

针对文件内容,使用"流对象"进行操作.

什么叫做"流对象":类比水流,就是指对文件的操作就好比水流一样,想流多少,就流多少.

就是说编译器操作文件也是一样,想读多少,就读多少.假如共有100个字节,我想读100个就读1次,我想读10个就读10次.

    • 操控"流"对象

操控"流"对象,总共分为两大类:

1)字节流:(操作二进制文件的)

主要的两个类:InputStream、OutputStream 子类:FileInputStream、FileOutputStream

注意:InputStream类是不能new的,因为InputStream类是个抽象类.

首先是开与关:

然后就是如操作了:

我们的读操作有三个版本:

无参数版本:一次读一个字节.

一个参数版本:把读到的内容存到这个数组里,(此处参数是输出型参数),返回值是读取到的字节数

三个参数版本:和2类似只不过是在一定空间里尽可能填满数组.

注意:虽然read读取的是一个字节,但它的返回值是int

原因:当read读完文件时,就会返回-1,来表示文件已经读完.

结果返回的是字符,返回的数字可以用ASCII进行转换成对应的字符.

另外,还可以利用字节流读取的另外一种方式:(使用在read中填写字符数组的形式读取)

我们发现和上面的结果是一样的.

这里的传参操作,相当于把刚才准备好的数组将给read方法,让read方法内部针对这个方法进行填写.

此处的参数相当于"输出型参数".

在Java中通常是把输入的信息作为参数,输出的信息作为返回值.但也有少数情况,是使用参数来返回内容的(输出型参数),但这是在C++中很常见.

inputStream.read()的本质是的读取字节,如果在读取的过程中发现读不到内容后才返回-1.上述代码设置了数组的最大阅读长度:1024.

如果读取的内容长度大于1024,程序则会覆盖之前读的内容继续读取,直到返回-1.

所以说文件操作一般都是读一部分处理一部分,不会等文件全部多玩再进行处理.


这里回忆一下抽象类和接口有什么区别:

抽象类和普通类:几乎没有区别,只不过抽象类不能够new而且带了抽象方法

接口比抽象类更加抽象,抽象:指信息的描述更加少.

抽象类还可以有普通成员,普通方法,抽象成员,抽象方法,但是接口就只能有抽象方法和抽象成员.


我们可以用intputStream读文件,也可以用outputStream写文件:

这里采用控制台循环输入的方式如果输入-1就停止.

注意:对于我们的OutputStream来说,默认情况下,会清空文件原有的内容.(这样的话之前的内容就没了)

如果我们不想清空之前的内容,流对象还提供了一个"追加写"对象,通过这个就可以实现不清空文件,把新的内容写到后面.

这里再说一下close()操作:

在我们多线程的PCB运行过程的同时,会运行一个文件描述符表(就是一个可以存放表的数组),这个表会记录每个线程打开的文件(这也是多线程进行信息交互的方式之一)打开文件操作会申请一个位置用来存放这个表,每次关闭文件,也就会把表从这个文件描述符表中释放掉.

如果我们不释放,会发生什么呢?

注意:文件描述符表这个数组是不会扩容的,虽然有自动释放功能,但可能不够即使及时,一但文件描述符表满了文件打开操作就会发生错误,导致程序崩溃.

但是,因为close()常见操作(就是如果出现if+break)之类的问题所以我们的常见操作是:

这是我们推荐的操作,在Java中被称为try with resources,在这个代码虽然没有显式的close,但是当try的部分执行完毕后,就可以自动执行到close的!!!

点入OutputStream中去,发现该类实现了Closeable接口,这个方法就是提供了close().

try with resources是文件IO中最方便的表述形式,所以我们后面讲全部采用这种形式.

2)字符流:(操作文本文件的)

主要的两个类:Reader、Writer 子类:FileReader、FileWriter

这些类的操控都是相对固定的,主要分为四个操作:1.打开文件(构造对象)2.关闭文件(close)3.读文件(read)针对InputStream、Reader4.写文件(write)针对OutputStream、Writer

跟上面一样的代码形式,作用是读取字符

因为汉字也是用字符表示的,所以也可以读取汉字.

写入方法也是一样:

这个我们来说一下Scanner:

如果我们点入System可以发现其实System也是一个流对象

所以说,按道理来讲我们将inputStream对象填入括号中也是可以的.

Scanner控制台就读取控制台内容,Scanner文件就读取文件内容,Scanner能读取所有的流对象.

六、案例

1.扫描目录,并找到名称中包含的指定字符所有普通文件(不包含目录),并且询问用户是否要删除该文件.

就相当于:

首先,做好准备工作,将代码的输入路径和指定删除文件部分完成:

接下来,完成目录的扫描能力部分:

我们首先要弄清目录是以书的形式存储的,对应的我们在遍历目录的时候可以使用递归的形式.如果是要删除文件,就删除,如果不是就下一个

这个代码要注意几点:

  1. 将输入的根目录一下的不管是目录还是文件都放入File[ ]数组,便于之后遍历数组.

  1. 判断是不是目录,如果是就继续递归,如果不是就将文件名和要删除文件进行比对,如果比对成功就删除.

  1. 在比对的过程中需要对用户进行询问,如果用户同意再删除,如果不同意就取消删除.

package IODemo6;

import java.io.File;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86139
 * Date: 2023-01-29
 * Time: 17:53
 */
public class IODemo8 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入要查找的路径:");
        String path=scanner.next();
        File root=new File(path);
        if(!root.isDirectory()){
            System.out.println("您输入的路径有误!!!");
            return;
        }
        System.out.println("请输入您要删除的文件名:");
        String filename=scanner.next();
        scanDir(root,filename);
    }

    private static void scanDir(File root, String filename) {
        File[] files=root.listFiles();
        if(files==null){
            return ;
        }
        for (File f:files) {
            if(f.isDirectory()){
                scanDir(f,filename);
            }else{
                if(f.getName().contains(filename)){
                    System.out.println("是否删除"+f.getAbsolutePath()+"文件");
                    Scanner scanner=new Scanner(System.in);
                    String choice=scanner.next();
                    if(choice.equals("y")||choice.equals("Y")){
                        f.delete();
                        System.out.println("删除成功!!!");
                    }else{
                        System.out.println("删除取消!!!");
                    }
                }
            }
        }
    }
}

2.进行普通文件的复制(就是把一个文件拷贝成另一个文件,把第一个文件按照字节的方式进行读取,然后拷贝到第二个文件里)

首先,进行文件的读取与判断:

接下来,打开源文件的输入流对象和目标文件的输出流对象:

然后我们采取读一个字节,写一个字节的形式进行拷贝:

这样代码就完成了.

我们发现拷贝成功了!!!

package IODemo6;

import java.io.*;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86139
 * Date: 2023-01-29
 * Time: 18:35
 */
public class IODemo9 {
    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("您输入的源文件有误!!!");
        }
        File destFile=new File(destPath);
        try(InputStream srcInputStream=new FileInputStream(srcFile);
        OutputStream destOutputStream=new FileOutputStream(destFile)) {
            while(true){
                int b=srcInputStream.read();
                if(b==-1){
                    break;
                }
                destOutputStream.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:这里的outputStream能够无中生有,不需要目标文件存在.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值