文件系统相关知识与IO

硬盘及内存的区别

在系统中,我们的文件都是存储在硬盘上的,我们经常听到“硬盘”和“内存”两词,两者虽然都是用于存储数据,但有区别:

  • 内存的读取速度快,硬盘读取速度慢
  • 内存的存储空间小,硬盘的存储空间大
  • 若断电后内存中的数据将会消失,硬盘中的数据不会消失
  • 内存的制作成本更高,硬盘的制作成本更低一些 

文件相关知识

文件的获取

文件是存储在硬盘中的,我们要获取文件,就需要通过java中的File类,当然,在正式学习前,应该再了解一下相关知识

绝对路径和相对路径

绝对路径:某文件被包含的所有路径,以盘符(也就是D盘,C盘等)为开头的就是绝对路径。如我想要打开D盘test文件夹内的的test1文件夹内的test2文件夹内的一个“hello.txt”文件:D:\test\test1\test2

 相对路径:文件以某文件为参考物,相对在哪个路径上。

注意:虽然平时windows系统上的打开某文件夹用的是 “\” 反斜杠,但其实普遍情况下大家在表示打开文件夹时使用的是 “/” 正斜杠,只是当年最初的时候DOS的产品经理临时做了一个违背祖宗的决定——将大家平时都在使用的正斜杠/改为反斜杠\。产品上线后大家都在说不行,使用才改为了正斜杠反斜杠都可以,但我们平时在java中使用打开什么路径一般还是使用正斜杠“/”,否则如果我们要使用反斜杠,要经过反义才能使用,例如在编译器中使用正斜杠版本:D:/test/test1/test2;若使用反斜杠版本则变为了:D:\\test\\test1\\test2;

工作目录

工作目录就是我们java程序默认在上面进行一系列操作的地方,就是我们项目所在的位置。要知道目前工作目录位置,我们可以这么操作:

 通常对工作路径的使用,我们要结合相对路径,一般从工作路径开始,我们需要用“ ./ ”来开头。

File srcFile = new File("./src/test");  //打开目前工作路径的src文件夹中的test文件夹

文件获取

为了找到文件,我们可以使用Java中的File类,来进行获取文件名字,判断是否为文件或是文件夹等操作。

import java.io.File;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * Description: 在这里练习IO文件操作
 * User: Lenovo
 * Date: 2022-11-02
 * Time: 20:43
 */
public class demo1 {
    public static void main(String[] args) throws IOException {
//        File file = new File("F:\\java练习专用\\java\\20221102\\src/hello.txt");
        File file = new File("src/test"); //要看目前的工作路径
        System.out.println(file.exists());  //判断该文件是否存在
        System.out.println(file.getName()); //获取名字
        System.out.println(file.getPath()); //获取相对路径
        System.out.println(file.getCanonicalPath()); //获取优化后的绝对路径
        System.out.println(file.getAbsolutePath()); //获取绝对路径
        File[] arr = file.listFiles();  //将目前文件里面的所有文件提取出来
    }
}

IO操作

我们平常所说的IO,也就是输入输出流,全称为InputputStream和OutputStream。

因为文件都是存储在硬盘中的,因为我们无法直接对硬盘进行操作,所以要对文件进行读写操作,我们需要通过InputStream类和OutputStream类在内存中间接地对文件进行读和写的操作,具体示意图如下:

 像inputStream这类操作硬盘数据的东西我们统称为“Handler”

IO细分

在IO中,我们也分为字符流和字节流

 InputStream字节流

InputStream类由于是抽象类,必须得由其子类来实例化,所以我们创建一个InputStream示例应该用FileinputStream类。

InputStream inputStream = new FileInputStream("src/hello.txt");

inputStream类的最主要方法为read(),read有三个版本

 read()版本:全部读完

read(byte[] b)版本:读多少个字节

read(byte[] b, int off, int len)版本:从第几个字节开始读,读len个字节

我们要特别注意,在读文件之后,要注意关闭文件,也就是在操作完该文件后,我们要使用close()函数

这是因为在进程的PCB中,会有一个属性,名字为“文件描述符表”,该表是一个顺序表,里面放着的就是一个个这样子的文件类型,其下标对应成为“文件描述符”。

我们每创建一个文件类型,就会占文件描述符表的一个位置,而放满之后就文件描述符表就不会再一次扩容了,若我们要创建一个新的文件IO类型来操作,会失败,所以在每次使用完后,要注意使用close()函数来关闭该文件,也就是将该文件在文件描述符表中删除。

InputStream的使用

关于InputStream类型的使用,我们可以到Scanner类等,详情看下面代码:

import java.io.*;

public class demo4 {
    public static void main(String[] args) throws IOException {
//        File file = new File("src/hello.txt");
        InputStream inputStream = new FileInputStream("src/hello.txt");
        byte[] arr = new byte[1024];
        int len = inputStream.read(arr);
        String s = new String(arr,0,len,"utf-8");
        for (int i = 0; i < len; i++) {
            System.out.println(arr[i]);
        }
        System.out.println(s);
        inputStream.close();
    }
}
import java.io.*;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2022-11-02
 * Time: 21:39
 */
public class demo5 {
    public static void main(String[] args) throws IOException {

        //使用该方法可以直接在try中完成后将inoutStream关闭
        try(InputStream inputStream= new FileInputStream("src/hello.txt")){
            byte[] arr = new byte[1024];
            Scanner scan = new Scanner(inputStream);
            String s = new String(scan.next());
            System.out.println(s);
        }catch(IOException e) {

        }

    }
}

注意,在try中创建流对象可以在try内的代码块完成后自动关闭,我们也可以通过分号在try内创建多个流对象,或者try嵌套来创建多个流对象。

OutputStream字节流

