IO流与File

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-06-25

File

import org.junit.Test;

import java.io.File;

/**
 * File类的一个对象,代表一个文件或一个文件目录
 */

public class FileTest {

  @Test
  public void test() {
    /**
     * 构造器1: File(String filePath);
     */
    // 相对路径 在单元测试中相对的是当前module 如果是类的main方法中相对的是当前工程
    File file = new File("hello.txt");

    // 路径中的分隔符 可以使用 File.separator 这个常量来代替 不用自己去分别系统
    File file1 = new File("d:\\demo\\a.txt");
    File file2 = new File("d:" + File.separator + "demo" + File.separator + "a.txt");

    System.out.println(file); // hello.txt
    System.out.println(file1); // d:\demo\a.txt
    // 不存在 也会输出传入的路径

    /**
     * 构造器2: File(String parentPath, String childPath);
     */
    File file3 = new File("/Users/upcccz/2021/learn-java2", "day01");
    System.out.println(file3); // 表示一个路径 /Users/upcccz/2021/learn-java2/day01

    File file4 = new File("/Users/upcccz/2021/learn-java2", "day01/hello.txt");
    System.out.println(file4); // 也可表示一个文件 /Users/upcccz/2021/learn-java2/day01/hello.txt


    /**
     * 构造器3: File(File parentPath, String childPath);
     * 第一个参数是一个File对象
     */
    File file5 = new File(file3, "hello.txt");
    System.out.println(file5);
  }
}

File的常用方法

1、获取功能

  • String getAbsolutePath():获取绝对路径,文件不存在会根据传入的参数返回。

  • String getPath():获取路径,文件不存在会根据传入的参数返回。

  • String getName():获取名称,文件不存在会根据传入的参数返回。

  • String getParent():获取上层文件目录路径,文件不存在会或者传入的是相对路径返回null。

  • long length():获取文件长度,即字节数,不能获取目录的长度

  • long lastModified():获取最后一次的修改时间,毫秒值,文件不存在就返回0

  • String[] list():获取指定目录下所有文件或者文件目录的名称数组,目录不存在会报错。

  • File[] listFiles():获取指定目录下所有文件或者文件目录的File数组,目录不存在会报错。

2、重命名

  • boolean renameTo(File dest):把文件重命名为指定的文件路径,返回是否重命名成功。示例file1.renameTo(file2),要想保证返回true,需要file1在硬盘中是存在的,file2不能在硬盘中存在。

3、判断功能,如果文件或文件目录不存在,以下方法都返回false。

  • boolean isDirectory():判断是否是文件目录

  • boolean isFile():判断是否是文件

  • boolean exists():判断是否存在

  • boolean canRead():判断是否可读

  • boolean canWrite():判断是否可写

  • boolean isHidden():判断是否隐藏

4、创建功能

  • boolean createNewFile():创建文件,若文件存在则不创建,返回false。

  • boolean mkdir():创建文件目录,如果文件目录存在,就不创建,如果此文件目录的上层目录不存在,也不创建。

  • boolean mkdirs():创建文件目录,如果上层文件目录不存在,一并创建。

如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下。

5、删除功能

  • boolean delete():删除我呢间或文件夹,如果要删除一个文件目录,该文件目录内不能包含文件或文件目录。
@Test
public void test() {
  File f = new File("abc.txt");

  if (!f.exists()) {
    f.createNewFile();
    System.out.println("创建成功");
  } else {
    f.delete();
    System.out.println("删除成功");
  }
}

总结:

  • File类声明在java.io包下

  • File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作,如果需要读取或写入文件内容,必须使用IO流来完成、

  • 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的结点。

IO流

Input/Output,用于处理设备之间的数据传输,如读写文件,网络通讯等。对于数据的输入/输出操作以“流(stream)”的方式进行。java.io包下提供了各种“流”类或接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

  • 按操作数据单位不同分为:字节流(8bit),如图片、视频,字符流(16bit),如文本。
  • 按数据流的流向不同分为:输入流、输出流
  • 按流的角色不同分为:节点流(也称文件流,作用在文件上)、处理流(作用在已有的流的基础之上的,可叠加,如缓冲流)

在java中IO流共设计40多个类,实际上非常规则,都是从如下4个抽象基类派生的。

抽象基类 节点流(或文件流) 缓冲流(处理流的一种)
字节流: InputStream FileInputStream BufferedInputStream
字节流: OutputStream FileOutputStream BufferedOutputStream
字符流: Reader FileRead BufferedReader
字符流: Writer FileWriter BufferedWriter

