02_6_IO

1 File类的使用

1.1 File类的理解

  • 每一个File file = new File(“path”)都是文件系统中的一个文件或者文件目录

  • File类声明在java.io包下

  • File类中涉及了关于文件或文件目录的创建createNewFile();mkdir();mkdirs(),删除delete(),重命名renameTo(),修改时间lastModified(),文件大小length()等方法

    并没有涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。

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

1.2 File的实例化

常用构造器
File file = new File(String filepath);

File file = new File(String parentPath, String childPath);

File file = new File(File parentFile, String childPath);
路径的分类
  • 相对路径:相较于某个路径下,指明的路径。
  • 绝对路径:包含盘符在内的文件或文件目录的路径

说明:

IDEA中:
如果大家开发使用JUnit中的单元测试方法测试,相对路径即为当前Module下。
如果大家使用main()测试,相对路径即为当前的Project下。
Eclipse中:
不管使用单元测试方法还是使用main()测试,相对路径都是当前的Project下。

路径分隔符

windows和DOS系统默认使用“\”来表示
UNIX和URL使用“/”来表示

1.3 File常用方法

1599312635281

1599312642676

public class FileTest {
    @Test
    public void test1(){
        //构造器1:File(String pathname)
        File file1 = new File("hello.txt");
        File file2 = new File("F:\\workspace\\SGU_Java_course\\IO\\hello.txt");

        System.out.println(file1);
        System.out.println(file2);

        //构造器2:File(String parentPath, String childPath)
        File file3 = new File("F:\\workspace\\SGU_Java_course", "IO");
        System.out.println(file3);

        //构造器3:File(File parentFile, String childPath)
        File file4 = new File(file3, "HelloWorld");
    }
    @Test
    public void test2(){
        //注意此时file1的相对路径是在src目录下的,并不是在www.code...下的。
        File file1 = new File("hello.txt");
        File file2 = new File("F:\\workspace\\SGU_Java_course\\IO\\hi.txt");

        //1. 获取绝对路径
        System.out.println(file1.getAbsolutePath());
        System.out.println(file2.getAbsolutePath());
        //2. 获取路径(写的什么路径就是什么)
        System.out.println(file1.getPath());
        System.out.println(file2.getPath());
        //3. 获取名称(获取文件名)
        System.out.println(file1.getName());
        System.out.println(file2.getName());
        //4. 获取上层目录路径(写的相对路径的话,往上找找不到,写绝对路径就可以。)
        System.out.println(file1.getParent());
        System.out.println(file2.getParentFile());
        //5. 获取文件长度(字节数),不能获取目录的长度
        System.out.println(file1.length());
        //6. 获取最后一次修改的时间,毫秒值
        long l = file1.lastModified();
        Date date = new Date(l);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String format = simpleDateFormat.format(date);
        System.out.println(format);//转换成现在的时间
    }
    @Test
    public void test3(){
        File file = new File("F:\\workspace\\SGU_Java_course");

        //7. 获取指定目录下的所有文件或文件目录的名称数组(如果路径找不到就会报错)
        //以文件名的形式显示。
        String[] list = file.list();
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("************************************");
        //8. 获取指定目录下的所有文件或文件目录的File数组
        //以绝对路径的形式显示。
        File[] files = file.listFiles();
        for (File file1 : files) {
            System.out.println(file1);
        }
    }
    @Test
    public void test4(){
        File file1 = new File("F:\\workspace\\SGU_Java_course\\file.txt");
        File file2 = new File("F:\\workspace\\SGU_Java_course\\IO\\hello.txt");
        //renameTo重命名文件(相同路径下),当不同路径renameTo就是剪切后重命名
        boolean b = file1.renameTo(file2);
        System.out.println(b);
    }
    @Test
    public void test5(){
        File file1 = new File("hello.txt");
        File file2 = new File("hi.txt");
        //判断文件是否存在
        boolean exists1 = file1.exists();
        System.out.println(exists1);
        boolean exists2 = file2.exists();
        System.out.println(exists2);
        //判断是否是一个文件
        boolean file = file1.isFile();
        System.out.println(file);
        //判断是否是一个文件目录
        boolean directory = file1.isDirectory();
        System.out.println(directory);
        File file3 = new File("F:\\workspace\\SGU_Java_course\\IO");
        boolean directory1 = file3.isDirectory();
        System.out.println(directory1);
        //判断是否可读
        boolean read = file1.canRead();
        System.out.println(read);
        boolean b = file2.canRead();
        System.out.println(b);
        boolean b1 = file3.canRead();
        System.out.println(b1);
        //判断是否可写
        boolean write = file1.canWrite();
        System.out.println(write);
        //判断是否隐藏
        boolean hidden = file1.isHidden();
        System.out.println(hidden);
    }
    @Test
    public void test6() throws IOException {
        //文件的创建
        File file1 = new File("F:\\workspace\\SGU_Java_course\\IO\\hadoop.txt");
        if (!file1.exists()){
            //file.createNewFile()创建新文件;返回为boolean
            boolean newFile = file1.createNewFile();
            if (newFile){
                System.out.println("创建成功");
            }else {
                System.out.println("创建失败");
            }
        }else {
            //file.delete()删除文件;返回为boolean
            boolean delete = file1.delete();
            if (delete){
                System.out.println("删除成功");
            }
        }
    }
    @Test
    public void test7(){
        //文件目录创建
        File file = new File("F:\\workspace\\SGU_Java_course\\IO\\IO1");
        if (!file.exists()){
            //mkdir()创建文件目录
            boolean mkdir = file.mkdir();
            if (mkdir){
                System.out.println("文件目录创建成功");
            }
        }else {
            //文件目录删除也是用delete
            boolean delete = file.delete();
            if (delete){
                System.out.println("文件目录删除成功");
            }
        }
    }
    @Test
    public void test8(){
        //创建多级目录
        File file = new File("F:\\workspace\\SGU_Java_course\\IO\\IO1\\IO21");
        //可以看到创建多级目录mkdir就不行了
        boolean mkdir = file.mkdir();
        System.out.println(mkdir);

        //创建多级目录
        if (!file.exists()){
            boolean mkdirs = file.mkdirs();
            if (mkdirs){
                System.out.println("多级目录创建成功");
            }
        }else {
            //多级目录的删除也是用delete
            //当待删除目录中存在文件就不能删除
            boolean delete = file.delete();
            if (delete){
                System.out.println("多级目录删除成功");
            }
        }
    }
}

