Java文件操作

1、文件的基本概念

平时说的文件一般都是指存储在硬盘上的普通文件,形如txt,jpg,mp4,rar等这些文件都可以认为是普通文件,它们都是在硬盘上存储的。

在计算机中,文件可能是一个广义的概念,就不只是包含普通文件,还可以包含目录(把目录称为目录文件),目录就是所谓的文件夹

操作系统中,还会使用文件来描述一些其他的硬件设备或者软件资源。例如操作系统就把网卡这样的硬件设备抽象成为文件,除此之外显示器,键盘、鼠标,操作系统也会把这些设备视为文件,这样做的好处就是为了简化开发。

站在程序员的角度,文件主要分为两大类

  1. 文本文件。里面存储的都是字符,不过文本文件的本质也是存放字节,但是相邻的字节在一起正好能构成一个个的字符。
    类似的,像日常中使用的.txt,.C,.C++,.java等都属于文本文件
  2. 二进制文件。里面存储的都是字节,字节之前完全没有任何关系。
    类似的,像.doc,.ppt,.exe,.zip,.class等都属于二进制文件

针对这两种文件,在编程的时候会存在差异

如何判定一个文件是文本文件还是二进制文件,有一种简单的方法:用记事本打开,如果打开是我们不认识的乱码,就是二进制文件,反之就是文本文件

文本文件:

在这里插入图片描述

二进制文件:

在这里插入图片描述

关于目录结构

在计算机里,保存管理文件,是通过操作系统中的文件系统这样的模块来负责的(Linux 下的文件系统主要有 ext2、ext3、ext4 等文件系统。Linux 还支持其他的 UNIX 文件系统,比如 XFS、JFS、UFS 等,也支持 Windows 的 FAT 文件系统和网络文件系统 NFS 等)

文件系统中,一般是通过"树形"结构来组织磁盘上的目录和文件,我们将这个结构称之为目录树。这里目录树并不是二叉的,而是N叉

在这里插入图片描述

如何在一个文件系统中找到一个具体的文件,操作系统就通过"路径"这样的概念,来描述一个具体文件/目录的位置

这里的路径就有两种描述风格(Windows下,Linux下也是差不多的)

1.绝对路径:以盘符开头
例如
B:\java\IntelliJ IDEA 2020.3.2\bin
D:\抖音\douyin-v1.0.8-win32-ia32-douyin.exe

2.相对路径:以.或者…开头,其中.表示当前路径,…表示当前路径的父目录(上级路径)
谈到相对路径,必须要限定一个基准目录,相对路径就是从基准目录出发,按照指示的路径找到对应文件
例如
以B:\java\IntelliJ IDEA 2020.3.2为基准目录,找到bin,./bin,此处的.就表示当前目录
以B:\java\IntelliJ IDEA 2020.3.2\bin为基准目录,找到B:java\IntelliJ IDEA 2020.3.2,…/,此处的…就表示基准目录的上级目录

即使定位到同一个文件,如果基准目录不同,此处的相对路径也是不同的

Linux中的路径分隔符(/作为分隔符)和Windows中的分隔符(\作为分隔符)是不同的

生活中也有相对路径和绝对路径的概念

在这里插入图片描述

当我在商城需要问路时,问工作人员奶茶店在哪里,工作人员的描述就有两种风格

绝对路径: 无论我站在商城的哪个位置,工作人员都按照从进入西门开始描述
例如,从进入西门开始,向前走50m,向右走200m,再向前走100,最后再向右走100m就能到达

相对路径: 根据我所处的位置进行不同的描述
例如我处在位置1,向右走200m,再向前走100,最后再向右走100m就能到达
处在位置2,向前走100,最后再向右走100m就能到达
处在位置3,向右走100m就能到达

2、java文件操作

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不代表真实存在该文件

2.1 File概述

File 类中的常见属性、构造方法和方法

属性

修饰符及类型属性说明
static StringpathSeparator依赖于系统的路径分隔符,String 类型的表示
static charpathSeparator依赖于系统的路径分隔符,char 类型的表示

构造方法

方法说明
File(File parent, Stringchild)根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, Stringchild)根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示

方法

