文件IO操作

本文详细介绍了Java中对文件的操作,包括相对路径和绝对路径的概念,文件的类型如文本文件和二进制文件,以及Java通过File类进行的创建、删除、重命名等文件系统操作。文章还深入讲解了文件内容的读写,利用数据流进行操作,并提供了代码示例,如使用InputStream和OutputStream进行字节流读写,以及Reader和Writer的字符流操作。
摘要由CSDN通过智能技术生成

目录

相对路径和绝对路径

文件的类型

Java对文件的操作

文件内容的读写 -- 数据流

扫描目录

拷贝文件

目录

相对路径和绝对路径

文件的类型

Java对文件的操作

文件内容的读写 -- 数据流

扫描目录

拷贝文件


文件的含义

狭义的文件:指的是你的硬盘上文件和目录(文件夹)

广义的文件:泛指计算机中的很多的软硬件资源,操作系统中,把很多的硬件设备和软件资源抽象成了文件,按照文件的方式统一管理

之前存储数据,主要是靠变量,变量是在内存中,现在的文件是在硬盘上的,每个文件在硬盘上都有一个具体的位置。

d:盘符,c,d,e这样 的盘符是通过“硬盘分区”来的,每个盘符可以是一个单独的硬盘,也可以是若干个盘符对应一个硬盘

相对路径和绝对路径

绝对路径:以c:d:盘符开头的路径

相对路径:以当前所在目录为基准,以.或者...开头(.有时可以省略),找到指定的路径

 定位到bin文件,相对路径的写法是不同的,如果工作目录是d:/,那么相对路径写成./java/bin,如果工作目录是d:/java,那么相对路径就写成./bin(./表示当前目录),如果绝对路径是d:/java/basic-code,相对路径就写../bin(..表示当前目录的上级目录),如果工作目录是d:/java/basic-code/git,相对路径写为../../bin。

文件的类型

文本文件

存储文本数据,字符串存储的,字符串,是由字符构成的,每个字符,都通过一个数据来看表示的,这个文本文件里存储的数据,一定是合法的数据,都是在指定的编码表之内的数据

二进制文件

存储的二进制数据,不一定是字符串,没有任何限制,可以以存储任何数据

如何区分是文本文件还是二进制文件?

使用记事本打开,如果乱码了,说明就是二进制文件,如果没乱码你,说明就是文本文件

Java对文件的操作

1.针对文件系统操作(文件的创建,删除,重命名...)

2.针对文件内容操作(文件的读和写)

文件的创建,删除,重命名

java通过File类来对一个文件进行抽象的描述,但是有File对象,并不代表真实存在该文件

属性 静态变量(/或者\,由系统决定)

static String
pathSeparator路径分隔符
static charpathSeparator路径分隔符

构造方法:

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

在new File对象的时候,构造方法参数中,可以指定一个路径,此时File对象就代表这个路径对应的文件了。可以是相对路径,也可以是绝对路径

parent表示当前文件所在的目录,child表示自身的文件名,d:/java,parent表示d:/,child表示java

import java.io.File;

public class IODemo1 {
    public static void main(String[] args) {
        File file = new File("d:/test.txt");
//不要求这个路径真实存在
        System.out.println();
    }
}
import java.io.File;
import java.io.IOException;

public class IOdemo2 {
    public static void main(String[] args) throws IOException {
        File file = new File("./test.txt");
        file.createNewFile(); //创建文件
        System.out.println(file.exists());//判断文件是否存在
        System.out.println(file.isFile());//判断文件是否为目录
        System.out.println(file.isDirectory());//
    }
}

deleteOnExit程序退出时会自动删除,适用于需要使用到一些“临时文件”的时候,临时文件,保存了当时实时编辑的内容,

import java.io.File;

public class IODemo5 {
    public static void main(String[] args) {
        File file = new File("./test");
        File dest = new File("./testDemo");
        file.renameTo(dest);//重命名
    }
}

文件内容的读写 -- 数据流

针对文件内容,使用“流对象”进行操作的,流对象就好比是我们去水房接水,我们要接一桶水,可以一次接完,也可以十次接完,可以任意次数接完,但如果我们从羽毛球桶里取羽毛球,只能一个一个取,不是流,从文件中读100个字节,可以,一次读100个字节,一次读完,一次读50个字节,两次读完,一次读10个字节,十次读完..

