文件操作和IO

一.认识文件

1.含义

文件本身是广义的概念,在操作系统中把软件资源/硬件资源都抽象为了“文件”。

我们平时所说的文件,指的是硬盘中的文件

2.硬盘与存内比较

  • 硬盘存储空间大,内容存储空间小
  • 硬盘读写速度较慢,内存读写速度较快
  • 硬盘成本较低,内存成本较高 
  • 硬盘能够持久化存储,内存断电后数据丢失

3.文件路径

文件路径用于表示文件所在的硬盘的具体位置,根据路径可以找到文件。

文件路径也可以认为是文件的一种身份标识,通过标识,区分唯一的一个文件。

文件路径分为绝对路径相对路径

绝对路径

绝对路径是从盘符开始,一层一层的深入,一直到文件名结束

例:C:\Program Files\Git\bin

相对路径

相对路径是指定一个目录作为基准目录,在此目录的基础上一层一层找到目标文件的路径

相对路径中./表示当前路径,../表示上一次路径。

4.文件类型

文件类型主要分为两大类:文本文件二进制文件

文本文件

文本文件中存储的所有内容都是字符串(合法的字符)

但本质上还是二进制文件(计算机存储的数据都是二机制的,可通过字符编码将二机制转换成字符)

二进制文件

二进制文件中保存的都是二进制数据,由“0”和“1”表示

区分一个文件是文本文件和二进制文件,可以使用记事本打开文件,如果是乱码,就是二进制文件,如果不是,则是文本文件。

如图

此文件就是二进制文件。

二.文件系统操作

1.file类

1)构造方法

构造的过程中,需使用绝对路径和相对路径进行初始化,这个路径所指向的文件可以是存在的,也可以是不存在的。

以第二种为例,代码如下:

   File file=new File("../test.txt");

2)方法

修饰符及返回值方法签名说明
StringgetParent()返回File对象的父目录文件路径 
StringgetName()返回File对象的纯文件名称
StringgetPath()返回File对象的文件路径
StringgetAbsolutePath()返回File对象的绝对路径
StringgetCanonicalPath()返回File对象修饰过的绝对路径
booleanexists()

判断File对象描述的文件是否真实存在

boolean isDirectory()判断File对象代表的文件是否是一个目录
booleanisFile()判断File对象代表的文件是否是一个普通文件
booleancreateNewFile()根据File对象自动创建一个空文件,成功返回true
booleandelete()根据File对象删除该文件,成功返回true
voiddeleteOnExit()

根据File对象,标注文件将被删除,JVM结束后

进行    

String[ ]list()返回File对象代表的目录下所有的文件名

File[ ]        

listFlies()

返回File对象代码的目录下所有的文件,

以File对象表示

booleanmkdir()创建File对象所代表的目录
booleanmkdirs()

创建File对象所代表的目录,如有必要

会创建中间目录

代码示例:

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

    }
}

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file=new File("/text.txt");
        System.out.println("是否存在"+file.exists());
        System.out.println("是否为文件"+ file.isFile());
        System.out.println("是否为目录"+file.isDirectory());
        //因为文件没创建  当然全是false
        file.createNewFile();
        System.out.println("是否存在"+file.exists());
        System.out.println("是否为文件"+ file.isFile());
        System.out.println("是否为目录"+file.isDirectory());

    }
}

面试题:遍历目录,打印每一个文件的路径

import java.io.File;

public class Demo3 {
    public static void scan(File file){
        if(!file.isDirectory()){
            return;
        }
        File[] f=file.listFiles();
        if(f==null||f.length==0){
            return;
        }
        System.out.println(file.getAbsolutePath());
        for(File f1:f){

            if(f1.isFile()){
                System.out.println(f1.getAbsolutePath());
            }
            else {
                scan(f1);
            }
        }

    }

    public static void main(String[] args) {
        File f=new File("./");
        scan(f);
    }
}

三.文件内容操作

文件内容操作,主要是读文件和写文件,都是由操作系统提供了API。(stream,流对象)

1.字节流(二进制)

字节流读写数据的基本单位是一个字节

JAVA针对读写两种操作,分别为字节流提供了 InputStream(输入) 和 OutputStream(输出) 类,为字符流提供了 Reader(输入) 和 Writer(输出) 类。