修饰符及返回值类型方法说明
StringgetParent()返回 File 对象的父目录文件路径
StringgetName()返回 FIle 对象的纯文件名称
StringgetPath()返回 File 对象的文件路径
StringgetAbsolutePath()返回 File 对象的绝对路径
StringgetCanonicalPath()返回 File 对象的修饰过的绝对路径
booleanexists()判断 File 对象描述的文件是否真实存在
booleanisDirectory()判断 File 对象代表的文件是否是一个目录
booleanisFile()判断 File 对象代表的文件是否是一个普通文件
booleancreateNewFile()根据 File 对象,自动创建一个空文件。成功创建后返回 true
booleandelete()根据 File 对象,删除该文件。成功删除后返回 true
voiddeleteOnExit()根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行
String[]list()返回 File 对象代表的目录下的所有文件名
File[]listFiles()返回 File 对象代表的目录下的所有文件,以 File 对象表示
booleanmkdir()创建 File 对象代表的目录
booleanmkdirs()创建 File 对象代表的目录,如果必要,会创建中间目录
booleanrenameTo(Filedest)进行文件改名,也可以视为我们平时的剪切、粘贴操作
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

例1:获取文件名,父目录以及文件路径

public class Demo1 {
    public static void main(String[] args) throws IOException { //IOException表示在输入输出时出现了问题
        //和这种写法是一样的  "D:\\test.txt"
        //我的计算机中确实存在这个文件
        File f = new File("D:/test.txt");

        //获取到文件的父目录
        System.out.println(f.getParent());

        //获取文件名
        System.out.println(f.getName());

        //获取到文件路径(构造File的时候指定的路径)
        System.out.println(f.getPath());

        //获取文件的绝对路径
        System.out.println(f.getAbsolutePath());

        //这也是获取文件的绝对路径
        System.out.println(f.getCanonicalPath());
    }
}

结果
============
D:\
test.txt
D:\test.txt
D:\test.txt
D:\test.txt

例2:判断文件是否存在,是否为目录,是否为普通文件

public class Demo2 {
    public static void main(String[] args) {
        File f = new File("D:/test.txt");
        System.out.println(f.exists());//判断文件是否存在
        System.out.println(f.isDirectory());//判断文件是否是目录
        System.out.println(f.isFile());//判断文件是否是普通文件
    }
}

结果
=============
true
false
true

如果文件不存在,则都为false

例3:文件的创建和删除

public class Demo3 {
    public static void main(String[] args) throws IOException {
        //文件的创建和删除
        File f = new File("D:/test.txt");
        f.delete();
        System.out.println("删除文件成功");
        System.out.println(f.exists());
        System.out.println("创建文件");
        f.createNewFile();
        System.out.println("创建文件完成");
        System.out.println(f.exists());
    }
}

结果
======================
删除文件成功
false
创建文件
创建文件完成
true

例4:创建单级目录和多级目录

public class Demo5 {
    public static void main(String[] args) {
        //创建单级目录
        File f = new File("./aaa");
        f.mkdir();
        System.out.println("创建单级目录成功");
        System.out.println(f.isDirectory());

        //创建多级目录
        File f1 = new File("./aaa/bbb/ccc");
        f1.mkdirs();
        System.out.println("创建多级目录成功");
        System.out.println(f1.isDirectory());
    }
}

结果
===============
创建单级目录成功
true
创建多级目录成功
true

2.2 InputStream 和 FileInputStream

InputStream

修饰符及返回值类型方法说明
intread()读取一个字节的数据,返回 -1 代表已经完全读完了
intread(byte[] b)最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表以及读完了
intread(byte[] b, int off, int len)最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了
voidclose()关闭字节流

InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基
本可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使
用 FileInputStream

FileInputStream

构造方法说明
FileInputStream(File file)利用 File 构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流

例5:以字节流的方式读取文件,一次读取一个字节