类的使用方式是固定的,核心就是四个操作:1.打开文件(构造对象)2.关闭文件(close方法)3.读文件(read) 4.写文件(write)

从类型上,可以分成两个大类型:

1.字节流(操作二进制数据的)以字节为单位

读文件 InputStream类 FilelnputStream类

public class IODemo6 {
    //读文件
    public static void main(String[] args) throws IOException{
              //如果这个文件不存在,那么就会抛出这个异常FileNotFoundException,是IOException的子类
        //创建InputStream 对象的时候,使用绝对路径或者相对路径都是可以的,也可以使用File对象
        InputStream inputStream = new FileInputStream("d:/test.txt");

        //进行读操作
        while(true){
        int b =  inputStream.read();
        if(b==-1){
            //读取完毕
            break;
        }
        System.out.println(""+(byte)b);
        }

        inputStream.close();
    }
}
int b =  inputStream.read();
    //read无参数版本:一次读一个字节,返回类型用int,为了表示读取文件结束
    // 一个参数版本:把读到的内容填充到参数的这个字节数组中
    // 三个参数版本:把读到的内容往数组的一部分区间里尽可能填充

read读取的是一个字节,按理说返回一个byte就行了,但是实际上返回是int,除了要表示byte里的0-255(-128->-127)这样的情况之外,还需要表示一个特殊情况,-1,这个情况表示读取文件结束了。

 //一次读取多组数据
        while(true){
        byte[] buffer = new byte[1024];
        int len = inputStream.read(buffer);
        if(len == -1){
        break;
        }
        //此时数据都存在了数组里
       for(int i = 0; i < len; i++){
       System.out.print("%x\n",buffer[i]);
        }
        }

一次读一点一次读一点,每次读都要保存

        byte[] buffer = new byte[1024];

buffer缓冲区,存在的意义,就是为了提高IO操作的效率,单次IO操作,是要访问硬盘IO设备,单次操作时比较好时节的,如果频繁进行IO操作,耗时就会更多,一次读一个字节,循环次数就比较高,read次数也就很高,但是一次读多组数据,一次读1024个字节,循环次数就降低了很多,read次数变少了,速度也就快了,buffer就是“缓冲区”

写文件 OutputStream类 FileOutputStream

public class IODemo7 {
    //写文件
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("d:/test.txt");
        outputStream.write(97);
        outputStream.write(98);
        outputStream.write(99);
        outputStream.close();
    }
}

编写完程序以后,打开text.txt文件就会得到这样的结果

对于OutputStream来说,默认情况下,打开一个文件,会先清空文件原有的内容,如果不想清空,流对象还提供了一个“追加写”对象,通过这个就可以实现不清空文件,把新内容追加到写的后面。

close操作

进程在内核里,使用PCB这样的数据结构来表示进程,一个线程对应一个PCB,一个进程也可以对应多个,PCB里有一个重要的属性,文件描述符表,记录了该进程打开了哪些文件,即使一个进程有多个线程多个PCB,这些PCB都共用一个文件描述符表。

close操作的意思是关闭文件,close一般是要执行的,但是如果一个程序,这里的文件对象自始至终要使用,不关闭也没事,随着进程的结束,PCB销毁了,文件描述符表也就销毁了,对应的资源操作系统就自动回收了,但是如果没有close,没有即使关闭,那就可能会导致文件描述符表被占满,后面打开文件就会不能打开。close操作以后流对象就用不了了,flush操作也能起到刷新缓冲区的效果,手动刷新。

为了防止我们忘记写close,可以使用try语句块执行完毕,就可以自动执行关闭操作,防止忘记没有关闭。

public class IODemo7 {
    //写文件
    public static void main(String[] args) throws IOException {
        
        try (OutputStream outputStream = new FileOutputStream("d:/test.txt")){
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);
        }
    }
}

2.字符流(操作文本数据的)以字符为单位

读文件 Reader类 FileReader