1.4 File的应用实例

递归显示某个文件夹中的所有内容
public class Test1 {
    public static void main(String[] args) {
        File file = new File("./testFile");
        listSubFile(file);
    }
    public static void listSubFile(File file){
        //输入的文件检验
        if (file.exists() && file.isDirectory()){
            //首先获取输入的这个文件的数组
            File[] files = file.listFiles();
            //如果输入的文件夹不是空文件夹
            if (files != null){
                //获取每一个文件名
                for (File file1 : files) {
                    //打印所有的文件名称,包括文件夹的
                    System.out.println(file1.getName());
                    if (file1.isDirectory())
                    listSubFile(file1);
//                    //只打印文件的名称
//                    if (file1.isFile())
//                    System.out.println(file1.getName());
//                    if (file1.isDirectory())
//                    listSubFile(file1);
                }
            }
        }
    }
}
递归删除某个文件夹中的所有内容
public class Test2 {
    @Test
    public void test1(){
        File file = new File("./testFile2");
        delSubFile(file);
    }
    //递归删除方法
    public void delSubFile(File file){
        //首先判断传进来的文件目录是不是存在,并且判断是不是文件夹
        if (file.exists() && file.isDirectory()){
            //或得该目录下的所有一级内容
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isDirectory()){
                    delSubFile(file1);
                }
                file1.delete();
            }
        }
    }
}
递归删除某个文件夹中的空白文件夹
public class Test3 {
    @Test
    public void test(){
        File file = new File("./testFile2");
        delEmptyDir(file);
    }
    public void delEmptyDir(File file){
        if (file.exists() && file.isDirectory()){
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isDirectory()){
                    File[] files1 = file1.listFiles();
                    //空白文件夹内的长度=0;
                    if (files1.length == 0){
                        file1.delete();
                    //非空文件夹,递归删除里面的
                    }else {
                        delEmptyDir(file1);
                    }
                }
            }
        }
    }
}

