JAVA文件IO, File类, 字符流,字节流

文件IO

I: Input, 从硬盘往内存读数据

O: Output, 从内存往硬盘输出数据

1. File

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

构造方法

方法说明
File(File parent, String child)根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child)根据父目录 + 孩子文件路径,创建一个新的 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(File dest)进行文件改名,也可以视为我们平时的剪切、粘贴操作
booleancanRead()判断用户是否对文件有可读权限
booleancanWrite()判断用户是否对文件有可写权限

代码示例

public static void main(String[] args) throws IOException {
    File file1 = new File("D/text.txt");
    System.out.println(file1.getName());
    System.out.println(file1.getParent());
    System.out.println(file1.getPath());
    System.out.println(file1.getAbsolutePath());
    System.out.println(file1.getCanonicalPath());
    
    System.out.println("===========================");
    
    File file2 = new File("./text.txt");
    System.out.println(file2.getName());
    System.out.println(file2.getParent());
    System.out.println(file2.getPath());
    System.out.println(file2.getAbsolutePath());
    System.out.println(file2.getCanonicalPath());
}

输出

text.txt

D:\

D:\text.txt

D:\text.txt

D:\text.txt

===========================

.

.\text.txt

D:\JAVA\java\system_code.\text.txt

D:\JAVA\java\system_code\text.txt

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());
}

输出

true

true

false

===========================

true

true

false

public static void main(String[] args) throws IOException {
    File file = new File("./text.txt");
    System.out.println(file.exists());
    file.delete();
    System.out.println("文件已删除");
    System.out.println(file.exists());
}

输出

false

文件已删除

false

public static void main(String[] args) throws IOException {
    File file = new File("text.txt");
    System.out.println(file.exists());
    //等到程序结束前再删除
    file.deleteOnExit();
    System.out.println(file.exists());
}

输出

true

true

public static void main(String[] args) {
    File file = new File("./testDir");
    file.mkdir();
    System.out.println(file.exists());
    System.out.println(file.isDirectory());
    
    File file1 = new File("./testDir/aaa/bbb/ccc");
    file1.mkdirs();
    System.out.println(file1.exists());
    System.out.println(file1.isDirectory());
}

输出

true

true

true

true

public static void main(String[] args) {
    File file = new File("./test.txt");
    File file1 = new File("./testRename.txt");
    
    System.out.println("file是否存在: " + file.exists());
    System.out.println("file1是否存在: " + file1.exists());
    
    System.out.println("renameTo执行是否成功: "+file.renameTo(file1));
    
    System.out.println("file是否存在: " + file.exists());
    System.out.println("file1是否存在: " + file1.exists());
}

输出

file是否存在: true

file1是否存在: false

renameTo执行是否成功: true

file是否存在: false

file1是否存在: true

public static void main(String[] args) throws IOException {
    File file = new File("./test.txt");
    File file1 = new File("./src/test2.txt");

    System.out.println("file是否存在: " + file.exists());
    System.out.println("file1是否存在: " + file1.exists());

    System.out.println("file的路径" + file.getCanonicalPath());

    System.out.println("renameTo执行是否成功: "+file.renameTo(file1));

    System.out.println("file是否存在: " + file.exists());
    System.out.println("file1是否存在: " + file1.exists());

    System.out.println("file1的路径" + file1.getCanonicalPath());

}

输出

file是否存在: true

file1是否存在: false

file的路径D:\JAVA\java\system_code\test.txt

renameTo执行是否成功: true

file是否存在: false

file1是否存在: true

file1的路径D:\JAVA\java\system_code\src\test2.txt

2. IO流

将硬盘中的数据比喻为池中的水

往池中加水, 相当于数据从内存往硬盘中流动, 称作输出流

从池中放水, 相当于数据从硬盘往内存中流, 称作输入流

IO流可以分为 字节流 , 字符流 两大类

这些类都有各自不同的特性, 但是使用方法还是类似的:

  1. 构造方法: 打开文件

  2. close方法: 关闭文件

    close方法一定要执行到, 如果使用完不关闭, 就会导致文件资源泄露 (尤其是在7*24小时运转的服务器上) 进而导致文件都打不开, 使服务器宕机.

    如何保证close方法一定能执行的到呢?

    1. 使用try-finally, 将close写入finally代码块

    2. 使用try with resources创建流对象. 例如

    try (Reader reader = new FileReader("D:/test.txt");
         Reader reader1 = new FileReader("");
         Reader reader2 = new FileReader("");
         ...) {
    	//代码
    }
    

    只要try代码块执行结束, 就会自动调用close方法.

  3. 如果衍生自InputStream或者Reader, 就可以使用read方法读文件

  4. 如果衍生自OutputStream或者Writer, 就可以使用write方法写文件