public class IODemo8 {
    //字符流的操作
    public static void main(String[] args) {
        //FileReader从文件里读
        try(Reader reader = new FileReader("d:/test.txt")){
           while(true){
               int ch = reader.read();
               if(ch == -1){
                   break;
               }
               System.out.println(""+(char)ch);
           }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

写文件 Writer类 FileWriter(写入的时候都是默认清空)

public class IODemo9 {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("d:/test.txt")){
            writer.write(99);//可以写一个字符串,一个整形,一个字符数组
            writer.write("hello world");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

有时候可能你运行完写操作的代码以后,文件的内容还是你之前写入的,那是因为像写操作都是先写到缓冲区里边,一次写操作可能会遇见很多种缓冲区,比如说代码里由缓冲区,标准库里也由缓冲区,操作系统内核里也有缓冲区,写操作执行完了,内容可能还在缓冲区里,并没有真正的进入硬盘里,而在这时候close操作,就会触发缓冲区的冲刷,

 scanner是搭配流对象使用的,System.in表示从键盘读入,在这里System.in就表示一个字节流对象,那同理打开读取一个文件,也可以把文件写入里面,那么就是从文件中读取

public class IoDemo10 {
    public static void main(String[] args) {
        //Scanner scanner = new Scanner(System.in);
        try(InputStream inputStream = new FileInputStream("d:/test.txt")){
            Scanner scanner = new Scanner(inputStream);

            //此时读取文件就是从文件中读取
            scanner.next();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Scanner的close本质上是要关闭内部这个流对象,但是此时,内部的流对象已经被try()关闭了,里面的Scanner,不关闭,也没事。

扫描目录

并找到名称里包含指定目录的所有普通文件(不包含目录),并且询问用户是否要删除该文件


import java.io.File;
import java.util.Scanner;

public class IoDemo11 {
    private  static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        //让用户输入一个指定搜索的目录
        //Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要搜索的路径");
        String basePath = scanner.next();

        //针对用户输入进行简单判定
        File root = new File(basePath);
        if (!root.isDirectory()) {
            //路径不存在,或者只是一个普通文件,不能搜索
            System.out.println("输入的目录有误");
            return;
        }
        //再让用户输入一个要删除的文件名
        System.out.println("请输入要删除的文件名:");
        //此处要使用next,不能使用nextLine
        String nameTODelete = scanner.next();

        //针对指定文件路径进行扫描,递归操作
        //先从根目录出发(root)
        //先判定一个这个根目录里是否包含要删除的文件,如果是,就删除,否则就跳过下一个
        //如果当时这里包含了一些目录,再针对子目录进行递归

        scanDir(root,nameTODelete);
       }

    private static void scanDir(File root, String nameTODelete) {
        //1.先列出当前路径下面包含的路径
        File[] files = root.listFiles();//查看这个目录里都有啥
        if(files == null){
            //当前root目录下没东西,是一个空目录
            //结束继续递归
            return;
        }
        //2.遍历当前的列出结果
        for(File f : files){
            if(f.isDirectory()){
                //如果是目录,就进一步递归
                scanDir(f,nameTODelete);
            }else{
                //如果是普通文件,则判定是否要删除
                if(f.getName().contains(nameTODelete)){
                    System.out.println("确定要删除"+f.getAbsolutePath()+"?");
                    String choice = scanner.next();
                    if(choice.equals("y")||choice.equals("Y")){
                        f.delete();
                        System.out.println("删除成功");
                    }else{
                        System.out.println("删除取消");
                    }
                }
            }
        }
    }

拷贝文件

一个字节一个字节拷贝

import java.io.*;
import java.util.Scanner;

public class IoDemo12 {
    public static void main(String[] args) {
        //输入两个路径
        //源和目标
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要拷贝哪个文件");
        String srcPath = scanner.next();
        System.out.println("请输入要被拷贝到哪个文件");
        String destPath = scanner.next();

        File srcFile = new File(srcPath);
        if(!srcFile.isFile()){
            //如果源不是一个文件(是一个目录或者不存在)
            //此时不做任何操作
            System.out.println("");
            return;
        }
        File destFile = new File(destPath);
        if(destFile.isFile()){
            //如果已经存在,那么也不能拷贝
            System.out.println("当前路径有误");
            //进行拷贝操作
            try(InputStream inputStream = new FileInputStream(srcFile)) {
                OutputStream outputStream = new FileOutputStream(destFile)
                //进行读文件操作 一边读一边写
                while(true){
                    int b = inputStream.read();
                    if(b==-1){
                        break;
                    }
                    outputStream.write(b);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } ;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值