栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JavaSE——IO流

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JavaSE——IO流

IO流 一、IO流概述
  1. 什么是IO?

    I : Input
    O : Output
    通过IO可以完成硬盘文件的读和写。

  2. IO的分类

    (1)一种方式是按照流的方向进行分类:

    ​ 以内存作为参照物,
    ​ 往内存中去,叫做输入(Input)。或者叫做读(Read)。
    ​ 从内存中出来,叫做输出(Output)。或者叫做写(Write)。

    (2)另一种方式是按照读取数据方式不同进行分类:
    有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件 都可以读取。包括:文本文件,图片,声音文件,视频文件等…
    假设文件file1.txt,采用字节流的话是这样读的:
    a中国bc张三fe
    第一次读:一个字节,正好读到’a’
    第二次读:一个字节,正好读到’中’字符的一半。
    第三次读:一个字节,正好读到’中’字符的另外一半。

    ​ 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取
    ​ 普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取。
    ​ 假设文件file1.txt,采用字符流的话是这样读的:
    ​ a中国bc张三fe
    ​ 第一次读:'a’字符('a’字符在windows系统中占用1个字节。)
    ​ 第二次读:'中’字符('中’字符在windows系统中占用2个字节。)

    ​ 综上所述:流的分类
    ​ 输入流、输出流
    ​ 字节流、字符流

  3. java IO流的四大家族:

    ​ 四大家族的首领(四大家族的首领都是抽象类。(abstract class)):
    ​ java.io.InputStream 字节输入流
    ​ java.io.OutputStream 字节输出流

    ​ java.io.Reader 字符输入流
    ​ java.io.Writer 字符输出流

    所有的流都实现了:
    java.io.Closeable接口,都是可关闭的,都有close()方法。
    流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。养成好习惯,用完流 一定要关闭。

    所有的输出流都实现了:
    java.io.Flushable接口,都是可刷新的,都有flush()方法。
    养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据
    强行输出完(清空管道!)刷新的作用就是清空管道。
    注意:如果没有flush()可能会导致丢失数据。

    **注意:**在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

  4. 需要掌握的流

    文件专属:
    java.io.FileInputStream(掌握)
    java.io.FileOutputStream(掌握)
    java.io.FileReader
    java.io.FileWriter

    转换流:(将字节流转换成字符流)
    java.io.InputStreamReader
    java.io.OutputStreamWriter

    缓冲流专属:
    java.io.BufferedReader
    java.io.BufferedWriter
    java.io.BufferedInputStream
    java.io.BufferedOutputStream

    数据流专属:
    java.io.DataInputStream
    java.io.DataOutputStream

    标准输出流:
    java.io.PrintWriter
    java.io.PrintStream(掌握)

    对象专属流:
    java.io.ObjectInputStream(掌握)
    java.io.ObjectOutputStream(掌握)


二、文件专属流以及转换流
  1. FileInputStream

​ ①文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。

​ ②字节的方式,完成输入的操作,完成读的操作(硬盘—> 内存)

