Java学习 day16 File&IO

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)

Java学习 day16 File&IO

io分类

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

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

按照数据类型分

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

4个基类

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

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

FileOutputStream

FileInputStream

什么时候该用什么流

文本数据,字符流去处理

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

字节流(重点)

字节输出流

基类

OutputStream

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

继承关系

Java学习 day16 File&IO


成员方法

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

具体子类

FileOutputStream

继承关系

Java学习 day16 File&IO


构造方法

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");
    }
}


成员方法:

void write(byte[] b) 将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void write(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 
              // 第二种 系统默认换行符
              // 创建输出流对象
              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();
    }
}
上一篇:Eclipse错误: Your project contains error(s),please fix them before running your application


下一篇:java 对象与xml相互转换