java文件操作和IO流(详解)(๑•́ ₃ •̀๑)エー

目录

😄一.认识文件

1.1文件的概念与组成:

1.2树形结构组织与目录:

1.3文件路径:

😚二.文件系统操作

2.1File类概述:

2.2案例演示:

案例演示一:

 演示案例二:

🤪三.文件内容操作(“文件流”/ "IO"流)

3.1InputStream概述:

示例:读取文件中的数据

3.2OutputStream概述:

示例:项文件中写入数据

3.3Reader概述:

3.4Writer概述:

🤩四.小案例测试:

4.1案例一:

4.2案例二:

4.3.案例三:


😄一.认识文件

1.1文件的概念与组成:

我们先来认识狭义上的文件(File),对于硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公室桌上的一份份真实的文件一般。

⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数 据而存在,我们把这部分信息可以视为⽂件的元信息。

1.2树形结构组织与目录:

同时,随着⽂件越来越多,对⽂件的系统管理也被提上了⽇程,如何进行⽂件的组织呢,⼀种合乎⾃ 然的想法出现了,就是按照层级结构进⾏组织⸺也就是我们数据结构中学习过的树形结构。这样, ⼀种专门用来存放管理信息的特殊⽂件诞⽣了,也就是我们平时所谓⽂件夹(folder)或者⽬录 (directory)的概念。

1.3文件路径:

  • 绝对路径

大家都知道,在我们平时使用计算机时要找到需要的文件就必须知道文件的位置,而表示文件的位置的方式就是路径,例如只要看到这个路径:c:/website/img/photo.jpg我们就知道photo.jpg文件是在c盘的website目录下的img子目录中。类似于这样完整的描述文件位置的路径就是绝对路径。

  • 相对路径

除了可以从根开始进⾏路径的描述,我们可以从任意结点出发,进⾏路径的描述,⽽这种描述⽅式就 被称为相对路径(relative path),相对于当前所在结点的⼀条路径。

举例:

file1的位置为:C:\ABC\path1\file1;(绝对路径)

file2的位置为:C:\ABC\path2\file2;(相对路径)

这时候让file1说出file2的位置则为:../path2/file2;两个点(..)表示回退到下一层。解释一下就是,file1在path1文件夹下,先点点,回退到ABC文件夹下,然后加上path2/file2,也就是 ../path2/file2,这就是相对路径了

😚二.文件系统操作

java通过java.io.File 类对一个文件(包括目录)进行抽象类的描述,注意,有File对象,并不代表真实存在该文件

2.1File类概述:

  • File类常见属性:

  • File类常见构造方法:

  •  File类常见方法:
修饰符及返回值类型⽅法签名说明
StringgetParent()返回File对象的⽗⽬录⽂件路径
StringgetName()返回FIle对象的纯⽂件名称
StringgetPath()返回File对象的⽂件路径
StringgetAbsolutePath()返回File对象的绝对路径
StringgetCanonicalPath()返回File对象的修饰过的绝对路径
booleanexists()判断File对象描述的⽂件是否真实 存在
booleanisDirectory()判断File对象代表的⽂件是否是⼀ 个⽬录
booleanisFile()判断File对象代表的⽂件是否是⼀ 个普通⽂件
booleancreateNewFile()根据File对象,⾃动创建⼀个空⽂件。成功创建后返回true
booleandelete()根据File对象,删除该⽂件。成功 删除后返回true
voiddeleteOnExit()根据File对象,标注⽂件将被删 除,删除动作会到JVM运⾏结束时 才会进⾏
String[]list()返回File对象代表的⽬录下的所有 ⽂件名
File[]listFiles()返回File对象代表的⽬录下的所有 ⽂件,以File对象表⽰
booleanmkdir()创建File对象代表的⽬录
booleanmkdirs()创建File对象代表的⽬录,如果必要,会创建中间⽬录
booleanrenameTo(Filedest)进⾏⽂件改名,也可以视为我们平 时的剪切、粘贴操作
booleancanRead()判断⽤⼾是否对⽂件有可读权限
booleancanWrite()判断⽤⼾是否对⽂件有可写权限

2.2案例演示:

案例演示一:

import java.io.File;
import java.io.IOException;
public class Test {
    public static void main(String[] args) throws IOException {
        File file = new File("../test.txt");
        //1.获取File对象的父目录文件路径
        System.out.println(file.getParent());
        //2.获取File对象的纯文件名称
        System.out.println(file.getName());
        //3.获取File对象的文件路径
        System.out.println(file.getPath());
        //4.获取File对象的绝对文件路径
        System.out.println(file.getAbsoluteFile());
        //5.过去File对象修饰过的绝对路径
        System.out.println(file.getCanonicalPath());
        //6.根据File对象,⾃动创建⼀个空⽂件。成功创建后返回true
        boolean ok = file.createNewFile();
        System.out.println(ok);
        //7.判断当前创建的文件是否存在
        System.out.println(file.exists());
        //8.判断File对象代表的⽂件是否是⼀ 个普通⽂件
        System.out.println(file.isFile());
        //9.判断File对象代表的⽂件是否是⼀个⽬录
        System.out.println(file.isDirectory());
        //10.删除该文件
        System.out.println(file.delete());
        //11.查看当前文件是否存在
        System.out.println(file.exists());
    }
}

