十一、IO流


一、File类的使用


1.1 File类概述

  • File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
  • File类声明在java.io包下
  • File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法
  • 并未涉及到写入或读取文件内容的操作,如果需要读取或写入文件内容,必须使用IO流来完成
  • 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录
  • 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"

1.2 File的实例化

1.2.1 常用构造器

  • File(String filePath)pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储
  • File(String parentPath,String childPath)parent为父路径,child为子路径创建File对象
  • File(File parentFile,String childPath)根据一个父File对象和子文件路径创建File对象

1.2.2 路径的分类

  • 绝对路径:包含盘符在内的文件或文件目录的路径
  • 相对路径:相较于某个路径下,指明的路径
  • 说明:
    • IDEA中:
      • 如果使用JUnit中的单元测试方法测试,相对路径即为当前Module下
      • 如果使用main() 测试,相对路径即为当前的Project下
    • Eclipse中:
      • 不管使用单元测试方法还是使用main()测试,相对路径都是当前的Project下

1.2.3 路径分隔符

  • windows和DOS系统默认使用\来表示,代码中写成转义字符\\
  • UNIX和URL使用/来表示
  • File类提供了一个常量,根据操作系统,动态的提供分隔符
    public static final String separator
    File file1 = new File("d:\\atguigu\\info.txt");
    File file2 = new File("d:" + File.separator + "atguigu" + File.separator + "info.txt");
    

1.3 File类的常用方法

File类的获取功能

MethodDescription
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数组

File类的重命名功能

MethodDescription
public boolean renameTo(File dest)把文件重命名为指定的文件路径
Boolean renameTo = file1.renameTo(file2); 
// file1在硬盘中存在,file2不能在硬盘中存在,则返回true

File类的判断功能

MethodDescription
public boolean isDirectory()判断是否是文件目录
public boolean isFile()判断是否是文件
public boolean exists()判断是否存在
public boolean canRead()判断是否可读
public boolean canWrite()判断是否可写
public boolean isHidden()判断是否隐藏

File类的创建功能

MethodDescription
public boolean createNewFile()创建文件。若文件存在,则不创建,返回false
public boolean mkdir()创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs()创建文件目录。如果上层文件目录不存在,一并创建
  • 注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下

File类的删除功能

MethodDescription
public boolean delete()删除文件或者文件夹
  • 注意事项:Java中的删除不走回收站,要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录

二、IO流原理及流的分类


2.1 JavaIO原理

  • 处理设备之间的数据传输
  • Java程序中,对于数据的输入/输出操作以流(stream) 的方式进行
  • java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据
  • 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序 (内存)
  • 输出output:将程序 (内存) 数据输出到磁盘、光盘等存储设备中

2.2 流的分类

  • 按操作数据单位不同分为:字节流(8 bit)字符流(16 bit)
  • 按数据流的流向不同分为:输入流输出流
  • 按流的角色的不同分为:节点流(文件流),处理流(“套接”在已有的流的基础上)
    在这里插入图片描述在这里插入图片描述

三、文件流(节点流)

  • FileInputStreamread(byte[] buffer)
  • FileOutputStreamwrite(byte[] buff,0,len)
  • FileReaderread(char[] cbuf)
  • FileWriterwrite(char[] cbuf,0,len)