2 IO流概述

2.1 流的分类

  • 按照数据处理单位分类:字节流(InputStream\OutputStream)、字符流(Reader\Writer)
  • 按照数据的流向分类:输入流(InputStream\Reader)、输出流i(OutputStream\Writer)
  • 按照流的角色分类:节点流、处理流

1599444097724

2.2 流的体系结构

  • 抽象基类:InputStream\OutputStream\Reader\Writer
  • 访问文件的流:FileInputStream\FileOutputStream\FileReader\FileWriter
  • 缓冲流:BufferedFileInputStream\BufferedFileOutputStream\BufferedReader\BufferedWriter

1599444273016

2.3 重点说明的几个流节点

抽象基类 节点流(文件流) 缓冲流(处理流的一种)

InputStream FileInputStream BufferedInputStream

OutputStream FileOutputStream BufferedOutputStream

Reader FileReader BufferedReader

Writer FileWriter BufferedWriter

1599444469615

2.3 输入、输出的标准化过程

输入过程

  1. 创建File类的对象,指明读取的数据的来源(要求此文件一定存在)、

  2. 创建相应的输入流,将File类的对象作为参数传入流的构造器

  3. 具体的读入过程:

    ​ 创建相应的byte[] 或char[]

  4. 关闭流资源

说明:程序中出现的异常需要使用try-catch-finally处理

输出过程

  1. 创建File类的对象,指明写出的数据的位置(不要求此文件一定存在)

  2. 创建相应的输出流,将File类的对象作为参数,传入流的构造器中

  3. 具体的写入过程:

    write(char[]/byte[] buffer , 0, len)

    其中buffer是char类型或byte类型的数组,写出文件时是从0到len长度

  4. 关闭流资源

说明:程序中出现的异常需要使用try-catch-finally处理

3 节点流(或文件流)

3.1 FileReader、FileWriter的使用

  • FileReader
    • read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
    • 异常的处理:为了保证流资源一定可以执行关闭操作,需要使用try-catch-finally处理
    • 读入的文件一定要存在,不然会产生FileNotFoundException
  • FileWriter
    • 输出操作,对应的File文件可以不存在,并不会报异常
    • File对应的硬盘文件如果存在:
      • 如果流使用的构造器是:FileWriter(file, false)/FileWriter(file):对源文件的覆盖
      • 如果流使用的构造器是:FileWriter(file, true):对源文件的追加
FileReader的使用