2.1 字符流

字符流, 顾名思义, 以操作字符为单位, 针对文本文件

2.1.1 Reader

read方法

方法作用返回值
int read()一次读一个字符以int类型返回读到的字符. 如果返回值为-1, 表示文件已经读完, 或者读到EOF.
int read(char cbuf[])一次读若干个字符, 并把读到的内容填充到cbuf[]中返回实际读到的字符个数
int read(char cbuf[], int off, int len)从第off个字符开始, 将字符读入数组, 一共读len个读取的字符数,如果已到达流的结尾,则返回-1

代码案例

public static void main(String[] args) throws IOException {
    try (Reader reader = new FileReader("D:/test.txt")) {
        while (true) {
            char[] buf = new char[1024];
            int n = reader.read(buf);
            if(n == -1) {
                break;
            }
            for (int i = 0; i < n; i++) {
                System.out.print(buf[i] + " ");
            }
        }
    }
}

在这里插入图片描述

2.1.2 Writer

write方法

方法说明
void write(int c)写入单个字符。
void write(char cbuf[])写入字符数组。
void write(char cbuf[], int off, int len)写入字符数组的一部分。cbuf -字符数组off -开始写入字符的偏移量len -要写入的字符数
void write(String str)写入字符串
void write(String str, int off, int len)写入字符串的一部分。str -字符串off -开始写入字符的偏移量len -写入字符的数目

代码示例

public static void main(String[] args) throws IOException {
    try(Writer writer = new FileWriter("D:/test.txt")) {
        writer.write("hello java");
    }
}

在这里插入图片描述

这里可能就会有疑问了, 文件里面之前的内容呢?

输出流对象(无论字节流还是字符流), 再打开文件之后, 清空文件内容.

如果不想被清空, 那就使用追加写方式打开文件.

Writer writer = new FileWriter("D:/test.txt", true)

在构造方法上, 写一个true, 便可

public static void main(String[] args) throws IOException {
    try(Writer writer = new FileWriter("D:/test.txt", true)) {
        writer.write("hello world");
    }
}

在这里插入图片描述

2.2 字节流

字节流, 顾名思义, 以操作字节为单位, 针对二进制文件

2.2.1 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

2.2.2 FileInputStream

构造方法

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

代码示例

public static void main(String[] args) {
    try(InputStream inputStream = new FileInputStream("D:/test.txt")) {
        while (true) {
            byte[] bytes = new byte[1024];
            int n = inputStream.read(bytes);
            if (n == -1) {
                break;
            }
            for (int i = 0; i < n; i++) {
                System.out.printf("%x ", bytes[i]);
            }
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

在这里插入图片描述

读到的字符, 我们更期望的是把他转化成字符串, 更直观. 所以我们可以借助一些额外的工具类, 就可以完成从字节/字符到字符串的转换.

一. 是使用String的构造方法. 但这种方式不够优雅.

String s = new String(bytes, 0, n, "utf8");
System.out.println(s);

在这里插入图片描述

二. 是Scanner.

2.2.3 利用Scanner进行字符读取

我们来看一下Scanner的构造方法

在这里插入图片描述

其中, 构造方法的参数中有InputStream, 也就是说我们可以往里面传字节流. 实际上, 我们经常写的new Scanner(System.in)中的in也是一个字节流

在这里插入图片描述

其实在操作系统中, "文件"是一个广义的概念

  • System.in是一个特殊的文件, 对应到"标准输入"
  • 硬盘上的文件, 也是文件
  • 网卡(socket), 也是文件

Scanner都是一视同仁的, 只是把当前读到的字节数据进行转换, 不关心这个数据的来源.

那么上述读取文件的代码就可以这样写了

public static void main(String[] args) throws IOException {
    try(InputStream inputStream = new FileInputStream("D:/test.txt")) {
        Scanner scanner = new Scanner(inputStream);
        //Scanner scanner = new Scanner(inputStream, "utf8");
        //从文件中读取
        while (scanner.hasNext()) {
            String s = scanner.next();
            System.out.print(s + " ");
        }
    }
}

在这里插入图片描述

但是Scanner只适合读取文本文件, 不适合读取二进制文件

2.2.4 OutputStream

方法

返回值类型方法说明
voidwrite(int b)将指定字节写入此输出流。
voidwrite(byte[] b)将 b 这个字节数组中的数据全部写入 os 中
voidwrite(byte b[], int off, int len)将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
voidclose()关闭字节流
voidflush()刷新此输出流并强制写出任何缓冲的输出字节。

我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。

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

所以使用 FileOutputStream

OutputStream 的使用方法和Writer完全一样, 只不过不能写入字符, 字符串.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是布谷阿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值