文件路径:D:\Java\007-API文档 (IDEA会自动把编程\,因为java中表示转义) 
写成这个/也是可以的。都是采用了:绝对路径的方式。
package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest01 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        //创建文件字节输入流对象
        try {
             fis = new FileInputStream("D:\Java\007-API文档\111");

             //开始读
            int readDate = fis.read();//这个方法的返回值是:读取到的“字节”本身。
            System.out.println( readDate);//97

            System.out.println( fis.read());//98
            System.out.println( fis.read());//99
            System.out.println( fis.read());//100
            System.out.println( fis.read());//101
            System.out.println( fis.read());//102
            System.out.println( fis.read());//-1  已经读到文件的末尾了,再读的时候读取不到任何数据,返回-1.

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

以上程序的缺点是 一次读取一个字节byte,这样内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面了。

将以上程序进行改进。循环

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest02 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\Java\007-API文档\111");

            while(true) {
                int readData = fis.read();
                if(readData == -1) {
                    break;
                }
                System.out.println(readData);
            }

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

再改进

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest02 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\Java\007-API文档\111");

            int readData = 0;
            while((readData = fis.read()) != -1){
                System.out.println(readData);
            }

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

​ ③IDEA默认的当前路劲是工程Project的根

​ ④采用byte数组开始读,一次读取多个字节,最多读取“数组.length”个字节。

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest03 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        try {

            fis = new FileInputStream("D:\Java\007-API文档\111");

            // 开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节。
            byte[] bytes = new byte[4]; // 准备一个4个长度的byte数组,一次最多读取4个字节。
            // 这个方法的返回值是:读取到的字节数量。(不是字节本身)
            int readCount = fis.read(bytes);
            System.out.println(readCount); // 第一次读到了4个字节。
            
            //System.out.println(new String(bytes));//将字节数组全部转换成字符串 // abcd
            // 不应该全部都转换,应该是读取了多少个字节,转换多少个。
            System.out.println(new String(bytes,0, readCount));

            readCount = fis.read(bytes); // 第二次只能读取到2个字节。
            System.out.println(readCount); // 2
            
            System.out.println(new String(bytes));//将字节数组全部转换成字符串 // abcd
            System.out.println(new String(bytes,0, readCount));

            readCount = fis.read(bytes); // 1个字节都没有读取到返回-1
            System.out.println(readCount); // -1

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

改进,最终版

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest04 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\Java\007-API文档\111");

            byte[] bytes = new byte[4];
            int readCount = 0;
            while((readCount = fis.read(bytes)) != -1){
                System.out.print(new String(bytes,0,readCount));
            }
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

​ ⑤FileInputStream其他常用方法

​ int available():返回流当中剩余的没有读到的字节数量

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest05 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\Java\007-API文档\111");
            //读一个字节
            int readByte = fis.read();
            //还剩下可以读的字节的数量是:
            System.out.println("还剩下可以读的字节的数量是:" + fis.available());
            
            //该方法的用处:可以知道字节数量,直接读就可以,不需要再循环,但是byte数组不能太大,不适合太大的文件
            byte[] bytes = new byte[fis.available()];
            int readCount = fis.read(bytes);
            System.out.println(new String(bytes));

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

long skip(long n):跳过几个字节不读。

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest06 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\Java\007-API文档\111");

            fis.skip(3);
            System.out.println(fis.read());
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  1. FileOutputStream

​ ① 文件字节输出流,负责写。从内存到硬盘。

package IO;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {

        FileOutputStream fos = null;
        try {
            //myfile文件不存在时,会自动新建
            // 这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入。
            //fos = new FileOutputStream("myfile");
            fos = new FileOutputStream("myfile",true);//以追加的方式在文件末尾写入。不会清空原文件内容。
            //开始写
            byte[] bytes = {39,22,30,25,29};
            //将byte数组全部写出
            fos.write(bytes);
            //将byte数组的一部分写出,再写两个
            fos.write(bytes,0,2);

            String s = "我是中国人";
            byte[] bytes2 = s.getBytes();
            fos.write(bytes2);
            //写完之后,最后一定要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  1. 文件复制

​ 使用FileInputStream + FileOutputStream完成文件的拷贝。拷贝的过程应该是一边读,一边写。
​ 使用以上的字节流拷贝文件的时候,文件类型随意,什么样的文件都能拷贝。

package IO;

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

public class Copy01 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            fis = new FileInputStream("D:\Java\007-API文档\111");
            fos = new FileOutputStream("C:\Java\IO\请粘贴到此处\111");

            //一边读 一边写

            byte[] bytes = new byte[1024 * 1024];//1MB
            int readCount = 0;
            while((readCount = fis.read(bytes)) != -1){
                fos.write(bytes,0,readCount);
            }

            //刷新,输出流最后要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            //一起try catch的话 其中一个出现异常 可能会影响另一个流的关闭
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
  1. FileReader的使用

    文件字符输入流,只能读取普通文本。读取文本内容时,比较方便,快捷。

    package IO;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class FileReaderTest01 {
        public static void main(String[] args) {
    
            FileReader reader = null;
            try {
                // 创建文件字符输入流
                reader = new FileReader("D:\Java\007-API文档\111");
    
                //准备一个char数组
                char[] chars = new char[4];
                // 往char数组中读
                reader.read(chars); // 按照字符的方式读取:第一次e,第二次f,第三次 风....
                for(char c : chars) {
                    System.out.println(c);
                }
    
                
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  2. FileWriter的使用

    FileWriter:
    文件字符输出流。写。只能输出普通文本。

    package IO;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class FileWriterTest01 {
        public static void main(String[] args) {
    
            FileWriter out = null;
            try {
                // 创建文件字符输出流对象
                //out = new FileWriter("file");
                out = new FileWriter("file", true);
    
                // 开始写。
                char[] chars = {'我','是','中','国','人'};
                out.write(chars);
                out.write(chars, 2, 3);
    
                out.write("我是一名java软件工程师!");
                // 写出一个换行符。
                out.write("n");
                out.write("hello world!");
    
                // 刷新
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  3. 复制普通文本文件

    使用FileReader FileWriter进行拷贝的话,只能拷贝“普通文本”文件。

    package IO;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class Copy2 {
        public static void main(String[] args) {
    
            FileReader in = null;
            FileWriter out = null;
            try {
                // 读
                in = new FileReader("Day2/src/IO/Copy2.java");
                // 写
                out = new FileWriter("Copy2.java");
    
                // 一边读一边写:
                char[] chars = new char[1024 * 512]; // 1MB
                int readCount = 0;
                while((readCount = in.read(chars)) != -1){
                    out.write(chars, 0, readCount);
                }
    
                // 刷新
                out.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    

三、缓冲流
  1. BufferedReader

    带有缓冲区的字符输入流。使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。

package IO;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderTest01 {
    public static void main(String[] args) {

        // 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流。
        // 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。
        // 像当前这个程序来说:FileReader就是一个节点流。BufferedReader就是包装流/处理流。
        FileReader read = null;
        BufferedReader br = null;
        try {
            read = new FileReader("file");
            br = new BufferedReader(read);

            

            // br.readLine()方法读取一个文本行,但不带换行符。
            String s = null;
            while((s = br.readLine()) != null){
                System.out.println(s);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  1. InputStreamReader 转换流
package IO;

import java.io.*;

public class BufferedReaderTest02 {
    public static void main(String[] args) {

        FileInputStream fis = null;
        BufferedReader br = null;
        InputStreamReader reader = null;
        try {
            
            //合并
            br = new BufferedReader(new InputStreamReader(new FileInputStream("file")));

            String line = null;
            while((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  1. BufferedWriter

    带有缓冲的字符输出流。

    package IO;
    
    import java.io.*;
    
    public class BufferedWriterTest01 {
        public static void main(String[] args) {
    
            BufferedWriter bw = null;
            try {
                //创建带有缓冲区的字符输出流
                //bw = new BufferedWriter(new FileWriter("file",true));
                bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file",true)));
    
                //开始写
                bw.write("我");
                bw.write("是");
                bw.write("n");
                bw.write("程序员");
                //刷新
                bw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                if (bw != null) {
                    try {
                        bw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

四、数据流
  1. java.io.DataOutputStream:数据专属的流。

    这个流可以将数据连同数据的类型一并写入文件。
    注意:这个文件不是普通文本文档。(这个文件使用记事本打不开。)

    package IO;
    
    import java.io.DataOutputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DataOutputStreamTest01 {
        public static void main(String[] args) {
    
            DataOutputStream dos = null;
            try {
                // 创建数据专属的字节输出流
                dos = new DataOutputStream(new FileOutputStream("data"));
    
                byte b = 100;
                short s = 200;
                long l = 300L;
                int i = 400;
                double d = 3.14;
                float f = 1.5F;
                boolean sex = false;
                char c = 'a';
    
                // 写数据
                dos.writeByte(b);
                dos.writeShort(s);
                dos.writeLong(l);
                dos.writeInt(i);
                dos.writeDouble(d);
                dos.writeFloat(f);
                dos.writeBoolean(sex);
                dos.writeChar(c);
    
                // 刷新
                dos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                // 关闭最外层
                if (dos != null) {
                    try {
                        dos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  2. DataInputStream:数据字节输入流。

    DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提前知道写入的顺序。读的顺序需要和写的顺序一致。才可以正常取出数据。

    package IO;
    
    import java.io.DataInputStream;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class DataInputStreamTest01 {
        public static void main(String[] args) {
    
            DataInputStream dis =null;
            try {
                dis = new DataInputStream(new FileInputStream("data"));
    
                System.out.println(dis.readByte());
                System.out.println(dis.readShort());
                System.out.println(dis.readLong());
                System.out.println(dis.readInt());
                System.out.println(dis.readDouble());
                System.out.println(dis.readFloat());
                System.out.println(dis.readBoolean());
                System.out.println(dis.readChar());
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally{
                if (dis != null) {
                    try {
                        dis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

五、标准输出流
  1. java.io.PrintStream:

    ​ 标准的字节输出流。默认输出到控制台。

    ​ 标准输出流不需要手动close()关闭。

    package IO;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    
    public class PrintStreamTest01 {
        public static void main(String[] args) {
    
            // 联合起来写
            System.out.println("hello world!");
    
            // 分开写
            PrintStream ps = System.out;
            ps.println("hello zhangsan");
            ps.println("hello lisi");
            ps.println("hello wangwu");
    
            // 标准输出流不再指向控制台,指向“log”文件。
            PrintStream printStream = null;
            try {
                printStream = new PrintStream(new FileOutputStream("log"));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            // 修改输出方向,将输出方向修改到"log"文件。
            System.setOut(printStream);
            // 再输出
            System.out.println("hello world");
            System.out.println("hello kitty");
            System.out.println("hello zhangsan");
        }
    }
    
     
  2. 应用:日志工具

    package IO;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Logger {
    
        //记录日志的方法
        public static void log(String msg){
    
            try {
                PrintStream ps = new PrintStream(new FileOutputStream("log.txt",true));
    
                //改变输出方向
                System.setOut(ps);
                Date nowTime = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
                String time = sdf.format(nowTime);
    
                System.out.println(time + ": " + msg);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    
    package IO;
    
    public class LoggerTest {
        public static void main(String[] args) {
    
    		//测试日志工具
            Logger.log("调用了System类的gc()方法,建议启动垃圾回收");
            Logger.log("调用了UserService的doSome()方法");
            Logger.log("用户尝试进行登录,验证失败");
            Logger.log("用户下线");
        }
    }
    

六、File类
  1. File类和四大家族没有关系,所以File类不能完成文件的读和写。

  2. File对象代表什么?
    文件和目录路径名的抽象表示形式。
    C:Drivers 这是一个File对象
    C:DriversLanRealtekReadme.txt 也是File对象。
    一个File对象有可能对应的是目录,也可能是文件。
    File只是一个路径名的抽象表示形式。

  3. File类的常用方法

    package IO;
    
    import java.io.File;
    import java.io.IOException;
    
    public class FileTest01 {
        public static void main(String[] args) {
    
            File f1 = new File("D:\file");
    
            //判断是否存在该文件
            System.out.println(f1.exists());
    
            //如果该文件不存在,则以文件的形式创建
            if(!f1.exists()){
                try {
                    f1.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
    
            //创建多重目录
            File f3 = new File("D:\mj");
            String parentPath = f3.getParent();
            System.out.println(parentPath);
    
            File parentFile = f3.getParentFile();
            System.out.println("获取绝对路径" + parentFile.getAbsolutePath());
        }
    }
    
    package IO;
    
    import java.io.File;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class FileTest02 {
        public static void main(String[] args) {
    
            File f1 = new File("D:\Java\007-API文档");
            // 获取文件名
            System.out.println("文件名:" + f1.getName());
    
            // 判断是否是一个目录
            System.out.println(f1.isDirectory()); // false
    
            // 判断是否是一个文件
            System.out.println(f1.isFile()); // true
    
            // 获取文件最后一次修改时间
            long haoMiao = f1.lastModified(); // 这个毫秒是从1970年到现在的总毫秒数。
            // 将总毫秒数转换成日期
            Date time = new Date(haoMiao);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime = sdf.format(time);
            System.out.println(strTime);
    
            // 获取文件大小
            System.out.println(f1.length()); //216064字节。
        }
    }
    
    package IO;
    
    import java.io.File;
    
    public class FileTest03 {
        public static void main(String[] args) {
    
            File f = new File("D:\Java");
            File[] files = f.listFiles();
            // foreach
            for(File file : files){
                //System.out.println(file.getAbsolutePath());
                System.out.println(file.getName());
            }
        }
    }
    

七、对象流
  1. 对象的序列化与反序列化

    (1)序列化 Serialize :java对象存储到文件中,将java对象的状态保存下来的过程。 过程中需要ObjectOutputStream.

    ​ 反序列化 DeSerialize :将硬盘上的数据重新恢复到内存当中,恢复成java对象。过程中需要ObjecInputStream.

    (2)参与序列化和反序列化的对象,必须实现Serializable接口。

    ​ 以下程序中Student没有实现Serializable接口,会出现java.io.NotSerializableException: Student对象不支持序列化!

    package IO;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    
    public class ObjectOutputStreamTest01 {
        public static void main(String[] args) {
    
            //创建java对象
            Student s = new Student(1111,"zhangsan");
            ObjectOutputStream oos = null;
            //序列化
            try {
                 oos = new ObjectOutputStream(new FileOutputStream("stu"));
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 序列化对象
            try {
                oos.writeObject(s);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //刷新
            try {
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                //关闭
                if (oos != null) {
                    try {
                        oos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    
    package IO;
    
    import java.io.Serializable;
    
    public class Student implements Serializable {
    
        private int num;
        private String name;
    
        public Student() {
        }
        public Student(int num, String name) {
            this.num = num;
            this.name = name;
        }
    
        public int getNum() {
            return num;
        }
    
        public void setNum(int num) {
            this.num = num;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "num=" + num +
                    ", name='" + name + ''' +
                    '}';
        }
    }
    

    (3)**注意:**通过源代码发现,Serializable接口只是一个标志接口:
    public interface Serializable {
    }
    这个接口当中什么代码都没有。 起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行 特殊待遇。Serializable这个标志接口是给java虚拟机参考的,会为该类自动生成一个序列化版本号。

    (4)反序列化

    package IO;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    
    public class ObjectInputStreamTest01 {
        public static void main(String[] args) {
    
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(new FileInputStream("stu"));
                
                System.out.println(ois.readObject());
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally{
                if (ois != null) {
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    (4)序列化多个对象

    ​ 可以将对象放到集合当中,序列化集合。参与序列化的ArrayList集合以及集合中的元素User都需要实现 java.io.Serializable接口。

    package IO;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ObjectOutputStreamTest02 {
        public static void main(String[] args) {
    
            List list = new ArrayList<>();
    
            list.add(new Student(1111,"zhangsan"));
            list.add(new Student(2222,"lisi"));
            list.add(new Student(3333,"dingwu"));
    
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(new FileOutputStream("students"));
    
                oos.writeObject(list);
    
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                if (oos != null) {
                    try {
                        oos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    package IO;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.util.List;
    
    public class ObjectInputStreamTest02 {
        public static void main(String[] args) {
    
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(new FileInputStream("students"));
    
                List stuList = (List)ois.readObject();
                for(Student student : stuList){
                    System.out.println(student);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if (ois != null) {
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    (5)transient关键字

    ​ 表示游离的,不参与序列化。

    (6)序列化版本号

    ​ java语言中是采用什么机制来区分类的?
    ​ 第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
    ​ 第二:如果类名一样,再怎么进行类的区别?靠序列化版本号进行区分。

    ​ 序列版本号的优点:

    ​ 不同的人编写了同一个类,但“这两个类确实不是同一个类”。这个时候序列化版本就起上作用。对于java虚拟机来说,java虚 拟机是可以区分开这两个类的,因为这两个类都实现了Serializable接口,都有默认的序列化版本号,他们的序列化版本号不 一样。所以区分开了。(这是自动生成序列化版本号的好处)

    ​ 自动序列化版本号的缺点:

    ​ 一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java
    ​ 虚拟机会认为这是一个全新的类。

    ​ 最终结论:
    ​ 凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。这样,以后这个类即使代码修改了,但是版 本号不变,java虚拟机会认为是同一个类。

    ​ private static final long serialVersionUID = 1L;


八、测试

​ 拷贝目录:

​ 将D:course拷贝到C盘根目录下。

​ 需要使用到:

​ FileInputStream

​ FileOutputStream
​ File

​ 可能需要使用到递归。

package IO.Homework;

import java.io.*;

public class CopyAll {
    public static void main(String[] args) {

        //拷贝源
        File srcFile = new File("D:\course");

        //拷贝目标
        File destFile = new File("C:\");

        //调用方法拷贝
        copyDir(srcFile,destFile);
    }

    
    private static void copyDir(File srcFile, File destFile) {

        if(srcFile.isFile()) {
            // srcFile如果是一个文件的话,递归结束。
            // 是文件的时候需要拷贝。
            // ....一边读一边写。
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                // 读这个文件
                in = new FileInputStream(srcFile);
                // 写到这个文件中
                String path = (destFile.getAbsolutePath().endsWith("\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\")  + srcFile.getAbsolutePath().substring(3);
                out = new FileOutputStream(path);
                // 一边读一边写
                byte[] bytes = new byte[1024 * 1024]; // 一次复制1MB
                int readCount = 0;
                while((readCount = in.read(bytes)) != -1){
                    out.write(bytes, 0, readCount);
                }
                out.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return;
        }

        //获取源下的子目录
        File[] files = srcFile.listFiles();

        for(File file : files){

            if(srcFile.isDirectory()){

                //新建对应的目录
                String srcDir = file.getAbsolutePath();
                String destDir = (destFile.getAbsolutePath().endsWith("\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\")  + srcDir.substring(3);
                File newFile = new File(destDir);
                if(!newFile.exists()){
                    newFile.mkdirs();
                }
            }
            //递归调用
            copyDir(file,destFile);
        }
    }
}

九、IO和Properties联用

(1)IO流:文件的读和写。

​ Properties:是一个Map集合,key和value都是String类型。

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class IoPropertiesTest01 {
    public static void main(String[] args) {

        // 新建一个输入流对象
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("myfile");

            // 新建一个Map集合
            Properties pro = new Properties();

            // 调用Properties对象的load方法将文件中的数据加载到Map集合中。
            pro.load(fis);

            // 通过key来获取value呢?
            System.out.println(pro.getProperty("username"));
            System.out.println(pro.getProperty("password"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

(2)IO+Properties的联合应用。
非常好的一个设计理念:
以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改 动,不需要重新编译,服务器也不需要重启。就可以拿到动态的信息。

(3)类似于以上机制的这种文件被称为配置文件,并且当配置文件中的内容格式是:
key1=value
key2=value
的时候,我们把这种配置文件叫做属性配置文件。

(4)java规范中有要求:属性配置文件建议以.properties结尾,但这不是必须的。这种以.properties结尾的文件在java中被称为:属性 配置文件。其中Properties是专门存放属性配置文件内容的一个类。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/685249.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号