Java学习 day16 File

File类

绝对路径和相对路径

  • 绝对路径
    • 绝对路径名是完整的路径名,根据绝对路径可以唯一确认文件和目录
    • 例如:E:\demo\first\a.txt
  • 相对路径
    • 相对路径是不完整的路径名,只依赖相对路径不能唯一确认文件和目录
    • 相对路径名必须使用其他路径名的信息进行解释,也就是常说地相对于“某个路径”

绝对路径可以唯一确认一个文件,相对路径却不可以

那么我们在IDEA中写代码,如果我们使用一个相对路径来表示文件

那这个相对路径又是相对于谁呢?

  • 默认情况下,java.io包中的类总是根据当前用户目录来解析相对路径名

  • 此目录由系统属性user.dir指定,通常是 Java虚拟机的调用目录

  • 可以使用以下代码获取

    • System.getProperty("user.dir")
      
  • 这个属性默认是project的根目录

  • 可以在run configuration中修改

  • 一般情况下默认就好了

  • 普遍来说,在Java程序中应该优先使用绝对路径,因为相对路径会随着环境的改变而指向不同的文件

不同操作系统下路径名表示的符号其实是有区别的

Microsoft Windows平台

  • Windows操作系统下,包含盘符的路径名前缀由驱动器号和一个 “:” 组成

  • 后面不同层级目录用“\”或者“\\”表示

  • 例如

    • 绝对路径: e:\demo\a.txt
      相对路径: (相对于e:\)demo\a.txt
      

类Unix平台

包括Unix系统,Linux系统,macOS系统

  • 这些系统是没有盘符标识的,而是用一个“/”表示根目录

  • 绝对路径就是从根目录开始的,一个完整的目录,后面的每个层级都用“/”分隔

  • 相对路径则不从根目录开始

  • 例如

    • 绝对路径:/home/demo/a.txt
      相对路径:(相对于/home/demo)a.txt
      根目录:/
      

转义字符 ‘\xxx’

  • '\t'表示制表符
    
  • '\r'表示回车
    
  • '\n'表示换行
    
  • '\\'表示字符串"\"
    

根据以上种种特征,那么我们怎么在Java程序中表示一个文件或者目录呢?

难道我们需要在用Windows写代码测试的时候用“\\”,而在代码上线后用"/"吗?

  • 当然不需要,Java早已是一门成熟的语言,跨平台性上,已经对路径符号作了优化
  • 你可以自由选择以下一种方式书写路径名,都是可以的
    • 全部用“//”
    • 全部用“\\”(推荐使用)
    • 全部用“/”
  • 不要使用“\”,单独使用“\”,这是一个转义字符

File类的使用

首先,在使用File之前,再明确一下File类的定义

File是文件和目录(文件夹)路径名的抽象表达形式F

  • File类是对文件、目录的抽象表示,并不代表这个文件和目录就一定存在

  • 创建File类对象的时候,编译器也不会去检查这个File对应的文件和目录是否存在,只是将我们给的地址当成一段字符

  • 用一个file对象调用以下方法,可判断该目录文件是否存在

    public boolean exists()
    

File类的构造方法

//创建一个File对象,该方法一般使用绝对路径来创建对象,也可以使用相对路径
File (String pathname)
    
//和第一种方式类似,只不过把一个路径劈成了两半
//普遍来说,parent路径表示一个绝对路径。child路径跟一个相对路径
File (String parent, Sting child)
    
//和第二种方式一样,只不过,子路径用一个File对象表示
File (File parent, String child)

File API

下面来学习File API的使用

几个属性

创建功能

//只负责创建文件,目录路径如果不存在,会报错而不是帮你创建
public boolean createNewFile() 

//只负责创建目录,但只能创建单层目录,如果有多级目录不存在的话,创建失败
public boolean mkdir()
    
//只负责创建目录,但可以创建多级目录,如果多级目录不存在,则帮你全部创建
public boolean mkdirs()
  • createNewFile()只能创建文件,不能创建目录,会报错
  • mkdir()和mkdirs()的区别就在于能否创建多级目录
    • 需要注意的是,它两个都不能创建文件
    • 如果File对象路径中包括文件名,它会把文件名当成目录名处理

删除功能

public boolean delete()
  • 删除此抽象路径名表示的文件或目录。如果此路径名表示一个目录,则该目录必须为空才能删除

