JavaSE篇:文件IO

一 认识文件

在硬盘这种持久化存储的I/O设备或其他存储介质中 ,当我们想要进行数据保存时,往往不是保存成⼀个整体,⽽是独⽴成⼀个个的单位进⾏保存,这个独⽴的单位就被抽象成⽂件的概念。就类似办公桌上的⼀份份真实的⽂件⼀般。
⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数据⽽存在。

1.1 文件路径

文件路径就是描述一个文件在文件系统中的唯一标识,文件路径分为绝对路径和相对路径。绝对路径:从文件系统根目录开始定位某文件的具体位置的一个路线就是绝对路径。相对路径:以当前所在目录路径为基准,定位目标文件的路线。

1.2 文本文件与二进制文件

即使是普通⽂件,根据其保存数据的不同,也经常被分为不同的类型,我们⼀般简单的划分为⽂本文件和⼆进制⽂件。任何数据都以二进制形式存储在磁盘上,普通文件和二进制文件的主要区别在于它们的 内容格式。普通文件也要通常被如 UTF-8、ASCII编码集合(编码集合:一套普通字符映射二进制指令的规则)转换,是可以通过查表可以知道原数据内容,但是二进制文件存储在磁盘的内容是特殊的二进制数据,内容只能借助第三方工具。

二 Java中操作文件

Java操作对象分为:1)针对文件系统进行操作(创建目录,删除目录等),2)针对文件内容操作。Java 中通过 java.io.File 类来对⼀个⽂件(包括⽬录)进⾏抽象的描述。

2.1 File类概述

File类可认为是对文件(目录也是文件)的属性信息进行一些操作。

2.1.1 File类的构造函数

File类的构造函数
函数说明
File(File parent, String child)
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例
File(String pathname)
根据⽂件路径创建⼀个新的 File 实例,路径可以是绝 对路径或者相对路径
File(String parent, String child)
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实 例,⽗⽬录⽤路径表⽰

最常用的是第二种,简单明了。

2.1.2 File类提供的方法 

修饰符及返回值类型
函数说明
String
getParent()
返回 File 对象的⽗⽬录⽂件路径
String
getName()
返回 FIle 对象的纯⽂件名称
String
getPath()
返回 File 对象的⽂件路径
String
getAbsolutePath()
返回 File 对象的绝对路径
boolean
exists()
判断 File 对象描述的⽂件是否真实 存在
boolean
isDirectory()
判断 File 对象代表的⽂件是否是⼀
个⽬录
boolean
isFile()
判断 File 对象代表的⽂件是否是⼀
个普通⽂件
String[]
list()
返回File对象代表的目录下所有的文件名
File[]
listFiles()
返回 File 对象代表的⽬录下的所有
⽂件,以 File 对象表⽰

import java.io.File;

public class dirio {
    public static void main(String[] args) {
        File file = new File("D:/test.txt");
        System.out.println(file.getName());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());
    }
}

以上的函数并不是File类中的所有函数。这些方法都是JVM封装操作系统提供的API实现的。JVM是由C++实现的, 对于所有系统下,比如:Windows,Linux,都是统一的。都是使用这一套函数,因为JVM做了封装。程序员在使用时不用考虑兼容问题。

 三 文件内容的读写⸺数据流

Java中通过“流”这样的一组类进行对文件内容的操作,文件读写像流水一样。“流”分为两种,字节流和字符流。字节流是以字节为基本单位读写数据,有InputStream,OutputStream。字符流是以字符为基本单位读写数据,有Reader,Writer。

3.1 InputStreamのFileInputStream读取数据

 查看InputStream可知,InputStream类被abstract修饰,证明这是一个抽象类,想使用它要自己定义类重写抽象方法。标准库中,已经实现了InputStream的的子类,不仅仅有对磁盘文件的读取的子类,也有从网卡读取的子类(PipedInputStream)等等。标准库实现对磁盘文件读取的子类是FileInputStream。

使用方法很简单,1)调用构造函数创建FileInputStream对象 2)调用FileInputStream类实现的函数完成读取操作

FileInputStream的构造函数有两种。

 FileInputStream会抛受查异常(编译时异常)FileNotFoundException, FileNotFoundException 是 Java 中的一个异常,表示试图打开一个不存在的文件或路径。它是 IOException的子类。IOException 是 Java 中的一个异常类,表示在进行输入输出操作失败或被中断。它是所有输入输出异常的父类。

接下来调用FileInputStream的read方法,即可读取对应文件的数据。read方法有三种格式。

3.1.1 read无参版本

