JavaEE——文件操作与IO操作

目录

文件路径

文件类型

File类

文件的创建

文件流

File类文件读写操作

通过PrintWriter写或Scanner读

PrintWriter写

Scanner读


文件路径

计算机中的文件是以树形结构进行存储的。要找一个文件,需要通过根目录一层一层找,直到找到,这个路径是唯一确定的,因此这整个查找路径称为绝对路径。如果在任意层(非根目录)目录下开始寻找,那么这个路径称为相对路径

例如要查找office这个文件:

绝对路径:C:\Program Files (x86)\Microsoft Office\Office

相对路径(从Microsoft Office开始):.\Office

.\代表从当前目录开始查找,..\代表从当前目录的上一层开始查找。

在编译器上输入路径时,可以使用'/'代替'\',系统可以自动识别。'\'与其他字符搭配会成为转义字符,如果要用'\'输入路径,那么每次输入'\'都要输入两次,譬如上述绝对路径应改为:C:\\Program Files (x86)\\Microsoft Office\\Office

文件类型

文件通常简单的分为文本文件二进制文件

文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等。

 二进制文件是基于值编码的文件,你可以根据具体应用,指定某个值是什么意思,也就是可以自定义编码。

要区分文本文件和二进制文件,只需要把内容拷贝到记事本上,通过观察是否出现乱码进行判断。如果没有乱码则是文本文件,乱码则代表是二进制文件。

例如把一个新建的word文件拖到记事本中,就会出现乱码:

JavaEE——文件操作与IO操作_第1张图片

 由此可见word是二进制文件,记事本无法翻译,要想翻译这样的文件,首先要知道它的编码格式,而记事本只会按照特定的编码格式进行翻译,翻译不出来的就会用某些符号代替——这也是出现乱码的原因。

File类

文件的创建

File类有三种构造方法: 

File(File parent,String child) 根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname) 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child)

根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示

new出来的文件并不一定实际存在,只是获得了一个实例对象。可以通过exists方法进行判断文件是否存在。

File file = new File("./hello-world.txt");//实际上没有这个文件
System.out.println(file.exists());//输出false

File类的方法比较简单,基本可以通过方法名直接推断出其功能,例如getName(获取文件名),getPath(得到相对路径),getAbsolutePath(得到绝对路径),getCanonicalPath(得到绝对路径),isFile(是否为文件),isDirectory(是否为目录),createNewFile(文件不存在时,以当前路径创建一个文件)等等……

文件流

文件的输入输出操作是通过文件流实现的。按照文件的内容,大体分为了两类读取方式:一类使用字节流,用于二进制文件读写,一类使用字符流,用于文本文件的读写。

JavaEE——文件操作与IO操作_第2张图片

File类文件读写操作

Filie文件的读写,不能直接使用这些抽象类,需要使用继承于他们的FileInputStream、FileOutputStream、FileRead和FileWriter类

字节流读:FileInputStream

通过read方法进行读数据,read方法有三个版本:

JavaEE——文件操作与IO操作_第3张图片

 无参版本表示读取一个字节,有一个参数表示把读取的数据放到该数组中,三个参数的版本是从文件第off位置读取len长度个字节,读取结果放到目标数组中。

标准的读操作:

public static void main(String[] args) throws IOException {
    File file = new File("hello.txt");
    InputStream inputStream = null;
    try {
        inputStream = new FileInputStream(file);
        while (true) {
            //每次读取一个字节
            int elem = inputStream.read();//返回的是ASCII码值
            if (elem == -1) {
                //读完了
                break;
            }
            System.out.println(elem);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            inputStream.close();
        }
    }
}

一般来说,read方法较为低效,因此要尽可能地降低读取次数,那么就需要每次读取尽可能多的字节数,所以更常见的read使用带一个参数的版本:

byte[] buf = new byte[1024];
int len = inputStream.read(buf);//读取的数据放入ret数组当中,返回读取字节长度
if (len == -1) {
    //读完了
    break;
}
for (int i = 0; i < len; i++) {
    System.out.println(buf[i]);
}

这里的操作需要经过这样的流程:打开文件流->文件操作->关闭文件流!

这里的new操作就是打开文件流,执行完操作后一定不能忘记close,否则可能造成内存泄露!

当然,在Java中实现了一种自动关闭功能——try with resources功能:

try (InputStream inputStream = new FileInputStream(file)) {
    while (true) {
        //每次读取一个字节
        byte[] buf = new byte[1024];
        int len = inputStream.read(buf);//读取的数据放入ret数组当中,返回读取字节长度
        if (len == -1) {
            //读完了
            break;
        }
        for (int i = 0; i < len; i++) {
            System.out.println(buf[i]);
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

也就是把InputStream放在try后的()中,后续就不用再写close了。这里的()中并不是什么都可以放的,只有实现了Closeable接口的才可以放,当然,Java中所有的流对象都实现了Closeable接口。如果要放我们自己实现的对象或流,就需要先实现Closeable接口。

字节流写:FileOutputStream

与读类似:通过writer方法将内容写到目标文件中

File file = new File("hello.txt");
try (OutputStream outputStream = new FileOutputStream(file)) {//每次都会覆盖原有内容
//try (OutputStream outputStream = new FileOutputStream(file, true)) {//每次从文件末尾开始写
    byte[] buf = { 1, 2, 3, 4 };
    outputStream.write(buf);//把buf中的内容写入文件file,也可指定单个字符写
} catch (IOException e) {
    e.printStackTrace();
}

字符流的读和写类似,通过FileReader的read方法读,FileWriter的writer方法写。只不过读取和写入的数据由byte类型变为了char类型,其余则完全相同。

字符流读:FileReader

try (Reader reader = new FileReader(file)){
    char[] buf = new char[1024];
    int len = reader.read(buf);
    for (int i = 0; i < len; i++) {
        System.out.println(buf[i]);
    }
} catch (IOException e) {
    e.printStackTrace();
}

通过PrintWriter写或Scanner读

PrintWriter写

PrintWriter类提供了我们熟悉的print/println/printf 方法,把FileOutputStream的实例对象作为参数构造PrintWriter的实例对象,就可以通过PrintWriter中的println方法把内容写入目标文件:

File file = new File("hello.txt");
System.out.println(file.exists());
System.out.println(file.getCanonicalPath());
try (OutputStream outputStream = new FileOutputStream(file)) {
    PrintWriter printWriter = new PrintWriter(outputStream);//传入要写入的流对象
    printWriter.println("hello world");//写入文件的内容
    printWriter.flush();//刷新才能写入成功
} catch (IOException e) {
    e.printStackTrace();
}

这里println函数打印的内容首先会放到缓冲区,正常情况下缓冲区满了以后才会一起提交到目的位置。如果使用flush函数,就会刷新缓冲区,并直接把内容提交,不需要等缓冲区放满。

Scanner读

与从键盘上读类似,只不过参数部分不再是System.in,而是FileInputStream实例对象。

try (InputStream inputStream = new FileInputStream(file)) {
    Scanner scanner = new Scanner(inputStream);
    String str = scanner.nextLine();//从文件中读
    System.out.println(str);
} catch (IOException e) {
    e.printStackTrace();
}

你可能感兴趣的:(java,java-ee)