移动且重命名文件功能

public boolean renameTo(File dest)
  • 当源文件和修改之后的目标文件,在同一目录的时候,效果只是重命名
  • 当源文件和修改之后的目标文件,不在同一目录的时候,效果是移动且重命名
  • 当源文件和修改之后的目标文件,同目录同名时,方法返回true,实际没有效果
  • 真正操作文件,应该使用(IO流操作)

判断功能

//判断File对象是否表示的是一个文件
public boolean isFile()
    
//判断File对象是否表示的是一个目录
public boolean isDirectory()
    
//判断File对象表示的文件或目录,是否真实存在
public boolean exists()

//判断File对象表示的文件,是否可读
public boolean canRead()

//判断File对象表示的文件,是否可写
public boolean canWrite()

//判断File对象表示的文件是否是隐藏文件
public boolean isHidden()

获取功能

//获取File对象表示的抽象文件的绝对路径
public File getAbsolutePath()

//获取File对象表示的抽象路径名的字符串,简单来说,创建的时候给的是什么就输出什么
public String getPath()

//获取File对象表示的文件或者目录的文件名
public String getName()
    
//返回由此抽象路径名表示的文件的所占硬盘空间大小,以字节为单位
//但是需要注意的是,这个方法只能获取文件的大小,不能获取目录大小
public long length()

//返回此File对象表示的文件的最后一次修改的时间
public long lastModified()

高级获取功能

//返回一个字符串数组,这些字符串包括,此抽象的路径名表示的目录中的所有文件和文件夹的名字
//如果File对象表示的是一个文件,则返回null
//只能获取当前目录的下一层,并不是获取所有层级
//如果是一个空目录,返回一个长度为0的数组,而不是null
public String[] list() 
    
    
//返回指定File目录下的文件和文件夹的绝对路径形式的File对象数组
//如果File对象表示的是一个文件,则返回null
//只能获取当前目录的下一层,并不是获取所有层级
//如果是一个空目录,返回一个长度为0的数组,而不是null
public File[] listFiles()

自定义获取功能

//获取这个文件夹下,满足filter过滤器的条件的文件
File[] listFiles(FileFilter filter) 
  • 自定义获取功能是在高级获取功能的基础上,加了一个过滤器,所以高级功能的特点它都有

  • FileFilter是一个接口,它只有下面一个方法

    • //测试指定抽象路径名是否应该包含在某个路径名列表中
      boolean accept(File pathname)
      
    • 这个方法相当于把高级功能中listFiles()获取的File数组中File对象遍历一遍,然后逐个判断

    • 符合条件的留下,不符合条件的干掉(丢弃)-

  • 常用匿名内部类来做实现

//留下所有txt文件
public class FileTest2 {
    public static void main(String[] args) {
        File file = new File("E:\\temp");
        //匿名内部类创建一个过滤器
        FileFilter fileFilter = new FileFilter() {
            @Override
            public boolean accept(File dir) {
                //条件是 dir对象是一个文件并且它的名字以txt结尾
                return dir.isFile() && dir.getName().endsWith("txt");
            }
        };
        //在有过滤器的情况下创建一个File[]数组,并且遍历
        File[] files = file.listFiles(fileFilter);
        for(File f : files){
            System.out.println(f);
        }
    }
  • 补充Arrays.sort(files, new Comparator())方法
    • 带比较器的File数组排序方法

递归删除目录的思路

  • 获取目录的下的所有File对象(包括文件和文件夹)
  • 判断,如果是一个空目录或者file对象不是一个目录而是文件
    • 直接删除
  • 程序执行到这里,那么一定是一个目录,且不是空目录
    • 遍历获取的file数组
    • 如果这个file对象仍然是一个目录,递归删除该目录
    • 如果这个file对象是文件,直接删除
  • 最后不要忘记删除已经是空目录的当前目录

作业

File练习题
递归删除目录(删除方法有风险,一定要慎重考虑使用)

目录结构为如下(尽量不要在c盘中测试)
firstLevel目录中,包含一个secondLevel目录和a1.txt和b1.java文件
secondLevel目录中包含dir1和dir2两个目录,和a2.txt和b2.java文件
dir1目录中包含a3.txt和b3.java文件
dir2目录是一个空目录
要求删除firstLevel目录

public class Demo03 {
  public static void main(String[] args) {
      File file = new File("/Users/chelsea-he/Documents/JAVA33th/firstLevel/secondLevel/b2.java");

       //File[] files = file.listFiles();
       // System.out.println(files);  // 当文件是空目录时,产生当文件数组不是null,只是长度为0
      // 当文件名代表的文件,不是一个目录的时候,files为null

      FileUtils.deleteFiles(file);

  }
}
class FileUtils{