运行结果:

..
test.txt
..\test.txt
D:\java_code\Test-java\..\test.txt
D:\java_code\test.txt
false
true
true
false
true
false

 演示案例二:

import java.io.File;
public class Demo {
    public static void main(String[] args) {
        File dir = new File("some-parent/some-dir");
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        //创建File对象代表的⽬录
        System.out.println(dir.mkdir());
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        //使用mkdir() 的时候,如果中间⽬录不存在,则⽆法创建成功;mkdirs()可以解决这个问题
        System.out.println("===================================");
        //创建File对象代表的⽬录,如果必要,会创建中间⽬录
        System.out.println(dir.mkdirs());
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
    }
}

运行结果:

false
false
false
false
false
===================================
true
true
false

🤪三.文件内容操作(“文件流”/ "IO"流)

IO简介:

IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。IO 流在 Java 中分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流。

Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

3.1InputStream概述:

方法简介:

说明:

InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。关于InputStream的实现类有很多,基本可以认为不同的输⼊设备都可以对应⼀个InputStream类,我们现在只关心从⽂件中读取,所以使 ⽤FileInputStream

FileInputStream构造方法概述:

示例:读取文件中的数据

注:原本文本文件中只有两个汉字:你好

实现方式1

import java.io.*;

public class Demo {
    public static void main(String[] args) throws FileNotFoundException {
        try (InputStream inputStream = new FileInputStream("./src/iotest/test.txt")) {
            while (true) {
                int b = inputStream.read();
                if (b == -1) {
                    // 读取完毕了
                    break;
                }
                // 表示字节, 更习惯使用 十六进制 打印显示.
                System.out.printf("0x%x\n", b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实现方式2:

import java.io.*;

public class Demo1 {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("./src/iotest/test.txt")) {
            while (true) {
                byte[] buffer = new byte[1024];
                // n 返回值表示 read 操作, 实际读取到多少个字节.
                int n = inputStream.read(buffer);
                System.out.println(n);
                if (n == -1) {
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("0x%x\n", buffer[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

3.2OutputStream概述:

方法简介:

示例:项文件中写入数据

public class Demo2 {
    public static void main(String[] args) {
        try (OutputStream outputStream = new FileOutputStream("./src/iotest/test.txt", true)) {
            // outputStream.write(97);
            byte[] buffer = new byte[] { (byte)0xe4, (byte)0xbd, (byte)0xa0, (byte)0xe5, (byte)0xa5, (byte)0xbd };
            //1.直接从0位置开始写6个单位长度的字符
            outputStream.write(buffer, 0, 6);
            //2.一个一个的写
            outputStream.write(0xe4);
            outputStream.write(0xbd);
            outputStream.write(0xa0);
            outputStream.write(0xe5);
            outputStream.write(0xa5);
            outputStream.write(0xbd);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

3.3Reader概述:

Reader用于从源头(通常是文件)读取数据(字符信息)到内存中,java.io.Reader抽象类是所有字符输入流的父类。

Reader 用于读取文本, InputStream 用于读取原始字节。

Reader 常用方法:

  • read() : 从输入流读取一个字符。
  • read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,等价于 read(cbuf, 0, cbuf.length)
  • read(char[] cbuf, int off, int len):在read(char[] cbuf) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字符数)。
  • skip(long n):忽略输入流中的 n 个字符 ,返回实际忽略的字符数。
  • close() : 关闭输入流并释放相关的系统资源。

3.4Writer概述:

Writer用于将数据(字符信息)写入到目的地(通常是文件),java.io.Writer抽象类是所有字符输出流的父类。

Writer 常用方法:

  • write(int c) : 写入单个字符。
  • write(char[] cbuf):写入字符数组 cbuf,等价于write(cbuf, 0, cbuf.length)
  • write(char[] cbuf, int off, int len):在write(char[] cbuf) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字符数)。
  • write(String str):写入字符串,等价于 write(str, 0, str.length())
  • write(String str, int off, int len):在write(String str) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字符数)。
  • append(CharSequence csq):将指定的字符序列附加到指定的 Writer 对象并返回该 Writer 对象。
  • append(char c):将指定的字符附加到指定的 Writer 对象并返回该 Writer 对象。
  • flush():刷新此输出流并强制写出所有缓冲的输出字符。
  • close():关闭输出流释放相关的系统资源。

🤩四.小案例测试:

4.1案例一:

要求:扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含目录),并且后续询问用户是否要删除该文件

代码详解:

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

public class IOTest1 {
    //递归扫描文件
    public static void scan(File currentFile,String key){
        //如果当前文件不是目录,直接返回
        if(!currentFile.isDirectory()){
            return ;
        }

        File[] files = currentFile.listFiles();
        //如果当前文件不存在或者当前文件为空时,直接返回
        if(files == null || files.length == 0){
            return ;
        }

        //递归遍历该目录下的文件
        for(File f : files){
            //如果是普通文件,判断文件名是否符合要求并提示用户删除
            if(f.isFile()){
                doDelete(f,key);
            }else{
                //如果是目录,继续递归
                scan(f,key);
            }
        }
    }

    private static void doDelete(File f, String key) {
        if(!f.getName().contains(key)){
            //文件名中不包含指定的关键字
            return ;
        }
        //提示用户,是否确认要删除
        Scanner scanner = new Scanner(System.in);
        System.out.println("查找到一个对应的文件路径: " + f.getAbsolutePath());
        System.out.print("这个文件路径 " + f.getAbsolutePath() + " 是否确认要删除 Y/N -> ");
        String choice = scanner.next();
        if(choice.equals("Y") || choice.equals("y")){
            f.delete();
        }
    }

    public static void main(String[] args) {
        System.out.print("请输入要搜索的路径:");
        Scanner scanner = new Scanner(System.in);
        String rootPath = scanner.next();
        File rootFile = new File(rootPath);
        if(!rootFile.isDirectory()){
            System.out.println("输入的文件路径不存在");
            return ;
        }
        System.out.print("请输入要删除的文件名的关键字:");
        String key = scanner.next();
        //进行递归查找
        scan(rootFile,key);
    }
}

运行结果(这里查找到的文件路径有许多,展示部分):

4.2案例二:

要求:实现复制文件, 把一个文件里的每个字节都读出来, 写入到另一个文件中

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

public class IOTest2 {
    // 实现复制文件, 把一个文件里的每个字节都读出来, 写入到另一个文件中
    public static void main(String[] args) {
        // 1. 输入路径, 并且做校验
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入源文件的路径: ");
        String srcPath = scanner.next();
        File srcFile = new File(srcPath);
        if (!srcFile.isFile()) {
            System.out.println("源文件路径有误!");
            return;
        }
        System.out.print("请输入目标文件的路径: ");
        String destPath = scanner.next();
        File destFile = new File(destPath);
        if (!destFile.getParentFile().isDirectory()) {
            System.out.println("目标文件的路径有误!");
            return;
        }

        // 2. 执行复制的过程
        try (InputStream inputStream = new FileInputStream(srcFile);
             OutputStream outputStream = new FileOutputStream(destFile)) {
            while (true) {
                byte[] buffer = new byte[1024];
                int n = inputStream.read(buffer);
                System.out.println("n = " + n);
                if (n == -1) {
                    break;
                }
                // 需要把 buffer 写入到 outputStream 中
                outputStream.write(buffer, 0, n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果(原本test1.txt中数据为“你好世界”,而test2.txt中为空,复制完成后):

4.3.案例三:

要求:扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Scanner;

public class IOTest3 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入要查找的目录: ");
        String srcString = scanner.next();
        File srcFile = new File(srcString);
        if(!srcFile.isDirectory()){
            System.out.println("输入的文件目录有误!");
            return ;
        }

        System.out.print("请输入要查询的关键词: ");
        String key = scanner.next();
        scan(srcFile,key);
    }

    private static void scan(File srcFile, String key) {
        if(!srcFile.isDirectory()){
            //如果不是目录,结束递归
            return ;
        }

        File[] files = srcFile.listFiles();
        if(files == null || files.length == 0){
            return ;
        }
        //递归遍历目录下的文件
        for(File f : files){
            if(f.isFile()){
                //进行后续的查询操作
                doReserch(f,key);
            }else{
                scan(f,key);
            }
        }
    }

    private static void doReserch(File f, String key) {
        //打开文件,读取文件内容,判断文件内容中是否包含 key
        StringBuilder stringBuilder = new StringBuilder();
        try(Reader reader = new FileReader(f)){
            char[] buffer = new char[1024];
            while(true){
                int n = reader.read(buffer);
                if(n == -1){
                    break;
                }
                String s = new String(buffer,0,n);
                stringBuilder.append(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        if(stringBuilder.indexOf(key) == -1){
            //没找到
            return ;
        }
        //找到了
        System.out.println("找到匹配文件: " + f.getAbsolutePath());
    }
}

运行结果:

参考文章:

Java IO 基础知识总结 | JavaGuide

结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值