JAVA高级-IO流

14 篇文章 0 订阅
11 篇文章 1 订阅

IO流

File类

说明

  • java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关

  • File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。

    如果需要访问文件内容本身,则需要使用输入/输出流。

  • 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对

象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。

  • File对象可以作为参数传递给流的构造器

  • 相对路径:IDEA在单元测试中,本module中下的路径,在main方法中,本工程下。Eclipse不区分,都是本工程下。

    绝对路径:本电脑里的文件路径,含有盘符。

  • 构造器:

    • public File(String pathname)
    • **public File(String parent,String child)**以parent为父路径,child为子路径创建File对象。
    • **public File(File parent,String child)**根据一个父File对象和子文件路径创建File对象
  • 路径分隔符和系统有关:

    • windows和DOS系统默认使用“\”来表示

    • UNIX和URL使用“/”来表示

    • 为了解决这个隐患,File类提供了一个常量:public static final String separator。根据操作系统,动态的提供分隔符。

      File file1 = new File("d:\\hyb\\info.txt");
      File file2 = new File("d:" + File.separator + "hyb" + File.separator + "info.txt");
      File file3 = new File("d:/hyb");
      

常用方法

  • public String getAbsolutePath():获取绝对路径

  • public String getPath() :获取路径

  • public String getName() :获取名称

  • public String getParent():获取上层文件目录路径。若无,返回null

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

  • public long lastModified() :获取最后一次的修改时间,毫秒值

  • public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组

  • public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组

  • public boolean renameTo(File dest):把文件重命名为指定的文件路径

    • rename是重命名,to是转到指定目录下。

    • 命名之前,要重命名的那个名字,不能为一个文件的名字,也就是不能实现存在文件。

      package com.hyb.IO;
      
      import org.junit.Test;
      
      import java.io.File;
      
      /**
       * @program: FileTest
       * @description:
       * @author: Huang Yubin
       * @create: 2021-06-14 12:44
       **/
      
      public class FileTest {
          @Test
          public void test1(){
              /*记住,这里我们是在单元测试方法中写入的相对路径,就说明是本module下的相对路径了,
              * 但如果你要在main方法里进行则是,这样写就不表明相对路径,它会显示文件不存在,若要在main函数里写入相对路径
              * 那么要写出盘符,也就是如同绝对路径那样写
              *
              * 还有一种会显示文件不存在的情况,如果你在src里建文件,肯定会显示文件不存在,因为本module不是src,这样会默认本module或者工程下没有文件
              * 而你要找到此文件,要用绝对路径。
              * */
      //        File f1=new File("hyb.txt");
              File f1 = new File("D:\\java学习\\code\\Base Grammer\\src\\com\\hyb\\IO\\hyb.txt");//这里我将文件创建在了src里的com里的hyb里的IO了,如果直接hyb.txt,会找不到文件。
              System.out.println(f1.exists());//true
      //        File f1=new File("D:\\hyb\\hello.txt");
              File f2=new File("D:\\java学习\\code\\Base Grammer\\hello.txt" );
              boolean b = f1.renameTo(f2);
              System.out.println(b);
          }
      }
      
  • public boolean isDirectory():判断是否是文件目录

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

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

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

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

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

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

  • public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。

    如果此文件目录的上层目录不存在,也不创建。

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

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

    路径下。

  • public boolean delete():删除文件或者文件夹

    删除注意事项:

    Java中的删除不走回收站

    要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录

说明

  • 借钱问题:

    站在不同角度说法不同,我借钱给你,对于我来说,我借出了钱,站在你的角度,你借进了钱。

    所以在IO流,要站在不同角度才能说明谁输入输出。

  • 流分别节点流和处理流。

  • 节点流又分为字符流和字节流,处理流是对流的处理。

    抽象类字节流(图像,视频)字符流(文本)
    输入流InputStreamReader
    输出流OutputStreamWriter
    • 注意:抽象类是不能被实例化的。
  • 从数据流向程序为输入流,从程序流向数据为输出流。