public class Demo8 {
    public static void main(String[] args) {
        //构造方法中需要指定打开的文件路径
        //这里的路径可以是绝对路径,也可以是相对路径,还可以是File对象
        try {
            //1.创建对象,同时也是在打开文件
            InputStream inputStream = new FileInputStream("D:/test.txt");
            //2.尝试一个一个字节的读,把整个文件读完
            while (true) {
                int b = inputStream.read();
                if (b == -1) {
                    //-1表示读到了文件末尾
                    break;
                }
                System.out.print(b + " ");
            }
            //3.读完之后,需要关闭文件
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//文件中存放的是字符abcdef
结果
===========
97 98 99 100 101 102 

在这里插入图片描述

这个代码还有一个缺陷:如果在执行read过程中抛出异常了,就会直接触发catch代码,从而导致close无法执行
更好的做法就是把close放在final里面

例6:

public class Demo8 {
    public static void main(String[] args) {
        //构造方法中需要指定打开的文件路径
        //这里的路径可以是绝对路径,也可以是相对路径,还可以是File对象
        InputStream inputStream = null;
        try {
            //1.创建对象,同时也是在打开文件
            inputStream = new FileInputStream("D:/test.txt");
            //2.尝试一个一个字节的读,把整个文件读完
            while (true) {
                int b = inputStream.read();
                if (b == -1) {
                    //-1表示读到了文件末尾
                    break;
                }
                System.out.print(b + " ");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.读完之后,需要关闭文件
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

改进之后,代码是稳妥了,但是整体显得太繁琐。
Java中提供了一个语法:try with resources

例7:

public class Demo8 {
    public static void main(String[] args) {
        try(InputStream inputStream = new FileInputStream("D:/test.txt");) {
            while (true) {
                int b = inputStream.read();
                if(b == -1) {
                    break;
                }
                System.out.println(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果
==========
97 98 99 100 101 102

在这个代码中,我们并没有显示的调用close,但try会帮我们自动调用,当代码执行完成这里的try语句块之后,就会自动调用close。在try()中,也不是随便什么都能填,只有实现了Closeable接口才能放在try()中,所有的流对象都实现了Closeable接口,所以可以直接放

例8:一次读取若干字节

public class Demo8 {
    public static void main(String[] args) {
    	try(InputStream inputStream = new FileInputStream("D:/test.txt");) {
            //一次读取若干个字节
            while(true) {
                byte[] buffer = new byte[1024];
                //将读取到的数据放在buffer中
                //len表示实际读取到的字节数
                int len = inputStream.read(buffer);
                if(len == -1) {
                    break;
                }
                for(int i = 0; i < len; ++i) {
                    System.out.print(buffer[i] + " ");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果
=============
97 98 99 100 101 102 

inputStream.read(buffer)中的buffer称为输出型参数,这个操作在Java中很少见,但在C/C++中很常见

每次读取磁盘都是比较低效的操作,能一次多读点是更好的

2.3 OutputStream 和 OutputStreamWriter

OutputStream

修饰符及返回值类型方法说明
voidwrite(int b)写入要给字节的数据
voidwrite(byte[]b)将 b 这个字符数组中的数据全部写入 os 中
intwrite(byte[]b, int off,int len)将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
voidclose()关闭字节流
voidflush()刷新缓冲区

OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,
所以使用 FileOutputStream

例9:一次写一个字节

public class Demo9 {
    //使用字节流,写文件案例
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("D:/test.txt")) {
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

例10:一次写多个字节

public class Demo9 {
    //使用字节流,写文件案例
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("D:/test.txt")) {
            byte[] buffer = new byte[]{97,98,99};
            outputStream.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

按上述写方式打开文件,无论是一次写一个字节,还是一次写多个字节,都会清空原有文件的内容,清空旧的内容,再从起始位置往后写

还有一种用于追加写的流对象,打开之后不清空,从文件末尾开始写
OutputStream outputStream = new FileOutputStream(“D:/test.txt”, true)
第二个参数表示是否追加,true表示追加,默认为false

例11:按照字符读取

ublic class Demo10 {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("D:/test.txt")) {
            //按照字符来读写
            while (true) {
                char[] buffer = new char[1024];
                int len = reader.read(buffer);
                if(len == -1){
                    break;
                }
                //如果这里传入的是byte数组,还可以手动指定一下utf8字符集,避免乱码
                String s = new String(buffer, 0, len);
                System.out.println(s);
            }
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

例12:

public class Demo11 {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("D:/test.txt")) {
            writer.write("xyz");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值