  public static void deleteFiles(File file){
      File[] files = file.listFiles();
      if(files == null || files.length == 0){
          file.delete();
          return;
      }
      for (int i = 0; i < files.length; i++) {
          deleteFiles(files[i]);
          if(files[i].isDirectory()){
              files[i].delete();
          }
      }
      file.delete();
  }
}   
     

io概述(掌握)

什么是IO

  • i:input 输入
  • o:output 输出

为什么有io

  • 把数据保存到磁盘Output
  • 把文件数据读取到内存Input
  • 内存有限,就存在io交互

java中如何实现io功能

  • 通过流的方式(Stream)

在这里插入图片描述

io分类

按照流向分(以内存为参照)

  • 输入流 input 外设→内存
  • 输出流 output 内存→外设

按照数据类型分

  • 字节流 按照一个字节一个字节进行传输 1B=8bit 0000 0000
  • 字符流 一连串的字符序列 (一种文化符号 宝, ABC , の)

4个基类

  • 字节输出流 OutputStream
  • 字节输入流 InputStream
  • 字符输出流 Writer
  • 字符输入流 Reader

由这4个基类派生的子类,都是以其父类名作为后缀的

FileOutputStream

FileInputStream


字节流和字符流

字节流和字符流的差别不大,它们的区别主要是它们可以操作的最小数据单元不同,字节流可以操作的最小数据单元是8位字节,字符流可以操纵的最小数据单元是16位的字符

什么时候该用什么流

文本数据,字符流去处理

非文本数据,字节流去处理 不知道什么类型就用字节流(字节流是万能的)

字节流(重点)

字节输出流

基类

OutputStream

此抽象类是表示输出字节流的所有类的超类

继承关系

在这里插入图片描述


成员方法

voidclose() 关闭此输出流并释放与此流有关的所有系统资源。
voidflush() 刷新此输出流并强制写出所有缓冲的输出字节。
voidwrite(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。
voidwrite(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract voidwrite(int b) 将指定的字节写入此输出流。

具体子类

FileOutputStream

继承关系

在这里插入图片描述


构造方法

FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。

demo

package com.cskaoyan.bytestream.out;

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

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo1 {
    public static void main(String[] args) throws IOException {
        //| FileOutputStream(File file)       
        // 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
        File file = new File("a.txt");
        FileOutputStream outputStream = new FileOutputStream(file);
        // 传String 文件名
        FileOutputStream outputStream1 = new FileOutputStream("b.txt");
    }
}


成员方法:

voidwrite(byte[] b) 将 b.length 个字节从指定 byte 数组写入此文件输出流中。
voidwrite(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
voidwrite(int b) 将指定字节写入此文件输出流。

注意:write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。或者你直接理解为write只接收byte,你传入了int会自动剪切


怎么写数据

write Demo

package com.cskaoyan.bytestream.out;

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

/**
 * @description: write方法
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 创建字节输出流对象
        FileOutputStream out = new FileOutputStream("a.txt");
        // 写数据 write方法
        // write(int b)
        //out.write(97);

        // write(byte[] b)
        String s= "hello world";
        byte[] bytes = s.getBytes();
        //out.write(bytes);
        // write(byte[] b,int off,int len)
        out.write(bytes, 0, bytes.length);
        // 关闭资源close
        out.close();
    }
}

注意事项(重要)

  • 创建字节输出流对象发生了什么?

    • 创建字节输出流之前,jvm会到操作系统中找文件是否存在
    • 如果不存在,帮我们创建
    • 如果存在,会覆盖掉
  • 怎么去实现换行功能?

    • package com.cskaoyan.bytestream.out;
      
      import java.io.FileOutputStream;
      import java.io.IOException;
      
      /**
       * @description:
       * @author: songtao@cskaoyan.onaliyun.com
       **/
      
      public class Demo3 {
          public static void main(String[] args) throws IOException {
              // 实现换行功能
              // 第一种 win 的换行符  \r\n ,Mac直接\n即可
              // 第二种 系统默认换行符
              // 创建输出流对象
              FileOutputStream out = new FileOutputStream("a.txt");
              // 写点数据
              out.write(97);
      
              // 换行
              //out.write("\r\n".getBytes());
              out.write(System.lineSeparator().getBytes());
              // 写点数据
              out.write(98);
      
              // close
              out.close();
              // a
              // b
              // ab
          }
      }
      
      
  • 如何实现文件追加?(借助构造方法)

    • append - 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处

    •     public static void main(String[] args) throws IOException {
              // 创建可以追加的输出流对象
              FileOutputStream out = new FileOutputStream("a.txt", true);
              // write
              out.write(99);
              // close
              out.close();
          }
      
  • 为什么要close?

    • io资源是操作系统资源,我们的jvm不能回收,所以只能通过close方法显式的去释放资源
    • 不属于jvm的资源 都要close
  • 怎么异常处理

    • 第一种 传统的try catch

    • package com.cskaoyan.bytestream.out;
      
      import java.io.FileNotFoundException;
      import java.io.FileOutputStream;
      import java.io.IOException;
      
      /**
       * @description: 异常处理
       * @author: songtao@cskaoyan.onaliyun.com
       **/
      // try-with-resources
      public class Demo5 {
          public static void main(String[] args)  {
              // 创建输出流对象
              FileOutputStream out = null;
              try {
                  out = new FileOutputStream("a.txt");
                  // 写数据
                  out.write("hello".getBytes());
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              }finally {
                  //close
                  try {// 判断是否为null
                      if (out != null) {
                          out.close();
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
      
          }
      }
      
      
    • 第二种

字节输入流

基类

具体子类

字符流(重点)

其他流(了解)

总结

作业

1.分别键盘输入文件名 和 文件内容,并按照文件名保存相应的内容

public class Demo01 {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入要创建的文件名:");
        File file = new File(sc.nextLine());
        FileOutputStream outputStream = new FileOutputStream(file);
        System.out.print("请输入文件内容:");
        String str = sc.nextLine();
        byte[] bytes = str.getBytes();
        try {
            outputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.键盘输入文件名,文件内容,按照输入的文件名,文件内容保存。要求输入内容的时候可以多次追加写入,以一个约定字符串表示结束输出内容,比如当输入end时表示终止内容输入。

package homework;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Demo02 {
    public static void main(String[] args) {
        System.out.println("请输入文件地址及文件名:");
        Scanner sc = new Scanner(System.in);
        File file = new File(sc.nextLine());
        FileOutputStream output = null;
        try {
            output = new FileOutputStream(file,true);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        String str = null;
        System.out.println("请输入文件内容:");
        str = sc.nextLine();

        while(!"end".equals(str)){
            byte[] bytes = str.getBytes();
            try {
                if (output != null) {
                    output.write(bytes);
                    output.write("\n".getBytes());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            str = sc.nextLine();

        }
        try {
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.定义一个这样的一个words数组,数组中每个字符串的格式为“词性:单词”

String[] words = {“verb:eat”,“verb:drink”,“verb:sleep”,“verb:play”,“noun:rice”,“noun:meat”,“noun:hand”,“noun:hair”};

根据单词性质动词verb全部存入verb.txt文件中

根据单词性质名词noun全部存入noun.txt文件中

public class Demo03 {
    public static void main(String[] args) throws IOException {
        File fileVerb = new File("/Users/chelsea-he/Documents/JAVA33th/testFile/verb.txt");
        File fileNoun = new File("/Users/chelsea-he/Documents/JAVA33th/testFile/noun.txt");
        FileOutputStream outputStream1 = new FileOutputStream(fileVerb,true);
        FileOutputStream outputStream2 = new FileOutputStream(fileNoun,true);

        String[] words = {"verb:eat","verb:drink","verb:sleep","verb:play","noun:rice","noun:meat","noun:hand","noun:hair"};
        for (int i = 0; i < words.length; i++) {
            if(words[i].startsWith("verb")){
                byte[] bytes = words[i].substring(5).getBytes();
                outputStream1.write(bytes);
                outputStream1.write("\n".getBytes());
            }else if(words[i].startsWith("noun")){
                byte[] bytes = words[i].substring(5).getBytes();
                outputStream2.write(bytes);
                outputStream2.write("\n".getBytes());
            }
        }

        outputStream1.close();
        outputStream2.close();
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值