在我们每次写完文件后,记得加一个.flush()函数,这是因为在操作系统中IO通常有些费时间,所以为了减少IO,系统会先将我们要输入的数据放入“缓冲区”先,等这个缓冲区满了,再写入,但是这样子有可能导致我们的一部分数据未写入,所以每次在写完数据后最好都使用flush。

OutputStream的使用方法其实和InputStream的使用方法差不多,详细使用看下面的代码:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class demo6 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os = new FileOutputStream("src/hello.txt")){
            String s = "郑小绿";
            byte[] arr = s.getBytes("utf-8");
            os.write(arr);
            os.flush();
        }
    }
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class demo6 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os = new FileOutputStream("src/hello.txt")){
            String s = "郑小绿";
//            byte[] arr = s.getBytes("utf-8");
            byte[] arr = {'a','b','c','d'};
            os.write(arr);
            os.flush();
        }
    }
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class demo6 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os = new FileOutputStream("src/hello.txt")){
            String s = "郑小绿";
//            byte[] arr = s.getBytes("utf-8");
            byte[] arr = {'a','b','c','d'};
            os.write(arr,1,2);
            os.flush();
        }
    }
}

Reader字符流读文件

除了InputStream字节流读文件外,我们还可以使用Reader来读取字符文件。具体使用方法如下:

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2022-11-02
 * Time: 21:39
 */
public class demo5 {
    public static void main(String[] args) throws IOException {
        //使用1
        Reader reader = new FileReader("src/hello.txt");
        char[] arr = new char[1024];
        int len = reader.read(arr);
        System.out.println(len);
        reader.close(); //要记得关闭文件

          //使用2
//        Scanner scan = new Scanner(reader);
//        String s = scan.next();
//        System.out.println(s);
//        reader.close(); //要记得关闭文件

          //使用3
//        Reader reader = new FileReader("src/hello.txt");
//        char[] arr = new char[1024];
//        int len = reader.read(arr);
//        String s = new String(arr,0,len);
//        for (int i = 0; i < len; i++) {
//            System.out.println(arr[i]);
//        }
//        System.out.println(s);
//        reader.close(); //要记得关闭文件

          //使用4
//        Scanner scan = new Scanner(reader);
//        String s = scan.next();
//        System.out.println(s);
//        reader.close(); //要记得关闭文件

    }
}

Writer字符流写文件

和OutPutStream差不多

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class demo6 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os = new FileOutputStream("src/hello.txt")){
            String s = "郑小绿";
//            byte[] arr = s.getBytes("utf-8");
            byte[] arr = {'a','b','c','d'};
            os.write(arr,1,2);
            os.flush();
        }
    }
}

PrintWriter

在这里着重介绍PrintWriter,在创建完该类后,我们可以像平常使用System.out.println来写入文件,具体使用如下代码:

import java.io.*;

public class demo7 {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
        OutputStream os = new FileOutputStream("src/hello.txt");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os,"utf-8");
        PrintWriter printWriter = new PrintWriter(outputStreamWriter);
        printWriter.print("郑小绿 ");
        printWriter.println("超6");
        printWriter.println("宇宙无敌牛");
        printWriter.flush();
    }
}

对读写文件的实操

实操①:找到指定文件并删除

要求:找到某文件,并让用户选择是否删除

代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2022-11-03
 * Time: 0:23
 */
public class demo8 {

    public static void scanFile(File srcFile,String del) {
        for (File f: srcFile.listFiles()) {
            if(f==null){
                return;
            }
            if(f.isDirectory()){
                scanFile(f,del);
            }
            if(f.isFile()){
                try {
                    System.out.println(f.getCanonicalPath());
                    tryDel(f,del);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void tryDel(File f,String del) {
        if(f.getName().contains(del)){
            System.out.println("已发现该文件,是否删除?Y/N");
            Scanner scan = new Scanner(System.in);
            String choose = scan.next();
            if(choose.equals("Y")){
                f.delete();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        System.out.println("请输入你要查询的路径:");
        Scanner scan = new Scanner(System.in);
        String srcFile = scan.next();
        File file = new File(srcFile);
        if(!file.exists()){
            System.out.println("输入的路径不正确或不存在");
            return;
        }
        System.out.println("请输入你要删除的文件名字:");
        String delFile = scan.next();
        scanFile(file,delFile);
    }
}

实操②:对文件进行复制

要求:选择某文件,然后复制到某指定路径内

代码:

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2022-11-03
 * Time: 9:53
 */
public class demo9 {
    public static void main(String[] args) throws IOException {
        System.out.println("请输入你要复制的文件路径:");
        Scanner scan = new Scanner(System.in);
        String src = scan.next();
        File srcFile = new File(src);
        if(!srcFile.exists()){
            System.out.println("该路径错误或不存在");
            return;
        }

        if(srcFile.isDirectory()){
            System.out.println("输入的路径为目录,错误");
            return;
        }
        System.out.println("请输入你需要复制到的路径(包含名字):");
        String copyPath = scan.next();
        try(InputStream inputStream = new FileInputStream(srcFile)){
            try(OutputStream os = new FileOutputStream(copyPath)){
//                byte[] buf = new byte[1024];
//                int len = inputStream.read(buf);
//                while(len!=-1){
//                    len = inputStream.read(buf);
//                    os.write(buf,0,len);
//                    os.flush();
//                }
//                byte[] buf = new byte[1024];
                while(true){
                    byte[] buf = new byte[1024];
                    int len = inputStream.read(buf);
                    if(len==-1){
                        break;
                    }
                    os.write(buf);
                    os.flush();
                }
            }
        }
    }
}

在这里我们要注意,不使用注释内的代码原因是因为如果按照上面的代码进行读取,若第一次buf都没有读满,则很可能会导致程序多读了数据,导致文件出错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值