3.1 FileReader、FileWriter

  • 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
  • FileReader
    /**
     * 将hello.txt文件内容读入程序中,并输出到控制台 
     * 说明:
     *     1.read():返回读入的一个字符,达到文件末尾返回-1
     *     2.异常的处理:为保证流资源一定可以执行关闭,需要用try-catch-finally处理
     *     3.读入的文件一定要存在,否则报 FileNotFoundException 异常
     */
    @Test
    public void testFileReader() {
        FileReader fileReader = null;

        try {
            // 1.实例化File类对象
            File file = new File("hello.txt"); //相较于当前Module下

            // 2.实例化字符输入节点流
            fileReader = new FileReader(file);

            // 3.数据的输入
            // read():返回读入的一个字符,达到文件末尾返回-1
            // 方式一:
//        int read = fileReader.read();
//        while(read != -1){
//            System.out.println((char)read);
//            read = fileReader.read();
//        }
            // 方式二:语法上的修改
            int read;
            while((read = fileReader.read()) != -1){
                System.out.print((char)read);// helloword
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.流的关闭(一定要写)
            try {
                if (fileReader != null) //如果上面造对象就报异常,没有fileReader对象,不用调用close()
                    fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // read()的升级,使用read的重载方法
    @Test
    public void testFileReader1() {
        FileReader fileReader = null;
        try {
            // 1.File类的实例化
            File file = new File("hello.txt");

            // 2.FileReader流的实例化
            fileReader = new FileReader(file);

            // 3.读入操作
            // read(char[] cbuf):返回每次读入cbuf数组中的字符个数,达到文件末尾返回-1
            char[] cbuf = new char[5];
            int len;
            while((len = fileReader.read(cbuf)) != -1){

                //方式一:
                //错误写法:
//               for (int i = 0;i<cbuf.length;i++) //第二次读少于5个字符,则cbuf数组前面的字符被覆盖,而后面的没有被替换
//                   System.out.print(cbuf[i]); //hellowordo
                //正确写法:
                for (int i = 0;i<len;i++)
                    System.out.print(cbuf[i]);//helloword

                //方式二:
                //错误写法:
//                String string = new String(cbuf); //错误同方式一
//                System.out.print(string);//hellowordo
                //正确写法:
                String string = new String(cbuf, 0, len);
                System.out.print(string);//helloword
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.资源的关闭
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  • FileWriter
    /**
     * 从内存写出数据到硬盘文件里
     * 说明点:
     *      1. 对应的File可以不存在的。并不会报异常
     *      2. File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
     *         File对应的硬盘中的文件如果存在:
     *            如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原文件的覆盖
     *            如果流使用的构造器是:FileWriter(file,true):不会对原文件覆盖,而是在原文件基础上追加内容
     */
    @Test
    public void testFileWriter() {
        FileWriter fileWriter = null;
        try {
            // 1.提供File类对象,指明写出到的文件
            File file = new File("hello1.txt");
            // 2.提供FileWriter的对象,用于数据的写出
            fileWriter = new FileWriter(file);
            // 3.写出的操作
            fileWriter.write("I have a dream!\n");
            fileWriter.write("Gun du zi!\n");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.流资源的关闭
            try {
                if (fileWriter!=null)
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 文本文件的复制:
    @Test
    public void testFileReaderFileWriter(){
        FileReader fileReader = null;
        FileWriter fileWriter = null;
        try {
            //1.创建File对象,指明读入和写出的文件
            File srcFile = new File("hello.txt");
            File destFile = new File("hello2.txt");
            //2.创建输入流和输出流的对象
            fileReader = new FileReader(srcFile);
            fileWriter = new FileWriter(destFile);
            //3.数据的读入和写出操作
            char[] cbuf = new char[5];
            int len;
            while((len=fileReader.read(cbuf))!=-1){
                //每次写出len个字符
                fileWriter.write(cbuf,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.流的关闭
            if (fileReader!=null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileWriter!=null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

3.2 FileInputStream、FileOutputStream

  • 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
  • 仅复制文本文件,不在内存显示也可以
  • 图片的复制操作:
    @Test
    public void testFileInputOutputStream(){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //1.造文件
            File srcFile = new File("IMG_2754.JPG"); //源文件
            File destFile = new File("IMG_2754(2).JPG"); //目标文件

            //2.造流
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);

            //3.复制的过程
            byte[] buffer = new byte[5];
            int len;
            while((len = fis.read(buffer)) != -1){
                fos.write(buffer,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

四、缓冲流

  • 提高流的读取、写入的速度
  • BufferedInputStreamread(byte[] buffer)
  • BufferedOutputStreamwrite(byte[] buff,0,len) / 自动flush()刷新缓存区
  • BufferedReaderread(char[] cbuf)readLine()
  • BufferedWriterwrite(char[] cbuf,0,len) / 自动flush()刷新缓存区

4.1 BufferedInputStream、BufferedOutputStream

  • 提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb
    在这里插入图片描述
    // 实现非文本文件的复制
    @Test
    public void BufferedStreamTest(){
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;

        try {
            //1.造文件
            File srcFile = new File("IMG_2754.JPG");
            File destFile = new File("IMG_2754(3).JPG");

            //2.造流
            //2.1节点流
            FileInputStream fileInputStream = new FileInputStream(srcFile);
            FileOutputStream fileOutputStream = new FileOutputStream(destFile);
            //2.2缓冲流
            bufferedInputStream = new BufferedInputStream(fileInputStream);
            bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

            //3.复制
            byte[] buffer = new byte[20];
            int len;
            while((len=bufferedInputStream.read(buffer))!=-1){
                bufferedOutputStream.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流
            //  要求:先关闭外层流,再关闭内层的流
            if (bufferedInputStream!=null) {
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedOutputStream!=null) {
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //  说明:关闭外层流同时,内层流也会进行关闭,内层流的关闭可以省略
//        fileInputStream.close();
//        fileOutputStream.close();
    }

4.2 BufferedReader、BufferedWriter

    //实现文本文件的复制
    @Test
    public void testBufferedReaderWriter(){
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            //1.造文件+流
            bufferedReader = new BufferedReader(new FileReader(new File("hello.txt")));
            bufferedWriter = new BufferedWriter(new FileWriter(new File("hello4.txt")));
            //2.复制
             //方式一:
//            char[] cbuf = new char[1024];
//            int len;
//            while((len=bufferedReader.read(cbuf))!=-1){
//                bufferedWriter.write(cbuf,0,len);
//            }
             //方式二:bufferedReader.readLine()
            String data;
            while((data=bufferedReader.readLine())!=null){
                //方法一:
                bufferedWriter.write(data + "\n");//data中不包含换行符
                //方法二:
                bufferedWriter.write(data);
                bufferedWriter.newLine();//换行
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭流
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

五、转换流

  • 转换流提供了在字节流和字符流之间的转换
  • 使用转换流来处理文件乱码问题,实现编码和 解码的功能
  • 转换流(属于字符流):
    • InputStreamReader:将InputStream转换为Reader
    • OutputStreamWriter:将Writer转换为OutputStream
      在这里插入图片描述

5.1 InputStreamReader

  • 实现将字节的输入流按指定字符集转换为字符的输入流
    @Test
    public void test1(){
        InputStreamReader inputStreamReader = null;
        try {
            FileInputStream fileInputStream = new FileInputStream("dbcp.txt");
//        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);//使用系统默认的字符集
            inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");//指明dbcp.txt文件所用的字符集
            char[] cbuf = new char[20];
            int len;
            while ((len = inputStreamReader.read(cbuf))!=-1){
                String str = new String(cbuf, 0, len);
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStreamReader!=null) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

5.2 OutputStreamWriter

  • 实现将字符的输出流按指定字符集转换为字节的输出流
	// UTF-8写入,gbk读出
    @Test
    public void test2(){
        InputStreamReader inputStreamReader = null;
        OutputStreamWriter outputStreamWriter = null;
        try {
            File file1 = new File("dbcp.txt");
            File file2 = new File("dbcp_gbk.txt");

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

            inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
            outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");

            char[] cbuf = new char[20];
            int len;
            while((len = inputStreamReader.read(cbuf))!=-1){
                outputStreamWriter.write(cbuf,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStreamReader!=null) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStreamWriter!=null) {
                try {
                    outputStreamWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

5.3 字符集

  • 编码表:将各个国家的文字用数字来表示,并一一对应,形成一张表
  • 常见的编码表:
    • ASCII:美国标准信息交换码
      用一个字节的7位可以表示
    • ISO8859-1:拉丁码表、欧洲码表
      用一个字节的8位表示
    • GB2312:中国的中文编码表
      最多两个字节编码所有字符
    • GBK:中国的中文编码表升级,融合了更多的中文文字符号
      最多两个字节编码,
      首位是0一个字节表示一个字符,
      首位是1两个字节表示一个字符
    • Unicode:国际标准码,融合了目前人类使用的所有字符
      为每个字符分配唯一的字符码
      所有的文字都用两个字节来表示
    • UTF-8:变长的编码方式
      可用1~4个字节来表示一个字符
      在这里插入图片描述

在这里插入图片描述


六、标准输入、输出流

  • System.in:标准的输入流,默认从键盘输入
  • System.out:标准的输出流,默认从控制台输出
  • 通过System类的setInsetOut方法对默认设备进行改变
    /**
     * 要求:从键盘输入字符串,要求将读取到的整行字符串转成大写输出
     *      然后继续进行输入操作,直至当输入“e”或者“exit”时,退出程序
     *
     * 方法一:Scanner,调用next()方法返回一个字符串
     * 方法二:System.in(字节流),转换流,BufferedReader(字符流)的readLine()
     */
    @Test
    public void test1(){
        BufferedReader bufferedReader = null;
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(System.in);//idea不支持单元测试的输入
            bufferedReader = new BufferedReader(inputStreamReader);
            while (true){
                System.out.println("输入字符串:");
                String data = bufferedReader.readLine();
                if ("e".equalsIgnoreCase(data)||"exit".equalsIgnoreCase(data)){
                    System.out.println("程序结束");
                    break;
                }
                String upperCase = data.toUpperCase();
                System.out.println(upperCase);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader!=null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
package com.lsy.java;
// MyInput.java: Contain the methods for reading int, double, float, boolean, short, byte and
// string values from the keyboard

import java.io.*;

public class MyInput {
    // Read a string from the keyboard
    public static String readString() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // Declare and initialize the string
        String string = "";

        // Get the string from the keyboard
        try {
            string = br.readLine();

        } catch (IOException ex) {
            System.out.println(ex);
        }

        // Return the string obtained from the keyboard
        return string;
    }

    // Read an int value from the keyboard
    public static int readInt() {
        return Integer.parseInt(readString());
    }

    // Read a double value from the keyboard
    public static double readDouble() {
        return Double.parseDouble(readString());
    }

    // Read a byte value from the keyboard
    public static double readByte() {
        return Byte.parseByte(readString());
    }

    // Read a short value from the keyboard
    public static double readShort() {
        return Short.parseShort(readString());
    }

    // Read a long value from the keyboard
    public static double readLong() {
        return Long.parseLong(readString());
    }

    // Read a float value from the keyboard
    public static double readFloat() {
        return Float.parseFloat(readString());
    }
}

七、打印流

  • 基本数据类型的数据格式转化为字符串输出
  • 打印流:PrintStreamPrintWriter
    • 提供了一系列重载的 print()println() 方法,用于多种数据类型的输出
    • PrintStreamPrintWriter 的输出不会抛出 IOException 异常
    • PrintStreamPrintWriter 有自动flush功能
    • PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。
      在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
    • System.out 返回的是 PrintStream 的实例
    @Test
    public void test2() {
        PrintStream ps = null;
        try {
            FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
            // 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)  
            ps = new PrintStream(fos, true);
            if (ps != null) {    
                System.setOut(ps); // 把标准输出流(控制台输出)改成文件
            }
            
            for (int i = 0; i <= 255; i++) { // 输出ASCII字符
                System.out.print((char) i);
                if (i % 50 == 0) { // 每50个数据一行
                    System.out.println(); // 换 行
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                ps.close();
            }
        }
    }

八、数据流

  • 为了方便地读取写出Java语言的基本数据类型String的数据
  • 数据流有两个类:(用于读取和写出基本数据类型、String类的数据)
    • DataInputStreamDataOutputStream
    • 分别“套接”在 InputStreamOutputStream 子类的流上
  • DataInputStream中的方法:
    • boolean readBoolean()
    • char readChar()
    • double readDouble()
    • long readLong()
    • String readUTF()
    • byte readByte()
    • float readFloat()
    • short readShort()
    • int readInt()
    • void readFully(byte[] b)
  • DataOutputStream中的方法
    • 将上述的方法的read改为相应的write即可
    //将内存中的字符串、基本数据类型的变量写出到文件中
    @Test
    public void test3() {
        DataOutputStream dos = null;
        try { // 创建连接到指定文件的数据输出流对象
            dos = new DataOutputStream(new FileOutputStream("destData.dat"));
            dos.writeUTF("我爱北京天安门"); // 写UTF字符串
            dos.flush(); // 刷新,将内存中的数据写入文件
            dos.writeBoolean(false); // 写入布尔值
            dos.writeLong(1234567890L); // 写入长整数
            System.out.println("写文件成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally { // 关闭流对象
            try {
                if (dos != null) {
                    // 关闭过滤流时,会自动关闭它包装的底层节点流
                    dos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //将文件中存储的基本数据变量、字符串读取到内存中,保存在变量中
    @Test
    public void test4() {
        DataInputStream dis = null;
        try {
            dis = new DataInputStream(new FileInputStream("destData.dat"));
            String info = dis.readUTF(); //读写顺序一致,否则报异常
            boolean flag = dis.readBoolean();
            long time = dis.readLong();
            System.out.println(info);
            System.out.println(flag);
            System.out.println(time);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

九、对象流

  • 用于存储和读取基本数据类型数据或对象的处理流
  • 对象序列化机制:把内存中的Java对象转换成平台无关的二进制流
    • 序列化:用ObjectOutputStream保存基本类型数据或对象的机制
    • 反序列化:用ObjectInputStream读取基本类型数据或对象的机制
  • 实现序列化的对象所属的类须:
    • 实现如下两个接口之一
      • Serializable
      • Externalizable
      • 否则,会抛出NotSerializableException异常
    • 提供一个全局常量serialVersionUID
    • 内部所属性也必须是可序列化的(默认情况下,基本数据类型可序列化)
    • ObjectOutputStreamObjectInputStream不能序列化statictransient修饰的成员变量
/**
 * Person满足以下要求,方可实现序列化:
 *      1.实现接口 Serializable
 *      2.提供全局常量 serialVersionUID
 *      3.内部所属性也必须是可序列化的
 */
public class person implements Serializable {

    private static final long serialVersionUID = 475463634632L;

    private String name;
    private int age;
    ...
}
    /**
     * 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
     * 用ObjectOutputStream实现
     */
    @Test
    public void test1(){
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("data.dat"));
            oos.writeObject(new String("哈哈哈哈哈哈哈哈哈"));
            oos.flush();
          
            oos.writeObject(new person("Tom",25));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 反序列化:将磁盘文件中的对象还原为内存中的一个java对象
     * 用ObjectInputStream
     */
    @Test
    public void test2(){
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("data.dat"));
            Object obj = ois.readObject();
            String str = (String) obj;

            person p = (person) ois.readObject();

            System.out.println(str);
            System.out.println(p);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois !=null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

十、随机存取文件流

  • RandomAccessFile直接继承于java.lang.Object类,实现了DataInputDataOutput接口
  • 既可以作为一个输入流,又可以作为一个输出流
  • 作为输出流时:
    • 写出到的文件如果不存在,则在执行过程中自动创建
    • 写出到的文件存在,则会对原文件内容进行覆盖(默认情况下,从头开始覆盖原有内容)
  • 创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指 定 RandomAccessFile访问模式
    • r: 以只读方式打开
    • rw:打开以便读取和写入
    • rwd:打开以便读取和写入;同步文件内容的更新
    • rws:打开以便读取和写入;同步文件内容和元数据的更新
  • RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置,RandomAccessFile 类对象可以自由移动记录指针
    • long getFilePointer():获取文件记录指针的当前位置
    • void seek(long pos):将文件记录指针定位到 pos 位置
  • 可以用RandomAccessFile这个类,来实现一个多线程断点下载的功能,下载前会建立两个临时文件,一个是与被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上 一次的地方下载,从而实现断点下载或上传的功能
    //RandomAccessFile既可以作为输入流也可以作为输出流
    @Test
    public void test3(){
        RandomAccessFile r1 = null;
        RandomAccessFile r2 = null;
        try {
            r1 = new RandomAccessFile(new File("IMG_2754.JPG"), "r");
            r2 = new RandomAccessFile(new File("IMG_2754(2).JPG"), "rw");

            byte[] buffer = new byte[1024];
            int len;
            while((len=r1.read(buffer))!=-1){
                r2.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (r1!=null) {
                try {
                    r2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (r2!=null) {
                try {
                    r1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    //通过相关操作实现RandomAccessFile的插入
    @Test
    public void test5(){
        RandomAccessFile raf1 = null;
        try {
            raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

            raf1.seek(3);
            //保存3后面的所有数据到StringBuilder中
            StringBuilder builder = new StringBuilder((int)new File("hello.txt").length());
            byte[] buffer = new byte[20];
            int len;
            while ((len=raf1.read(buffer))!=-1){
                builder.append(new String(buffer,0,len));
            }
            //调回指针
            raf1.seek(3);
            raf1.write("xxxx".getBytes());
            //写入builder
            raf1.write(builder.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (raf1!=null) {
                try {
                    raf1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

十一、NIO.2中Path、Paths、Files类的使用


11.1 NIO.2

  • Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API
  • NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作,NIO将以更加高效的方式进行文件的读写操作
  • JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,称为 NIO.2
  • Java API中提供了两套NIO:
    • 针对标准输入输出NIO:
      • |-----java.nio.channels.Channel
        • |-----FileChannel:处理本地文件
    • 网络编程NIO:
      • |-----java.nio.channels.Channel
        • |-----SocketChannel:TCP网络编程的客户端的Channel
        • |-----ServerSocketChannel:TCP网络编程的服务器端的Channel
        • |-----DatagramChannel:UDP网络编程中发送端和接收端的Channel

11.2 Path、Paths和Files

  • File类的功能比较有限,所提供的方法性能也不高,且大多数方法在出错时仅返回失败,并不会提供异常信息
  • 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 常用方法:

MethodDescription
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类的对象

Files 常用方法:

MethodDescription
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常用方法:用于判断

MethodDescription
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常用方法:用于操作内容

MethodDescription
SeekableByteChannel newByteChannel(Path path, OpenOption…how)获取与指定文件的连 接,how 指定打开方式。
DirectoryStream<Path> newDirectoryStream(Path path)打开 path 指定的目录
InputStream newInputStream(Path path, OpenOption…how)获取 InputStream 对象
OutputStream newOutputStream(Path path, OpenOption…how)获取 OutputStream 对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值