读取某个文件的内容,写入到控制台中

    @Test
    public void testFileReader(){
        FileReader fr = null;
        try {
            //1创建文件对象
            File file = new File("hello.txt");
            //2创建流对象,将文件作为参数传入到流的构造器中
            fr = new FileReader(file);
            //3处理数据
            //方式一:创建字符型的数组
            char[] buffer = new char[5];
            //定义每次读取char型数组中的元素个数
            int len;
            //read(char[] buffer)返回的是buffer数组中字符的个数,如果达到末尾返回-1
            while ((len = fr.read(buffer)) != -1){
                //方式1:使用String(char[] buffer, 0, len)构造器,使用String接收
                String str = new String(buffer, 0, len);
                System.out.print(str);
                //方式2:使用for循环遍历char[]
                //for(int i = 0; i < len; i++){
                    //System.out.print(buffer[i]);
                //}
            }
            //方式二
            //int data = fr.read();
           // while(data != -1){
               // System.out.print((char)data);
                //data = fr.read();
            //}
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4关闭流资源
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
FileWriter的使用

读取某个文件内容,输出到另一个文件中。

FileWriter(String descPath, true)//true,表示追加到目标文件内,默认为false,如果没有目标文件则创建,如果存在目标文件则覆盖。

    @Test
    public void testFileWriter() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            //造文件
            File srcFile = new File("hello.txt");
            File descFile = new File("descFile.txt");
            //造流
            fr = new FileReader(srcFile);
            fw = new FileWriter(descFile, true);//使用true表示追加在目标文件后
            //处理数据
            char[] buffer = new char[5];
            int len;
            while ((len = fr.read(buffer)) != -1){
                fw.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null){
                //关闭流资源
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

3.2 FileInputStream、FileOutputStream的使用

  • 对于文本文件(.txt;.java;.c;.cpp),使用字符流处理
  • 对于非文本文件(.jpg;.mp4;.doc;.ppt)等,使用字节流处理
  • FileInputStream

    • 构造器:
      • FileinputStream(File file)
      • FileInputStream(String filePath)
    • 方法:

  • FileOutStream

    • 构造器:
      • FileOutPutStream(File file)
      • FileOutPutStream(String filePath)
      • FileOutPutStream(File file, boolean append)
      • FileOutPutStream(String filePath, boolean append)
    • 方法:

FileInputStream的使用
//第一种方式:单个字节的读取
FileInputStream fis = new FileInputStream("./testIO/a.txt");
int data = fis.read();
whihe(data != -1){
    System.out.print((char)data);
    data = fis.read();
}
fis.close();

//第二种方式:字节数组的方式读取
FileInputStream fis = new FileInputStream("./testIO/a.txt");
byet[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
    String str = new String(buffer, 0, len);
    System.out.print(str);
}
fis.close();
FileOutputStream的使用

实现对图片的复制
    @Test
    public void testFileInputStream(){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //造文件
            File srcFile = new File("picture.png");
            File descFile = new File("descPicture.png");
            //造流
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(descFile);
            //处理数据,使用byte[]
            byte[] buffer = new byte[5];
            int len;
            //复制图片
            while ((len = fis.read(buffer)) != -1){
                fos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null){
                //关闭流资源
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

4 缓冲流

4.1 缓冲流涉及到的类

  • BufferedReader
  • BufferedWriter
  • BufferedInputStream
  • BufferedOutputStream

4.2 缓冲流作用

  • 作用:提高流的读取速度、写入速度
  • 提高读写速度的原因:内部提供了一个缓冲区,
  • 默认情况下是8kb

1599454031513

4.3 flush和close

IO流中每一个类都实现了Closeable接口,它们进行资源操作之后都需要执行close()方法将流关闭 。但字节流与字符流的不同之处在于:字节流是直接与数据产生交互,而字符流在与数据交互之前要经过一个缓冲区

使用字符流对资源进行操作的时候,如果不使用close()方法,则读取的数据将保存在缓冲区中

img

    @Test
    public void test2() throws IOException {
        FileWriter fos = new FileWriter("iotest\\file2.txt");
        fos.write("尚硅谷");
        fos.flush();
        fos.write("hello");//写出文件内容:尚硅谷
    }
    @Test
    public void test3() throws IOException {
        FileOutputStream fos = new FileOutputStream("iotest\\file3.txt");
        fos.write("hello".getBytes());
        fos.flush();
        fos.write("hi".getBytes());//写出文件内容:hello
    }
BufferedReader、BufferedWriterc复制文本文件
    @Test
    public void testBufferedReader(){
        //造文件
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            File srcFile = new File("hello.txt");
            File descFile = new File("descHello.txt");
            //造流
            FileReader fr = new FileReader(srcFile);
            FileWriter fw = new FileWriter(descFile, true);
            //包一层处理流
            br = new BufferedReader(fr);
            bw = new BufferedWriter(fw);

            //处理数据
            char[] cBuf = new char[5];
            int len;
            while ((len = br.read(cBuf)) != -1){
    //            String str = new String(cBuf, 0, len);
    //            System.out.print(str);
                bw.write(cBuf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null){
                //关闭资源
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
BufferedInputStream、BufferedOutputStream复制字节文件
    @Test
    public void testBufferedInputStream() {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //造文件
            File srcFile = new File("picture.png");
            File descFile = new File("pictureInputStream.jpg");
            //造节点流
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(descFile);
            //造缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            //处理数据
            byte[] buffer = new byte[5];
            int len;
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null){
                //关闭流资源
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

5 转换流

5.1 转换流涉及到的类(属于字符流)

  • InputStreamReader:将一个字节的输入流转换为字符的输入流
    • 解码:字节、字节数组 —> 字符数组、字符串
  • OutputStreamWriter:将一个字符的输出流转换成字节的输出流
    • 解码:字符数组、字符串 —> 字节、字节数组

5.2 作用

  • 提供了字节流和字符流之间的转换

1599477963307

5.3 字符集

  • ASCII:美国标准信息交换码
    • 用一个字节的7位可以表示
  • ISO8859-1:拉丁码表。欧洲码表
    • 用一个字节的8位表示。
  • GB2312:中国的中文编码表。最多两个字节编码所有字符
  • GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
  • Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
  • UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
InputStreamReader的使用
    //转换流,读取一个UTF-8编码的文件,解码显示在控制台
    @Test
    public void test1() {
        InputStreamReader isr = null;
        try {
            //1.造文件,造流,造处理流
            FileInputStream fis = new FileInputStream(new File("dbcp.txt"));
            //解码
            isr = new InputStreamReader(fis,"utf-8");
            //2.处理数据
            char[] cbuf = new char[20];
            int len;
            while ((len = isr.read(cbuf)) != -1){
                String str = new String(cbuf, 0, len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (isr != null){
                //3.关闭资源
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
InputStreamReader、OutputStreamWriter的综合使用
    //综合使用InputStreamReader、OutputStreamWriter
    @Test
    public void test2(){
        InputStreamReader isr = null;//指定编码格式
        OutputStreamWriter osw = null;//指定解码格式
        try {
            //1. 造文件,造流,造处理流
            FileInputStream fis = new FileInputStream("dbcp.txt");
            FileOutputStream fos = new FileOutputStream("dbcp2.txt");

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

            //2. 处理数据
            char[] cbuf = new char[20];
            int len;
            while ((len = isr.read(cbuf)) != -1){
                osw.write(cbuf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (isr != null){
                //3. 关闭资源
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (osw != null){
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

6 其他流的使用

6.1 标准输入输出流

  • System.in:标准输入流,默认从键盘输入
  • System.out:标准输出流,默认控制台输出
  • 修改默认的输入:System.setIn(InputStream is)
  • 修改默认的输出:System.setOut(PrintStream ps)
练习题

从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,
直至当输入“e”或者“exit”时,退出程序。

  • 方式一:使用while循环+Scanner
  • 方式二:利用缓冲流中的readLine()方法
    • 首先创建一个InputStreamReader输入转换流使用其InputStreamReader(InputStream)的构造器,因为是从控制台输入,所以构造器内的输入流为System.in
    • 然后将转换流作为BufferedInputStream()的参数传入,
    • 然后调用BufferedInputStream的readLine()方法,读取字符串
public class Test04 {
    //方式一:使用Scanner(System.in)的方式
//    public static void main(String[] args) {
//        while (true) {
//            Scanner scanner = new Scanner(System.in);
//            System.out.println("请输入字符串:");
//            String line = scanner.nextLine();
//            if (line.equals("e") || line.equals("exit")) {
//                break;
//            }
//            String up = line.toUpperCase();
//            System.out.println(up);
//        }
//
//    }

    //方式二:使用System.in实现,System.in ---> 转换流 ---> BufferedReader的readLine()
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            //转换流InputStreamReader(输入流)
            InputStreamReader isr = new InputStreamReader(System.in);
            //BufferedReader处理流
            br = new BufferedReader(isr);
            while (true){
                System.out.println("请输入字符串");
                String data = br.readLine();
                if (data.equalsIgnoreCase("e") || data.equalsIgnoreCase("exit")){
                    break;
                }
                String string = data.toUpperCase();
                System.out.println(string);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

6.2 打印流

  • PrintStream
  • PrintWriter
练习题

打印0-255的ASCII码,输出到本地文件中

    @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();
            }
        }
    }

6.3 数据流

  • DataInputStream
  • DataOutputStream

作用:用于读取或写出基本数据类型的变量或字符串,从内存写出到磁盘,从磁盘写入到内存

练习题

练习:将内存中的字符串、基本数据类型的变量写出到文件中。

此时是乱码的~

    @Test
    public void test1(){
        DataOutputStream dos = null;
        try {
            //1 造流;将内存中的数据存入到磁盘,应该是输出流
            dos = new DataOutputStream(new FileOutputStream("out1.txt"));

            //2 处理数据
            dos.writeUTF("Tom");//写入字符串
            dos.writeInt(23);//写入整型
            dos.writeBoolean(true);//写入布尔型
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null){
                //3 关闭资源
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

将本地文件的内容重写写入到内存

    @Test
    public void test2(){
        DataInputStream dis = null;
        try {
            //1 造文件,造流;此时相对于内存来说是写入数据
            dis = new DataInputStream(new FileInputStream("data.txt"));
            //2 将数据写入到内存
            //注意的是此时的写入内存的顺序必须和当时写入到磁盘的顺序一样
            String name = dis.readUTF();
            int age = dis.readInt();
            boolean gender = dis.readBoolean();
            System.out.println("name:"+name);
            System.out.println("age:"+age);
            System.out.println("gender:"+gender);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dis != null){
                //3 关闭资源
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

7 对象流

  • ObjectOutputStream:内存中的对象 —> 存储的文件、通过网络传输出去到另一个节点,序列化过程
  • ObjectInputStream:存储中的文件、通过网络接收过来 —> 内存的对象。反序列化过程

7.1 对象的序列化机制

  • 对象的序列化机制:
    • 序列化过程:允许把内存的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久化保存到磁盘上,或者通过网络将这种二进制流传送到另一个网络节点。
    • 反序列化过程:当其他程序获得了这种二进制和流,就可以恢复成原来的Java对象

7.2 序列化的代码实现

package www.codejiwei.java;
import org.junit.Test;
import java.io.*;
/**
 * @Author jiweicode
 * @Date 2020/9/10 - 10:59
 * @Version 1.0
 * @Description
 * 对象流:
 * ObjectOutputStream   ObjectInputStream
 * 1. 作用:用于存储基本数据类型数据或对象的处理流,可以把Java对象写入到数据源中,也可以把对象从数据源中还原回来
 * 2. 要想一个Java对象是可序列化的,需要满足:
 *      2.1 类要实现Serializable接口(标识接口)
 *      2.2 当前类需要具有一个全局常量,序列化常量SerialVersionUID
 *      2.3 除了当前类实现Serializable接口之外,还必须保证其内部的所有属性也是可序列化的(默认基本数据类型都是可序列化的)
 *      补充:ObjectOutputStream和ObjectInputStream不能序列化static和t'ransient修饰的属性
 * 3.序列化机制:
 *      对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种
 *      二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。
 *      当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
 **/
//String的序列化到本地文件object.dat
public class ObjectInputOutputStreamTest {
    @Test
    public void testObjectOutputStream(){
        ObjectOutputStream oos = null;
        try {
            //1.
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
            //2.
            oos.writeObject(new String("我爱北京天安门"));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null){
                //3.
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //String对象的反序列化,读取本地文件转换为String对象
    @Test
    public void testObjectInputStream(){
        ObjectInputStream ois = null;
        try {
            //1.
            ois = new ObjectInputStream(new FileInputStream("object.dat"));
            //2.
            Object o1 = ois.readObject();
            String str = (String)o1;
            System.out.println(str);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                //3.
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    //将Person对象序列化存为本地文件
    @Test
    public void testObjectOutputStream2(){
        ObjectOutputStream oos = null;
        try {
            //1.
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
            //2.
            oos.writeObject(new Person("Tom", 23, new Account(1)));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                //3.
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //Person对象的反序列化,读取本地文件转换为Person对象
    @Test
    public void testObjectInputStream2(){
        ObjectInputStream ois = null;
        try {
            //1
            ois = new ObjectInputStream(new FileInputStream("object.dat"));
            //2
            Object object = ois.readObject();
            Person p1 = (Person)object;
            System.out.println(p1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                //3
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package www.codejiwei.java;

import java.io.Serializable;

/**
 * @Author jiweicode
 * @Date 2020/9/10 - 11:56
 * @Version 1.0
 * @Description
 **/
//Person对象必须实现Serializable接口;提供SerialVersionUID序列号;Account对象作为属性出现也必须实现Serializable接口
public class Person implements Serializable {
    private String name;
    private int age;
    private Account account;
    private static final long serialVersionUID = -694470754667710L;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, Account account) {
        this.name = name;
        this.age = age;
        this.account = account;
    }

    public Person() {
    }

    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 long getSerialVersionUID() {
        return serialVersionUID;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", account=" + account +
                '}';
    }
}
class Account implements Serializable{
    private int id;

    public Account(int id) {
        this.id = id;
    }

    public Account() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                '}';
    }
}

8 随机读取文件流

8.1 RandomAccessFile类

  • RandomAccessFile类直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
  • RandomAccessFile既可以作为y一个输入流,也可以作为一个输出流
  • 如果RandomAccessFile作为输出流时,写出的文件如果不存在,则在执行过程中自动创建;
    • 如果写出的文件存在,则会覆盖源文件内容(默认从文件头覆盖)
  • 可以通过相关的操作,实现RandomAccessFile的插入。方法:seek(int num)定位到num位置

8.2 典型代码

使用RandomAccessFile复制图片
    @Test
    public void test1(){
        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            //1. 造文件造流
            //1.1 从本地文件读取
            raf1 = new RandomAccessFile(new File("beauty.jpg"),"r");
            //1.2 写入到本地的哪里?
            raf2 = new RandomAccessFile("beauty1.jpg", "rw");

            //2. 处理数据,将图片资源使用字节数组进行存储
            byte[] buffer = new byte[1024];
            int len;
            while ((len = raf1.read(buffer)) != -1){
                raf2.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭资源
            if (raf1 != null){
                try {
                    raf1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (raf2 != null){
                try {
                    raf2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
使用RandomAccessFile实现文本中插入操作

在文件hello.txt中的abcdefghijklmn的c后面插入zxf

    @Test
    public void test2(){
        RandomAccessFile raf1 = null;
        try {
            //1. 造文件造流
            raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

            //2. 处理数据
            //2.1 首先将指针指到3的位置,复制后面的所有数据
            raf1.seek(3);
            StringBuilder sbf = new StringBuilder((int) new File("hello.txt").length());
            byte[] buffer = new byte[20];
            int len;
            while ((len = raf1.read(buffer)) != -1){
                sbf.append(new String(buffer, 0, len));
            }
            //2.2 调回指针,添加要插入的数据
            raf1.seek(3);
            raf1.write("zxf".getBytes());
            //2.3 将StringBuilder的数据写入文件
            raf1.write(sbf.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (raf1 != null){
                //3. 关闭资源
                try {
                    raf1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

9 Path、Paths、Files的使用

1.NIO的使用说明:

Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java
IO AP。
NIO与原来的IO同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于
通道的IO操作。
NIO将以更加高效的方式进行文件的读写操作。
随着 JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为 NIO.2。

2.Path的使用 —jdk7提供
2.1Path的说明:
Path替换原有的File类。
2.2如何实例化:

1599729899754

2.3常用方法:1599729906850

3.Files工具类 —jdk7提供
3.1作用:
操作文件或文件目录的工具类
3.2常用方法:

1599729917758

1599729922230

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最佳第六六六人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值