FileReader

1、read()

import org.junit.Test;

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

public class StreamTest {

  @Test
  public void testFileReader()  {

    FileReader fr = null;

    // 为了保持流资源一定可以执行关闭操作,需要用try-catch-finally处理
    // 读操作 要求文件存在,否则会报FileNotFoundException

    try {
      // 1、实例化File类的对象,指明要操作的文件
      File file = new File("hello.txt");

      // 2、提供具体的流
      fr = new FileReader(file);

      // 3、数据的读入
      // read(): 返回读入的一个字符,如果达到了末尾,返回-1
      int data;
      while((data = fr.read()) != -1) {
        System.out.print((char) data);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      // 4、流的关闭操作,不然会有内存泄露
      try {
        if (fr != null) {
          fr.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}

2、read(char[] cbuf)

import org.junit.Test;

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

public class StreamTest {
  @Test
  public void testFileReader1() {
    FileReader fr = null;

    try {
      File file = new File("hello.txt");
      fr = new FileReader(file);

      // read(char[] cbuf): 返回每次读入cbuf数组中的字符的个数,如果达到文件末尾,返回-1
      // 读操作 改为一次读多个
      char[] cbuf =new char[5];

      int len;
      while((len = fr.read(cbuf)) != -1) {
        // 方式一:
        // 错误的写法 读整个cbuf
        // for (int i = 0; i < cbuf.length; i++) {
        //   System.out.print(cbuf[i]); // aaaa123aa1
        //   // hello.txt里面的文本是aaaa123
        //   // 每次读5个 第一次读完 aaaa1
        //   // 然后接着读 是直接替换的 23aa1
        //   // 最后到末尾了循环结束,所以打印出aaaa123aa1
        // }

        // 正确的写法 只读cbuf中当前读的
        // for (int i = 0; i < len; i++) {
        //   System.out.print(cbuf[i]); // aaaa123
        // }

        // 方式二:将char[] 转换为String
        // 错误的写法 对应方式一种错误的写法
        // String str = new String(cbuf);
        // System.out.print(str); // aaaa123aa1

        // 正确的写法
        String str = new String(cbuf, 0, len);
        System.out.print(str); // aaaa123
      }

    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (fr != null) {
          fr.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}

FileWriter

import org.junit.Test;

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

public class FileWriterTest {

  @Test
  public void testFileWriter() {
    // 1、提供File类的对象,指明写出到的文件
    File file = new File("abc.txt");

    // 2、提供FileWriter的对象,用于数据的写出
    FileWriter fw = null;

    try {
      // 每次程序执行都是重写,而不是追加,如果执行的追加的方式,第二个参数传入true
      // fw = new FileWriter(file, true);
      fw = new FileWriter(file);
      // 3、写出操作 文件不存在时会帮我们创建
      fw.write("hello world");
      fw.write("123456");
      // 不会换行 需要加\n
      fw.write("789\n");
      fw.write("第二行");
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (fw != null) {
        try {
          // 4、关闭操作
          fw.close();
        }catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

FileInputStream/FileOutputStream

与上面的基本流程基本不变,如下实现一个图片复制:

import org.junit.Test;

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

/**
 * 图片复制
 */
public class FileInputStreamTest {
  @Test
  public void testFileInputStream() {
    // 1、提供File类的对象,指明写出到的文件
    File src = new File("1.jpg");
    File dest = new File("2.jpg");

    // 2、提供流对象
    FileInputStream fis = null;
    FileOutputStream fos = null;

    try {
      fis = new FileInputStream(src);
      fos = new FileOutputStream(dest);

      // 复制 开发中常写为 new byte[1024]
      byte[] buffer = new byte[5];
      int len;
      // 3、读数据
      while((len = fis.read(buffer)) != -1) {
        // 4、写数据
        fos.write(buffer, 0, len);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (fis != null) {
        try {
          // 5-1、关闭操作
          fis.close();
        }catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (fos != null) {
        try {
          // 5-2、关闭操作
          fos.close();
        }catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

缓冲流

缓冲流的作用:提高流的读取、写入的速度,而能提高速度的原因是内部提供了一个缓冲区。

1、BufferedInputStream / BufferedOutputStream

import org.junit.Test;

import java.io.*;

public class BufferedTest {

  @Test
  public void test() {
    // 1、造文件
    File src = new File("1.jpg");
    File dest = new File("3.jpg");

    FileInputStream fis = null;
    FileOutputStream fos = null;
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;

    try {
      // 2.1、造节点流
      fis = new FileInputStream(src);
      fos = new FileOutputStream(dest);

      // 2.2、造缓冲流
      bis = new BufferedInputStream(fis);
      bos = new BufferedOutputStream(fos);

      // 复制
      byte[] buffer = new byte[5];
      int len;
      // 3、读数据
      while((len = bis.read(buffer)) != -1) {
        // 4、写数据
        bos.write(buffer, 0, len);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      // 要先关闭外层的流,再关内层的流
      // 关闭外层流的同时,会关闭内层的流 所以常常只调用内层流的关闭操作
      if (bos != null) {
        try {
          bos.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (bis != null) {
        try {
          bis.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

2、BufferedReader / BufferedWriter

public class TestBuffered {

  // 开发中应该使用try/catch包裹, 而不是throws
  @Test
  public void test2() throws IOException {
    // new File可以省略,直接将path传给FileReader一样
    BufferedReader br = new BufferedReader(new FileReader(new File("abc.txt")));
    BufferedWriter bw = new BufferedWriter(new FileWriter(new File("abc1.txt")));


    // 使用char[] 数组
    // char[] cbuf = new char[1024];
    // int len;
    // while((len = br.read(cbuf)) != -1) {
    //   bw.write(cbuf, 0, len);
    // }

    // 使用String
    String data;
    while((data = br.readLine()) != null) {
      // data中不包含换行符
      bw.write(data + "\n");  // 直接拼接换行符

      // 或者调用一下newLine()方法
      // bw.write(data);
      // bw.newLine();
    }

    bw.close();
    br.close();
  }
}

字节流能对字符流文件进行复制,不在程序中读就行,只当搬运工,当字符流不能对字节流文件进行复制。

转换流

转换流:是处理流的一种,属于字符流,作用是提供字节流与字符流之间的转换。

InputStreamReader: 将一个字节的输入流转换为字符的输入流 OutputStreamReader: 将一个字符的输出流转换为字节的输出流

解码:字节、字节数组 —> 字符数组、字符串 编码:字符数组、字符串 —> 字节、字节数组

import org.junit.Test;
import java.io.*;

public class InputStreamReaderTest {

  @Test
  public void test1() throws IOException {
    // 使用字节流去处理字符流文件
    FileInputStream fis = new FileInputStream("abc.txt");

    // 使用转换流,将一个字节的输入流转换为字符的输入流
    // 第二个参数指明了字符集,具体使用哪个字符集取决于fis这个文件保存时使用的字符集,不传默认使用系统默认的字符集
    InputStreamReader isr = new InputStreamReader(fis, "UTF-8");

    char[] cbuf = new char[20];
    int len;
    while((len = isr.read(cbuf)) != -1) {
      String str = new String(cbuf, 0, len);
      System.out.print(str);
    }

    isr.close();
  }


  @Test
  public void test2() throws IOException {
    File file1 = new File("abc.txt");
    File file2 = new File("abc_gbk.txt");

    FileInputStream fis = new FileInputStream(file1);
    FileOutputStream fos = new FileOutputStream(file2);

    InputStreamReader isr = new InputStreamReader(fis, "utf-8");
    OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");

    char[] cbuf = new char[20];
    int len;
    while((len = isr.read(cbuf)) != -1) {
      osw.write(cbuf, 0, len);
    }

    isr.close();
    osw.close();
  }
}

标准流

import org.junit.Test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class StreamTest2 {

  /**
   * System.in: 标准的输入流,默认从键盘输入,类型InputStream
   * System.out: 标准的输出流,默认从控制台输出,类型PrintStream
   *
   * System类的setIn(InputStream in) 、SetOut(PrintStream, out)方法能重新指定输入和输出的流
   */

  /**
   * 练习:从键盘输入字符串,要求将读取到的郑航字符串转成大写输出,然后继续进行输入操作
   * 直至单独输入e或者exit时,退出程序
   *
   * 使用System.in实现, System.in ---> 转换流 ---> BufferedReader的readLine() 可以读整行,当用户回车时代表输入完了一行
   */
  @Test
  public static void main(String[] args) throws IOException {
    InputStreamReader isr = new InputStreamReader(System.in);
    BufferedReader br = new BufferedReader(isr);

    while (true) {
      System.out.println("请输入字符串");
      String data = br.readLine(); // 开始读取用户的输入
      if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
        System.out.println("程序结束");
        break;
      }

      String s = data.toUpperCase();
      System.out. (s);
    }

    br.close();
  }
}

打印流

打印流:PrintStream 和 PrintWriter两个类,提供了一系列重载的print()println()方法,所以System.out.print才能传入不同的数据类型。

以下联系就是更改了System的打印流,将控制台输出改成以写文件的方式输出,并打印出对应ASCII码

import org.junit.Test;

import java.io.*;

public class StreamTest3 {

  @Test
  public void test() throws IOException {

    FileOutputStream fos = new FileOutputStream(new File("ascii.txt"));

    PrintStream ps = new PrintStream(fos, true);

    if (ps != null) {
      System.setOut(ps); // 把标准输出流(控制台输出)改为以写文件方式输出
    }

    for (int i = 0; i < 255; i++) {
      System.out.print((char) i);

      if (i % 50 == 0) {
        System.out.println();
      }
    }
  }
}

数据流

DataInputStream和DataOutputStream,用于读取或写出基本数据类型的变量或字符串。

import org.junit.Test;
 import java.io.*;

public class StreamTest4 {


  /**
   * 将内存中的字符串、基本数据类型的变量写到文件中
   * 所以写出的data.txt不能直接双击打开看 会乱码
   * 是需要使用DataInputStream来读的
   */
  @Test
  public void test() throws IOException {
    DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

    dos.writeUTF("jack");
    dos.flush(); // 刷新操作,将内存中的数据写入文件
    dos.writeInt(23);
    dos.writeBoolean(true);

    dos.close();
  }


  /**
   * 将文件中存储的基本数据类和字符串读取到内存中,保存在变量中
   * 读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致
   */
  @Test
  public void test2() throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

    // 读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致
    String name = dis.readUTF();
    int age = dis.readInt();
    boolean isMale = dis.readBoolean();

    System.out.println("name=" + name);
    System.out.println("age=" + age);
    System.out.println("isMale=" + isMale);
  }
}

对象流

用于存储和读取基本数据类型数据或对象的处理流,它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

序列化:用ObjectOutputStream类保存基本类型数据或对象的机制。

反序列化:用ObjectInputStream类读取基本类型数据或对象的机制

ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。

import org.junit.Test;

import java.io.*;

public class StreamTest5 {
  /**
   * 应该使用try-catch处理异常,这里只是为了方便
   *
   * 序列化过程
   */
  @Test
  public void test() throws IOException {
    /**
     * 同样创建的data1文件也不能双击打开查看,会乱码,应使用ObjectInputStream读取
     */
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data1.txt"));

    oos.writeObject(new String("123"));
    oos.flush();  // 刷新操作
    oos.close();
  }

  /**
   * 将磁盘文件中的对象还原为内存中的一个java对象
   * 同样需要按写入的顺序读取
   */
  @Test
  public void test2() throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data1.txt"));

    Object obj = ois.readObject();
    String str = (String) obj;
    System.out.println(str); // 123
    ois.close();
  }
}

如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,该类必须实现如下两个接口之一,否则会抛出NotSerializableException异常。

  • Serializable:属于标识接口,没有任何具体内容。
    • 需要提供一个静态常量serialVersionUID,因为不加java会自动生成一个,但你改变这个类的时候,serialVersionUID也会改变,将无法完成反序列化。
    • 除了当前类需要实现Serializable接口外,还要保证其内部所有属性必须是可序列化的。
  • Externalizable

随机存取文件流

RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类,并且它实现了DataInput、DataOutput这两个接口,意味着这个类及可以读也可以写。

它支持“随机访问”的方式,程序可以直接跳到文件的任意位置来读、写文件。

  • 支持只访问文件的部分内容
  • 可以向已存在的文件后追加内容
  • 如果作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建,如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)

包含一个记录指针,用以标示当前读写处的位置,也可以自由的移动记录指针。

  • long getFilePointer():获取文件记录指针的当前位置。
  • void seek(long pos):将文件记录指针定位到pos位置。

代码示例如下:

import org.junit.Test;

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

public class StreamTest6 {

  @Test
  public void test() throws IOException {
    /**
     * 第二个参数是mode
     *
     * r: 以只读方式打开
     * rw: 打开以方便读取和写入
     * rwd: 打开以便读取和写入;同步文件内容的更新
     * rws:打开以便大区和写入;同步文件内容和元数据的更新
     *
     * 如果模式为r,则不会创建文件,而是会去读写一个已经存在的文件,如果一个不存在的文件则会出现异常
     * 如果模式为rw,如果文件不存在,就会去创建文件。
     */
    RandomAccessFile raf1 = new RandomAccessFile(new File("1.jpg"), "r");
    RandomAccessFile raf2 = new RandomAccessFile(new File("4.jpg"), "rw");

    byte[] buffer = new byte[1024];
    int len;
    while((len = raf1.read(buffer)) != -1) {
      raf2.write(buffer, 0, len);
    }

    raf1.close();
    raf2.close();
  }

  /**
   * 使用RandomAccessFile实现数据的插入效果
   */
  @Test
  public void test3() throws IOException {

    RandomAccessFile raf1 = new RandomAccessFile("abc.txt","rw");

    //将指针调到角标为3的位置
    raf1.seek(3);

    //保存指针3后面的所有数据到StringBuilder中
    StringBuilder builder = new StringBuilder((int) new File("abc.txt").length());

    byte[] buffer = new byte[20];
    int len;
    while((len = raf1.read(buffer)) != -1){
      builder.append(new String(buffer,0,len));
    }

    //调回指针,写入“xyz”
    raf1.seek(3);
    raf1.write("xyz".getBytes());

    //将StringBuilder中的数据写入到文件中
    raf1.write(builder.toString().getBytes());
    raf1.close();
  }
}

NIO

Java NIO(New IO, Non-Blocking IO)是Java 1.4版本开始引入的一套新的IO API,可以替代标注你的Java IO API,与原来的IO有同样的作用和目的,但是使用方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作,NIO将以更加高效的方式进行文件的读写操作。

JavaAPI中提供了两套NIO,一套是针对标准输入输出的NIO,另一套就是网络编程NIO。

升级版的NIO2引入了Path接口,代表一个平台无关的平台路径,描述了目录结果中文件的位置,Path可以看出是File类的升级版本,实际引用的资源也可以不存在。另外还提供了Files、Paths工具类,Files包含了大量静态的工具方法来操作文件;Paths则包含了两个返回Path的静态工厂方法。

Path

Paths类提供的静态get()方法用来获取Path对象

  • static Path get(String first, Stirng second, ...):用于将多个字符串串连成路径。
  • static Path get(URI uri):返回指定uri对应的Path路径
import org.junit.Test;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathTest {
  // 如何使用Paths实例化Path
  @Test
  public void test1() {
    Path path1 = Paths.get("d:\\nio\\hello.txt"); //new File(String filepath)
    Path path2 = Paths.get("d:\\", "nio\\hello.txt"); //new File(String parent,String filename);

    System.out.println(path1);
    System.out.println(path2);

    Path path3 = Paths.get("d:\\", "nio");
    System.out.println(path3);
  }

  // Path中的常用方法
  @Test
  public void test2() {
    Path path1 = Paths.get("d:\\", "nio\\nio1\\nio2\\hello.txt");
    Path path2 = Paths.get("hello.txt");

    // String toString() : 返回调用 Path 对象的字符串表示形式
    System.out.println(path1);

    // boolean startsWith(String path) : 判断是否以 path 路径开始
    System.out.println(path1.startsWith("d:\\nio"));

    // boolean endsWith(String path) : 判断是否以 path 路径结束
    System.out.println(path1.endsWith("hello.txt"));

    // boolean isAbsolute() : 判断是否是绝对路径
    System.out.println(path1.isAbsolute() + "~");
    System.out.println(path2.isAbsolute() + "~");

    // Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径
    System.out.println(path1.getParent());
    System.out.println(path2.getParent());

    // Path getRoot() :返回调用 Path 对象的根路径
    System.out.println(path1.getRoot());
    System.out.println(path2.getRoot());

    // Path getFileName() : 返回与调用 Path 对象关联的文件名
    System.out.println(path1.getFileName() + "~");
    System.out.println(path2.getFileName() + "~");

    // int getNameCount() : 返回Path根目录后面元素的数量
    // Path getName(int idx) : 返回指定索引位置 idx 的路径名称
    for (int i = 0; i < path1.getNameCount(); i++) {
      System.out.println(path1.getName(i) + "*****");
    }

    // Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象
    System.out.println(path1.toAbsolutePath());
    System.out.println(path2.toAbsolutePath());

    // Path resolve(Path p) : 合并两个路径,返回合并后的路径对应的Path对象
    Path path3 = Paths.get("d:\\", "nio");
    Path path4 = Paths.get("nioo\\hi.txt");
    path3 = path3.resolve(path4);
    System.out.println(path3);

    // File toFile(): 将Path转化为File类的对象
    File file = path1.toFile(); //Path--->File的转换
    Path newPath = file.toPath(); //File--->Path的转换
  }
}

Files

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.*;
import java.util.Iterator;

public class FilesTest {
	@Test
	public void test1() throws IOException{
		Path path1 = Paths.get("d:\\nio", "hello.txt");
		Path path2 = Paths.get("atguigu.txt");
		
    // Path copy(Path src, Path dest, CopyOption … how) : 文件的复制
		// 要想复制成功,要求path1对应的物理上的文件存在。path2对应的文件没有要求。
    // Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING);
		
    // Path createDirectory(Path path, FileAttribute<?> … attr) : 创建一个目录
		// 要想执行成功,要求path对应的物理上的文件目录不存在。一旦存在,抛出异常。
		Path path3 = Paths.get("d:\\nio\\nio1");
    // Files.createDirectory(path3);
		
    // Path createFile(Path path, FileAttribute<?> … arr) : 创建一个文件
		// 要想执行成功,要求path对应的物理上的文件不存在。一旦存在,抛出异常。
		Path path4 = Paths.get("d:\\nio\\hi.txt");
    // Files.createFile(path4);
		
    // void delete(Path path) : 删除一个文件/目录,如果不存在,执行报错
    // Files.delete(path4);
		
    // void deleteIfExists(Path path) : Path对应的文件/目录如果存在,执行删除.如果不存在,正常执行结束
		Files.deleteIfExists(path3);
		
    // Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置
		//要想执行成功,src对应的物理上的文件需要存在,dest对应的文件没有要求。
    // Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE);
		
    // long size(Path path) : 返回 path 指定文件的大小
		long size = Files.size(path2);
		System.out.println(size);
	}

	@Test
	public void test2() throws IOException{
		Path path1 = Paths.get("d:\\nio", "hello.txt");
		Path path2 = Paths.get("atguigu.txt");

    // boolean exists(Path path, LinkOption … opts) : 判断文件是否存在
		System.out.println(Files.exists(path2, LinkOption.NOFOLLOW_LINKS));

    // boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录
		// 不要求此path对应的物理文件存在。
		System.out.println(Files.isDirectory(path1, LinkOption.NOFOLLOW_LINKS));

    // boolean isRegularFile(Path path, LinkOption … opts) : 判断是否是文件
    // boolean isHidden(Path path) : 判断是否是隐藏文件
		// 要求此path对应的物理上的文件需要存在。才可判断是否隐藏。否则,抛异常。
    System.out.println(Files.isHidden(path1));

    // boolean isReadable(Path path) : 判断文件是否可读
		System.out.println(Files.isReadable(path1));

    // boolean isWritable(Path path) : 判断文件是否可写
		System.out.println(Files.isWritable(path1));

    // boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在
		System.out.println(Files.notExists(path1, LinkOption.NOFOLLOW_LINKS));
	}

	/**
	 * StandardOpenOption.READ:表示对应的Channel是可读的。
	 * StandardOpenOption.WRITE:表示对应的Channel是可写的。
	 * StandardOpenOption.CREATE:如果要写出的文件不存在,则创建。如果存在,忽略
	 * StandardOpenOption.CREATE_NEW:如果要写出的文件不存在,则创建。如果存在,抛异常
	 *
	 */
	@Test
	public void test3() throws IOException{
		Path path1 = Paths.get("d:\\nio", "hello.txt");

    // InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象
		InputStream is = Files.newInputStream(path1, StandardOpenOption.READ);

    // OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象
		OutputStream os = Files.newOutputStream(path1, StandardOpenOption.WRITE,StandardOpenOption.CREATE);


    // SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。
		SeekableByteChannel channel = Files.newByteChannel(path1, StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);

    // DirectoryStream<Path>  newDirectoryStream(Path path) : 打开 path 指定的目录
		Path path2 = Paths.get("e:\\teach");
		DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path2);
		Iterator<Path> iterator = directoryStream.iterator();
		while(iterator.hasNext()){
			System.out.println(iterator.next());
		}
	}
}