怎样去区分输入和输出?

如图:

靠近CPU的是输入,远离cpu的是输出

1)InputStream

实现
InputStream  stream=new FileInputStream("./text.txt");

此处隐含着“打开文件”的操作。

针对文件进行读写,务必需先打开,结束后,也需要关闭。

        stream.close();

打开文件,其实是在该进程的文件描述符表中,创建了一个新的表项

进程描述符表描述了该进程要执行哪些操作,可以认为是一个数组,数组的每一个元素就是一个struct file对象。数组的下标就称为“文件描述符

每打开一个文件,就相当于在数组上占用了一个位置。

而在系统内核中,文件描述符表数组,是固定长度的。

因而,如果不主动释放文件,会导致这里的资源越来越少,数组满了,后续再打开文件就会失败,这个问题称为“文件资源泄漏”

为了避免该问题,我们可以用try/catch来确保文件的释放

  try (InputStream stream = new FileInputStream("./text.txt")) {

        }catch (IOException e){
            e.printStackTrace();
        }

try(){}的代码执行完毕,最终都会执行close~

读文件

代码如下:

public class Demo5 {
    public static void main(String[] args) throws IOException {
        try (InputStream stream = new FileInputStream("./text.txt")) {
            while (true){
                int b=stream.read();
                if(b==-1){
                    break;
                }
                System.out.printf("0x%x\n",b);
            }
          }catch (IOException e){
            e.printStackTrace();
        }

    }
}

由于read()是一个字节一个字节读取,所以需要循环读取,当读取完毕时,返回-1。

频繁的读取多次硬盘,IO耗时比较大。

可以使用第二种构造方法,一次读取所有数据

代码:

public class Demo6 {
    public static void main(String[] args) throws IOException {
        try(InputStream stream=new FileInputStream("./text.txt")) {
            byte[] buffer=new byte[1024];
            //b表示实际读到的字节数
            int b= stream.read(buffer);
            for (int i = 0; i < b; i++) {
                System.out.printf("0x%x\n",buffer[i]);
            }
        }
    }
}

2)OutputStream

写文件

写文件与读文件用法相似

代码:

public class Demo7 {
    public static void main(String[] args) throws IOException {
        try (OutputStream stream=new FileOutputStream("./text.txt")){
            stream.write(0xe4);
            stream.write(0xbd);
            stream.write(0xa0);
            stream.write(0xe5);
            stream.write(0xa5);
            stream.write(0xbd);
        }
    }
}

当前的写操作,会把之前的内容清空,再写入内容。

若是想在保持原有内容不变,新增信写内容,可以开启“追加写”模式

 

 

write也可以一次性写多个字节

public class Demo8 {
    public static void main(String[] args) throws IOException {
        try (OutputStream stream = new FileOutputStream("./text.txt", true)){
        byte[] buffer = new byte[]{(byte) 0xe4, (byte) 0xbd, (byte) 0xa0, (byte) 0xe5, (byte) 0xa5, (byte) 0xbd};
        stream.write(buffer);
        }
    }
}

2.字符流(文本)

字符流读写数据的基本单位是一个字符

字符流内部做的工作更多,它会自动查询码表,把二进制数据转换成对应字符。

1)Reader

一次读一个字符,代码:

public class Demo9 {
    public static void main(String[] args) throws IOException {
        try (Reader reader = new FileReader("./text.txt")) {
            while (true) {
                int c = reader.read();
                if (c == -1) {
                    return;
                }
                char ch = (char) c;
                System.out.println(ch);
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }
}

一次性读所有字符

代码: 

public class Demo10 {
    public static void main(String[] args) throws IOException {
        try (Reader reader = new FileReader("./text.txt")) {
            char[] buffer=new char[1024];
            int n=reader.read(buffer);
            for (int i = 0; i < n; i++) {
                System.out.println(buffer[i]);
            }
        }
    }
}

2)Writer

使用:

第一个构造方法可以之间添加字符串

代码

public class Demo11 {
    public static void main(String[] args) throws IOException {
        try (Writer writer=new FileWriter("./text.txt")){
            writer.write("你好,世界");
        }
    }
}


以上便是全部内容,如有不对,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值