1)第一种无参版本,每次只读一个字节,读取到的内容通过返回值返回,如果读取不到返回-1,返回值不用byte而是用int,是因为byte范围是从-128-127,如果读取失败,无法通过返回值告知。所以采用了int。

import java.io.*;

public class dirio {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");

        FileInputStream fileInputStream = new FileInputStream("D:/test.txt");
        while (true) {
            int res = fileInputStream.read();
            if (res == -1)
                break;
            System.out.printf("%c", res);
        }
    }
}

 

为什么不用short而是用int,使用short不是可以省下2个字节吗?

short和float是上个世纪80,90时代使用的,那时候还是采用的16位CPU,内存紧张。如今硬件设备发展迅速,已经不在乎2个字节的消耗,而且就算使用short,如今使用的32位CPU也会将short整形提升为int。float精度太低,容易造成误差,所以更不用了。

3.1.2 read单参数版本

read(byte[ ]),byte[ ]是一个输出型参数。对,就是C++中的那个输出型参数,这种方式在C++中是很常用的,但是在Java中是不常用的。读取到的结果回被存储在传进去的byte数组中。返回值是实际读取到了多少个字节。

import java.io.*;

public class dirio {
    public static void main(String[] args) throws IOException {
        try (InputStream is = new FileInputStream("D:/test.txt")) {
            byte[] buf = new byte[1024];
            int len = 0;
            while(true) {
                len = is.read(buf);
                if (len == -1) {
                    // 代表⽂件已经全部读完
                    break;
                }
                for (int i = 0; i < len; i++) {
                    System.out.printf("%c", buf[i]);
                }
            }
        }
    }
}

3.1.3 read三参数版本

read(byte[ ],int off,int len) 从off下标开始读取len个长度字节存储在byte数组中。

3.2 关闭文件

使用FileInputStream读取文件,在操作系统中,其实是会在进程PCB的文件描述符表中的数组中占一个位置,这个数组的长度是有一定限度的,如果这个数组被占满了再打开文件就放不下了,这个进程就崩溃了,服务器是7×24小时运行的,所以不能崩,要及时手动关闭打开的文件,避免文件资源泄露。在Linux上,ulimit -n可以查看这个数组的大小。如果怕忘记了,可以借助try语句。try with resources。在try后面跟一个圆括号,资源会在 try 块结束后自动关闭,减少了代码中的冗余。

import java.io.*;

public class dirio {
    public static void main(String[] args) throws IOException {
        try (InputStream is = new FileInputStream("D:/test.txt")) {
            ,,,,,,
        }
    }
}

3.3 OutputStreamのFileOutputStream写入数据

OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件
中,所以使⽤ FileOutputStream。OutputStream和FileOutputStream的关系和InputStream和FileInputStream的关系一样。构造方式也是一样的。
FileOutputStream的write版本也有三个,

注意:在构造时候,默认是清空内容再写入,如果想追加,则构造时候,加一个true。

3.3.1 write无参版本

一次写入一个字节,它的参数类型是int。在 Java 中,int的范围是 -2,147,483,648 到 2,147,483,647,而字节的范围是 0 到 255。将一个字节(0-255)转换为int,可以用int 表示这个字节的值,方便地进行位运算。如果直接使用 byte 类型作为参数,可能会引起一些混淆,因为 byte 是有符号的(-128 到 127)。通过使用 int,你可以在方法内部更容易地处理和转换数据。

import java.io.*;
public class Main {
 public static void main(String[] args) throws IOException {
     try (OutputStream os = new FileOutputStream("output.txt")) {
         os.write('H');
         os.write('e');
         os.write('l');
         os.write('l');
         os.write('o'); 
         }
    }
}

3.3.2 write单参数byte数组

import java.io.*;

public class dirio {
    public static void main(String[] args) throws IOException {

        try(FileOutputStream os = new FileOutputStream("D:/test.txt",true)) {
            byte[] b = new byte[] { 'G', 'o', 'o', 'd' };
            os.write(b);
        }
    }
}

3.3.3 write三参数版本

import java.io.*;

public class dirio {
    public static void main(String[] args) throws IOException {

        try (OutputStream os = new FileOutputStream("D:/test.txt")) {
            byte[] b = new byte[] {'G','o', 'o','d','B','a'};
            os.write(b, 0, 4);
        }
    }
}

三 总结

文件IO类还有很多,使用方法大同小异。基本都是有一个父类,再根据不同的场景封装不同的系统调用。对于文件IO基本就有三步1)打开文件(构造)  2)读写  3)关闭文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值