流实现

  • 下面给出流的体系结构

    https://i.loli.net/2021/06/14/48XTvcgVl7rzKe3.png

InputStream & Reader
* InputStream 和 Reader 是所有输入流的基类。
* InputStream(典型实现:FileInputStream) int read()
*int read(byte[] b)
*int read(byte[] b, int off, int len) Reader(典型实现:FileReader) int read()
*int read(char [] c)
*int read(char [] c, int off, int len) 程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资
	源,所以应该显式关闭文件 IO 资源。 
* FileInputStream 从文件系统中的某个文件中获得输入字节。FileInputStream 用于读取非文本数据之类的原始字节流。要读取字符	流,需要使用 FileReader
InputStream
*int read()
* 从输入流中读取数据的下一个字节。返回 0255 范围内的 int 字节值。如果因
* 为已经到达流末尾而没有可用的字节,则返回值 -1*int read(byte[] b)
* 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已
* 经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取
* 的字节数。
*int read(byte[] b, int off,int len)
* 将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取
* 的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于
* 文件末尾而没有可用的字节,则返回值 -1*public void close() throws IOException
* 关闭此输入流并释放与该流关联的所有系统资源。
Reader
* Reader
*int read()
* 读取单个字符。作为整数读取的字符,范围在 065535 之间 (0x00-0xffff)2* 字节的Unicode码),如果已到达流的末尾,则返回 -1 
*int read(char[] cbuf)
* 将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。 
*int read(char[] cbuf,int off,int len)
* 将字符读入数组的某一部分。存到数组cbuf中,从off处开始存储,最多读len个字
* 符。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。 
*public void close() throws IOException
* 关闭此输入流并释放与该流关联的所有系统资源。
OutputStream & Writer
* OutputStream & Writer
*  OutputStream 和 Writer 也非常相似:
*void write(int b/int c);
*void write(byte[] b/char[] cbuf);
*void write(byte[] b/char[] buff, int off, int len);
*void flush();
*void close(); 需要先刷新,再关闭此流
*  因为字符流直接以字符作为操作单位,所以 Writer 可以用字符串来替换字符数组,
* 即以 String 对象作为参数
*void write(String str);
*void write(String str, int off, int len);
*  FileOutputStream 从文件系统中的某个文件中获得输出字节。FileOutputStream
* 用于写出非文本数据之类的原始字节流。要写出字符流,需要使用 FileWrite
OutputStream
*OutputStream
*void write(int b)
* 将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写
* 入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入0~255范围的。
*void write(byte[] b)
* 将 b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定是:应该
* 与调用 write(b, 0, b.length) 的效果完全相同。
*void write(byte[] b,int off,int len)
* 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
*public void flush()throws IOException
* 刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立
* 即写入它们预期的目标。
*public void close() throws IOException
* 关闭此输出流并释放与该流关联的所有系统资源。
writer
* writer
*void write(int c)
* 写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。 即
* 写入065535 之间的Unicode码。
*void write(char[] cbuf)
* 写入字符数组。
*void write(char[] cbuf,int off,int len)
* 写入字符数组的某一部分。从off开始,写入len个字符
*void write(String str)
* 写入字符串。
*void write(String str,int off,int len)
* 写入字符串的某一部分。
*void flush()
* 刷新该流的缓冲,则立即将它们写入预期目标。
*public void close() throws IOException
* 关闭此输出流并释放与该流关联的所有系统资源。
*字符流实现
抽象基类节点流(文件流)缓冲流(处理流)
InputStreamFileInputStreamBufferedInputStream
OutputStreamFileOutputStreamBufferedOutputStream
ReaderFileReaderBufferedReader
writerFileWriterBufferedWriter
FileReader
    @Test
    public void FileReadTest() throws IOException {
//        事先建立的文件一定要跟src在同一个module下,不然要用相对路径
        File file = new File("hello.txt");

        FileReader fileReader = new FileReader(file);

//        fileReader.read()读取字符,读到文件末尾,返回-1
        int data;
        while ((data=fileReader.read())!=-1){
            System.out.print((char)data);
        }

//        最后一定要关闭流
        fileReader.close();
    }
  • 读文件的时候是一定要抛出异常的,但仔细分析以上代码,若是中间出错,则会抛出异常,那么后面的关闭流操作就不会执行了,但流使用后是一定要关闭的,不然会造成内存泄露,所以我们要用try catch finally去捕获异常,不能抛出
    @Test//文件:hyb
    public void FileReadTest(){

        //        事先定义的文件一定要跟src在同一个module下,不然要用相对路径
        FileReader fileReader=null;
        try {
            File file=new File("hello.txt");
            fileReader = new FileReader(file);
//        fileReader.read()读取字符,读到文件末尾,返回-1
            int data;
            while ((data=fileReader.read())!=-1){
                System.out.print((char)data);
            }


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 最后一定要关闭流
            try {
//                加入第一次出现了错误,还未new一个fileReader,会报空指针异常。
                if (fileReader!=null) {fileReader.close();}
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • *上面运用到的Read方法每次只能读入一个字符,这大大影响了效率,所以,我们一次要读入多行。

    • 利用数组,无需改动多行,只需要在操作data那里就可以了。

      		//文件:helloWorld123	
      			int data;
                  char[] s=new char[5];
                  while ((data=fileReader.read(s))!=-1){
                      for (int i = 0; i < s.length; i++) {
                          System.out.print(s[i]);
      //                    helloWorld123ld
                      }
      
                  }
      

      但是,我们看到,他居然报错了,文件最后多输出了World中的ld,我们尝试分析,因为我们先new了一个char数组,所以是每次执行read(s)都是将现有数据取代原数组,所以到最后一次只有三个的时候,最后两个没有数据代替原数据ld,就会报错。

      • 注意:如果是一些文字,需要注意,每次取的文字字节都不一样。
    • 所以,我们可以做以下改动。

      for (int i = 0; i < data; i++)
      

      也就是每次取数值的个数范围就data,就不会出现重复问题。

    • 还有一种方法,可以拿一个字符串是更改。

                  int data;
                  char[] s=new char[5];
                  while ((data=fileReader.read(s))!=-1){
                      String s1 = new String(s,0,data);
                      //每次读一个数组,从0,每次读data个
                      System.out.print(s1);
                  }
      
FileWriter
    @Test
    public void FileWriterTest(){
        FileWriter fileWriter = null;

        try {
//        源文件:helloWorld23
            File file=new File("hello.txt");

            fileWriter = new FileWriter(file,true);

            fileWriter.write("My name is hyb from The Buu University\n");

//        helloWorld123
//        My name is hyb from The Buu University
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fileWriter != null;
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
  • 如果不存在源文件,写入时会自动生成一个源文件。

  • 如果存在源文件

    • FileWriter(file,false),FileWriter(file)会对源文件进行覆盖。

    • FileWriter(file,true)不会对源文件进行覆盖,而是继续写下去。

FileCopy

@Test
public void FileCopy(){

    FileReader fileReader = null;
    FileWriter fileWriter = null;
    try {
        File file = new File("hello.txt");//helloWorld123
        								//My name is hyb from The Buu University
        File file1=new File("hello1.txt");//空

        fileReader = new FileReader(file);

        fileWriter=new FileWriter(file1);

        int data;
        char[] s=new char[5];
        while ((data=fileReader.read(s))!=-1){
            String s1 = new String(s,0,data);
            fileWriter.write(s1);//hello复制到了hello1
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            assert fileReader != null;
            fileReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            assert fileWriter != null;
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
*字节流实现
  • 引出问题:

    字符文本是否可以拿字节流实现?

    自然可以,因为英文字母本身就是占据一个字节。

    但是汉字不是一个字节,一个汉字是由多个字节组成的,所以,当你用字节流读取汉字的时候,有可能会出现乱码(比如中国二字,我们每一次读取三个字节,若是中字前面还有字节没读完,加上中字的一半数量字节刚好够我们一次性读取的数量,就会报乱码了)。

    所以,我们字符文本还是得用字符流读取字节文本还是得用字节流实现比较为妙。

  • 若是我们进行文件的copy,字节流也可以实现字符流,虽然会出现上述的问题,但是我们是在最终的结果去看的,所以不影响效果。

  • 字节流实现与字符流实现基本一样,只是字节流加数组的时候要变成byte,大小一般是1024,这样能加快速度。

*缓冲流
  • 套接在已有的流之上。

  • 内部一个缓冲区,大大增加流的速度。

@Test
public void FileBufferTest(){
    BufferedInputStream bufferedInputStream = null;
    BufferedOutputStream bufferedOutputStream = null;
    try {
        File file = new File("8.png");
        File file1 = new File("NewMyPicture1.png");

        FileInputStream fileInputStream = new FileInputStream(file);
        FileOutputStream fileOutputStream = new FileOutputStream(file1);

        bufferedInputStream = new BufferedInputStream(fileInputStream);
        bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

        byte[] s=new byte[1024];
        int data;
        while ((data=bufferedInputStream.read(s))!=-1){
            bufferedOutputStream.write(s,0,data);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //        有了处理流,系统会默认关闭字节流
        try {
            assert bufferedInputStream != null;
            bufferedInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            assert bufferedOutputStream != null;
            bufferedOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}
*转换流
  • 处理流的一种,属于字符流。
  • 提供字节流和字符流之间的转换。
  • InputStreamReader:实现将字节的输入流按指定字符集转换为字符的输入流。
  • OutputStreamWriter:实现将字符的输出流按指定字符集转换为字节的输出流。
  • 所以当我们合并使用的时候,就可以将一个utf-8的字节文件转换为一个gbk文件
public void testMyInput() throws Exception {
    FileInputStream fis = new FileInputStream("dbcp.txt");
    FileOutputStream fos = new FileOutputStream("dbcp5.txt");
    InputStreamReader isr = new InputStreamReader(fis, "GBK");
    OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
    BufferedReader br = new BufferedReader(isr);
    BufferedWriter bw = new BufferedWriter(osw);
    String str = null;
    while ((str = br.readLine()) != null) {
        bw.write(str);
        bw.newLine();
        bw.flush();
    }
    bw.close();
    br.close();
}
*对象流
什么是可序列化?
  • 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从

    而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传

    输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原

    来的Java对象

  • 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制,通俗来讲就是将内存里的数据读到硬件文件中。

  • 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制,通俗来讲就是将硬件文件中的数据读入内存里。

  • ObjectInputStream和OjbectOutputSteam

    • 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可

      以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

可序列化条件
  • 以类来举例:
    • 该类必须是可序列化的,要想让类可序列化,必须满足以下条件
      • 类里的每一个成员都是可序列化的,如int,String…………这些基本数据类型都默认为可序列化。
      • 如果类里面有不是默认序列化的成员,要将此成员序列化,比如,类里有另一个类定义的变量,那么该类也必须是可序列化的。
      • 必须实现*Serializable或者Externalizable接口。
        • 我们可以查看String源码,发现它就是实现了这两个接口。
      • 必须提供一个静态的全局变量,serializable,数值是一个long型的数,数值本身随便。
        • 这个如同一个标签,我们进入了序列化接口,可序列化的属性就被序列化,当我们输出的时候,要经过这个标签识别,反序列化才能准确。
        • 如果我们没有自定义这个标签,那个系统默认定义,但是在我们更改类的时候,系统会根据类更改的属性而改变这个标签,就会造成字节流混乱,反序列化错误。所以,我们必须显示定义。
    • 要想类里有不被序列化的成员,加上static,transient关键字修饰。
可序列与反序列例子
  • 我们还是拿类来举例,因为基本数据类型直接可序列就可以了。
  • 我们生成一个类,并将其可序列化。
package com.hyb.IO;

import java.io.Serializable;

/**
 * @program: Series
 * @description:
 * @author: Huang Yubin
 * @create: 2021-06-14 23:07
 **/

//实现接口,进入可序列化门户
public class Series implements Serializable {

//    贴上标签,自己是什么人,什么类型,待反序列化不出错。
    public static final long serialVersionUID= 11188981398L;

//    提供可序列化自己的属性
    private String name;
    private int age;

//    提供不想序列化的属性

    private static int BodyHigh;
    private transient String MyFatherName;

//    提供一个类的基本方法


    public Series() {
    }

    public Series(String name, int age, String myFatherName) {
        this.name = name;
        this.age = age;
        MyFatherName = myFatherName;
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static int getBodyHigh() {
        return BodyHigh;
    }

    public static void setBodyHigh(int bodyHigh) {
        BodyHigh = bodyHigh;
    }

    public String getMyFatherName() {
        return MyFatherName;
    }

    public void setMyFatherName(String myFatherName) {
        MyFatherName = myFatherName;
    }

    @Override
    public String toString() {
        return "Series{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", MyFatherName='" + MyFatherName + '\'' +
                '}';
    }
}
  • 然后我们进行可序列化操作
//    序列化(编码),从内存方面写入硬盘文件
//    ObjectOutputStream
    @Test
    public void Serialized(){

        ObjectOutputStream ops = null;
        try {

//            制造一个文件,注意,这生成一个文件,无论是什么类型,都是不能直接读取的,因为下面序列化了。
            File f1 = new File("Serialized.dat");

//            生成一个节点流
            FileOutputStream fos = new FileOutputStream(f1);

//            序列化
            ops = new ObjectOutputStream(fos);

            ops.writeObject(new Series("hyb",20,"hfy"));

            ops.flush();//刷新操作

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

//        生成一个查看不了的文件
    }
  • 然后我们反序列化
//    反序列化(解码),从硬盘文件里读取数据到内存里。
//    ObjectOutputStream
    @Test
    public void ReversalSerialized(){

        ObjectInputStream ois = null;
        try {
            File f1 = new File("Serialized.txt");

            FileInputStream fis = new FileInputStream(f1);

            ois = new ObjectInputStream(fis);

            Object o = ois.readObject();

            System.out.println(o);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                assert ois != null;
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
//    Series{name='hyb', age=20, MyFatherName='null'}
  • 总结

    • 若某个类实现了 Serializable 接口,该类的对象就是可序列化的:

      • 创建一个 ObjectOutputStream

      • 调用 ObjectOutputStream 对象的 writeObject(对象)方法输出可序列化对象

      • 注意写出一次,操作flush()一次

    • 反序列化

      • 创建一个 ObjectInputStream

      • 调用 readObject() 方法读取流中的对象

随即存储文件流
  • RandomAccessFile 声明在java.io包下,但直接继承于java.lang.Object类。并

    且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也

    可以写。

  • RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意

    地方来读、写文件

    • 支持只访问文件的部分内容

      • 可以通过编程实现文件中间插入代码。
    • 可以向已存在的文件后追加内容

  • RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。

    RandomAccessFile 类对象可以自由移动记录指针:

    • long getFilePointer():获取文件记录指针的当前位置

    • *void seek(long pos):将文件记录指针定位到 pos 位置

      • 这个方法很实用,一般用在我们下载文件的时候,如果断网了能继续下载,就要用seek记录当前下载位置。
  • 构造器

    • public RandomAccessFile(File file, String mode)

    • public RandomAccessFile(String name, String mode)

    • 创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:

      • r: 以只读方式打开

      • rw:打开以便读取和写入

      • **rwd:**打开以便读取和写入;同步文件内容的更新

      • **rws:**打开以便读取和写入;同步文件内容和元数据的更新

    • 如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,

      如果读取的文件不存在则会出现异常。 如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。

  • 注意:

    • 作为输出流时,如果文件不存在,会创建一个新的文件,如果存在,会对源文件进行覆盖,注意,是按照你加入的字符个数进行一个一个覆盖的,不是整个文件进行覆盖
    • 所以如果你要在文件中央插入一段字符,自然简单的插入是会将源文件的内容进行部分覆盖,所以,在中间插入你要将后一部分先拿出来,然后再追加你要插入的,再拼接。
RandomAccessFile raf = new RandomAccessFile(“test.txt”, “rw”);
raf.seek(5);
byte [] b = new byte[1024];
int off = 0;
int len = 5;
raf.read(b, off, len);
String str = new String(b, 0, len);
System.out.println(str);
raf.close();
RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
raf.seek(5);
//先读出来
String temp = raf.readLine();
raf.seek(5);
raf.write("xyz".getBytes());
raf.write(temp.getBytes());
raf.close();
  • *ByteArrayOutputStream()提供了将固定大笑的字节文件一部分一部分装进去,底层有一个数组,到最后直接toString,可以避免汉字字节转换出现分半的问题。
NIO.2中Path、Paths、Files类的使用(介绍)
  • 早期的Java只提供了一个File类来访问文件系统,但File类的功能比较有限,所

    提供的方法性能也不高。而且,大多数方法在出错时仅返回失败,并不会提供异

    常信息。

  • NIO. 2为了弥补这种不足,引入了Path接口,代表一个平台无关的平台路径,描

    述了目录结构中文件的位置。Path可以看成是File类的升级版本,实际引用的资

    源也可以不存在。

    • 在以前IO操作都是这样写的:

      import java.io.File;

      File file = new File(“index.html”);

    • 但在Java7 中,我们可以这样写:

      import java.nio.file.Path;

      import java.nio.file.Paths;

      Path path = Paths.get(“index.html”);

  • 同时,NIO.2在java.nio.file包下还提供了Files、Paths工具类,Files包含

    了大量静态的工具方法来操作文件;Paths则包含了两个返回Path的静态

    工厂方法。

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

  • static Path get(String first, String … more) : 用于将多个字符串串连成路径

  • static Path get(URI uri): 返回指定uri对应的Path路径

  • Path 常用方法:

String toString() : 返回调用 Path 对象的字符串表示形式

boolean startsWith(String path) : 判断是否以 path 路径开始

boolean endsWith(String path) : 判断是否以 path 路径结束

boolean isAbsolute() : 判断是否是绝对路径

Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径

Path getRoot() :返回调用 Path 对象的根路径

Path getFileName() : 返回与调用 Path 对象关联的文件名

int getNameCount() : 返回Path 根目录后面元素的数量

Path getName(int idx) : 返回指定索引位置 idx 的路径名称

Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象

Path resolve(Path p) :合并两个路径,返回合并后的路径对应的Path对象

File toFile(): 将Path转化为File类的对象

  • java.nio.file.Files 用于操作文件或目录的工具类。

    Path copy(Path src, Path dest, CopyOption … how) : 文件的复制

    Path createDirectory(Path path, FileAttribute<?> … attr) : 创建一个目录

    Path createFile(Path path, FileAttribute<?> … arr) : 创建一个文件

    void delete(Path path) : 删除一个文件/目录,如果不存在,执行报错

    void deleteIfExists(Path path) : Path对应的文件/目录如果存在,执行删除

    Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置

    long size(Path path) : 返回 path 指定文件的大小

    Files常用方法:用于判断

    boolean exists(Path path, LinkOption … opts) : 判断文件是否存在

    boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录

    boolean isRegularFile(Path path, LinkOption … opts) : 判断是否是文件

    boolean isHidden(Path path) : 判断是否是隐藏文件

    boolean isReadable(Path path) : 判断文件是否可读

    boolean isWritable(Path path) : 判断文件是否可写

    boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在

    Files常用方法:用于操作内容

    SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连

    接,how 指定打开方式。

    DirectoryStream newDirectoryStream(Path path) : 打开 path 指定的目录

    InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象

    OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象

  • 在项目的时候,框架会对这些底层做封装,到时候再了解即可。

说明

  • 做项目开发,很少真正编写IO流源代码,而是使用第三方API,但这并不表明IO流不重要。
  • IO流非常重要,它提供了于硬盘文件与内存之间的转换存储,极大地方便了下载与保存。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值