Java基础:IO

IO流

一、流的分类:

  • 1.操作数据单位:字节流、字符流
  • 2.数据的流向:输入流、输出流
  • 3.流的角色: 节点流、处理流

二、流的体系结构

抽象基类       	 节点流(或文件流)                                        缓冲流(处理流的一种)
InputStream     FileInputStream ---> (read(byte[] buffer))    <---   BufferedInputStream
OutputStream    FileOutputStream --->(write(byte[] buffer,0,len))<---BufferedOutputStream
Reader          FileReader     --->  (read(char[] chars))      <---  BufferedReader
Writer          FileWriter    --->   (write(char[] chars,0,len) <--- BufferedWriter

节点流:字符流

适用于文本文件的读写(.txt .java .c)

FileReader
FileWriter

read()


  • 从该输入流读取一个字节的数据,返回读入的一个字符,如果到达文件末尾,返回-1
  • 异常处理:为保证资源一定可以执行关闭操作。需要使用try-catch-finally
  • 读入的文件一定要存在,否则就会会FileNotFoundException异常
   @Test
    public void test() {
        /*
            read():从该输入流读取一个字节的数据,返回读入的一个字符,如果到达文件末尾,返回-1
            异常处理:为保证资源一定可以执行关闭操作。需要使用try-catch-finally
            读入的文件一定要存在,否则就会会FileNotFoundException异常
         */

        FileReader fs = null;
        try {
            //1.File类的实例化
            File file = new File("zmj.txt");
            System.out.println(file.getAbsolutePath());
            //2.FileReader流的实例化
            fs = new FileReader(file);

            //3.读入操作
            int read = fs.read();
            while (read != -1){
                System.out.print((char)read);
                read = fs.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //4、流的关闭操作
                if(fs != null)
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

read(char[] cbf):更高效

	@Test
    public void test2() {
        FileReader fr = null;
        try {
            File file = new File("zmj.txt");
            fr = new FileReader(file);

            //read(char[] cbf);返回每次读入cbf数组中的字符个数。如果达到文件末尾,返回-1
            char[] chars = new char[3];
            int read;
            while ( (read= fr.read(chars))!=-1){
                //方式一
//                for (int i=0;i<read;i++){
//                    System.out.println(chars[i]);
//                }
            //方式二
            String str = new String(chars, 0, read);
            System.out.print(str);
            }

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

write()


从内存中写出数据到硬盘的文件里

说明:

  • 1.输出操作,对应的File可以不存在,不会报异常

    ***File对应的硬盘文件如果不存在:***在输出的过程中,会自动创建该文件
    File对应的硬盘文件如果存在:
    如果流使用的构造器是:FileWriter(file,true);写的内容将在原文件的基础上追加
    如果流使用的构造器是:FileWriter(file,false);写的内容将覆盖原文件的内容
    构造器FileWriter(file)默认为false

@Test
public void test3()throws Exception{
    //1.初始化文件类,指明要写到的文件
    File file = new File("zmj1.txt");
    //2.初始化FileWriter流对象,用于数据的写出
    FileWriter fw = new FileWriter(file);

    //3.写出操作
    fw.write("zmj123!\n");
    fw.write("hello!");

    //4.关闭流文件
    fw.close();
}

/*
    文件的复制操作
 */
@Test
public void test4(){
    FileReader fr = null;
    FileWriter fw = null;
    try {
        File zmj1File = new File("zmj1.txt");
        File zmj2File = new File("zmj2.txt");

        fr = new FileReader(zmj1File);
        fw = new FileWriter(zmj2File);

        //3.数据的读入和写出操作
        char[] chars = new char[5];
        int len;
        while ((len=fr.read(chars)) != -1){
            fw.write(chars,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.关闭流
        try {
            if(fr!=null)
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (fw!=null)
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

节点流:字节流

适用于非文本文件(.jpg .png .mp3 .doc .ppt)

FileInputStream
FileOutputStream

  • 使用字节流处理文本文件 有可能有会导致字符乱码:因为其使用的byte[]存储数据而非char[]
//使用字节流处理文本文件测试
@Test
public void test() {
    FileInputStream fis = null;
    try {
        File file = new File("zmj2.txt");
        fis = new FileInputStream(file);
        byte[] bytes = new byte[5];
        int len;
        while ((len=fis.read(bytes)) != -1){
            for (int i=0;i<len;i++){
                System.out.print((char) bytes[i]);//hello!¦ᄌᆳ₩ヨヌ¦ᄍᄆ￧ᅠチ
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if(fis!=null)
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

非文本文件的复制

//非文本文件的复制操作
@Test
public void test2(){
    long start = System.currentTimeMillis();
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        File file = new File("zmj.jpg");
        File file1 = new File("zmj1.jpg");

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

        byte[] bytes = new byte[5];
        int len;
        while ((len=fis.read(bytes)) != -1){
            fos.write(bytes,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if(fis!=null)
                fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (fos!=null)
                fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    long end = System.currentTimeMillis();
    System.out.println("花费时间:"+(end-start));//6800毫秒
}


public void copyFile(String srcPath,String destPath){

    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        File file = new File(srcPath);
        File file1 = new File(destPath);

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

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

public void test3(){
    long start = System.currentTimeMillis();

    String srcPath="被复制视频.mp4";
    String destPath="生成目标视频.mp4";
    copyFile(srcPath,destPath);

    long end = System.currentTimeMillis();

    System.out.println("执行时间:"+(end-start));
}

处理流:缓冲流

处理流,就是“套接”在已有流的基础之上的流

  • 非文本文件缓冲流

    BufferedInputStream
    BufferedOutputStream

  • 文本文件缓冲流

    BufferedReader
    BufferedWriter

缓冲流作用:


  • 提供流的读取,写入的速度
  • 提高读写速度的原因,内部提供了一个缓冲区

复制非文本文件:同样的两张图片:使用缓冲流比不使用复制快了100倍

    /*
        复制非文本文件:缓冲流
     */
    @Test
    public void test(){
        long start = System.currentTimeMillis();
        FileInputStream fis = null;
        FileOutputStream fos = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //1.实例化文件构造器
            File file = new File("zmj.jpg");
            File file1 = new File("zmj1.jpg");

            //2.实例化流
            //2.1实例化节点流
            fis = new FileInputStream(file);
            fos = new FileOutputStream(file1);

            //2.2实例化缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            //3.复制操作
            byte[] bytes = new byte[10];
            int len;
            while ((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流
            if(bis!=null)
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(bos!=null)
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            //关闭外层流的同时,内层流也会自动进行关闭,所以可以省略内层流的关闭操作
//            fis.close();
//            fos.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("使用缓冲流的处理时间:"+(end-start));//65毫秒
    }

复制文本文件

    //文本文件缓冲流复制操作
    public void test1(){

        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            br = new BufferedReader(new FileReader(new File("zmj.txt")));
            bw = new BufferedWriter(new FileWriter(new File("zmj2.txt")));

            //方式一
//        char[] buffer = new char[1024];
//        int len;
//        while ((len=br.read(buffer))!=-1){
//            bw.write(buffer,0,len);
//        }

            //方式二 readLine()  -->字符流缓冲流的方法
            String date;
            while ((date=br.readLine()) != null){
    //            bw.write(date);//data中不包含换行符
                bw.write(date);
                bw.newLine();//换行方法
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br!=null)
                    br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bw!=null)
                    bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

处理流:转换流

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

OutputStreamWriter将一个字符的输出流转换为字节的输出流

转换流作用

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

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

    @Test
    public void test2(){
        FileInputStream fis = null;
        InputStreamReader isr = null;
        try {
            //使用字节流读取文本文件
            fis = new FileInputStream("zmj2.txt");
            //使用转换流对字节流进行转换 --字符
            //参数2指明了字符集,具体使用哪个字符集,取决于文件保存是使用的字符集编码格式
            isr = new InputStreamReader(fis, "utf-8");

            char[] chars = new char[5];
            int len;
            while ((len=isr.read(chars))!=-1){
//                for(int i=0;i<len;i++){
//                    System.out.println(chars[i]);
//                }
                String str = new String(chars, 0, len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (isr!=null)
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(fis!=null)
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

标准的输入输出流

  • System.in:标准的输入流,默认从键盘输入
  • System.out:标准的输出流,默认从控制台输出
  • System类的setIn(InputStream is)/setOut(PrintStream ps)方式重新指定输入和输出的方式位置

练习:从键盘输入字符串,要求将读取到的整行字符串转成大写输出,然后继续进行输入操作,输入e退出

方法:使用System.in实现。System.in —> 转换流 —> BufferedReader的readLine()

public class IoInAndOut {

    public static void main(String[] args) {
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            isr = new InputStreamReader(System.in);
            br = new BufferedReader(isr);

            while (true){
                System.out.println("输入字符串");
                String str = br.readLine();
                if("e".equals(str)){
                    System.out.println("程序退出");
                    break;
                }
                //toUpperCase()将所有在此字符 String使用默认语言环境的规则大写
                String s = str.toUpperCase();
                System.out.println(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(isr!=null)
                    isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (br!=null)
                    br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

数据流

作用:用于读取或写出基本数据类型的变量或字符串

DataInputStream

DataOutputStream


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

@Test
public void test(){
    DataOutputStream dos = null;
    try {
        dos = new DataOutputStream(new FileOutputStream("data.txt"));

        dos.writeUTF("张明均");
        dos.flush();
        dos.writeInt(22);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {

        try {
            dos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

对象流

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

ObjectInputStream

ObjectOutputStream

  • java对象可序列化需要满足响应条件,见Person. java

  • 序列化机制:

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

    • 谈谈你对对象序列化机制的理解。
      序列化过程: 4
      反序列化过程:
    • 对象要想实现序列化,需要满足哪几个条件。
      1.实现接口: Serializable\标识接口+
      2.对象所在的类提供常量:序列版本号
      3.要求对象的属性也必须是可序列化的。(基本数据类型、String: 本身就已经是可序列化)

可序列化的类Person

/**
 * Created by KingsLanding on 2022/7/2 17:28
 *
 * Person需要满足如下要求,才能序列化
 *  1.需要实现接口Serializable:标识性接口
 *  2.当前类需要提供一个全局常量:serialVersionUID    相当于对象的身份标识,兼容版本控制
 *  3.除了当前Person类需要实现Serializable接口之外,也必须保证其内部所有属性也必须是可序列化的
 *  (默认情况下,基本数据类型是可序列化的),如果有内部类的话该内部类也要可序列化设置
 *
 *  ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
 */
public class Person implements Serializable {

    public static final long serialVersionUID = 42123354653L;

    String name;
    int age;

    public Person() {
    }

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

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试

public class ObjectStream {

    /*
    序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
    使用ObjectOutputStream实现
     */
    @Test
    public void test(){
        ObjectOutputStream obs = null;
        try {
            //1.实例化对象流
            obs = new ObjectOutputStream(new FileOutputStream("object.dat"));
            //2.写入对象数据
            obs.writeObject(new String("对像流测试"));
            obs.flush();//刷新操作
            obs.writeObject(new Person("张明均",20));
            obs.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                obs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    反序列化过程:将磁盘文件中的对象还原为内存中的一个java对象
    使用ObjectOutputStream进行实现
     */

    @Test
    public void test1(){

        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));

            Object obj = ois.readObject();
            String str = (String)obj;
            Person person =(Person)ois.readObject();

            System.out.println(str);
            System.out.println(person);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

NIO

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

​ 随着JDK 7的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为NIO2


随机存储流RandomAccessFile

  • RandomAccessFile的使用
    1.RandomAccessFile直接继承于java. lang. object类, 实现了DataInputDataOutput接口
    2.RandomAccessFile 既可以作为一个输入流,又可以作为一个输出流
    3.如果RandomAccessFile作为输出流时, 写出到的文件如果不存在,则在执行过程中自动创建

如果写出的文件存在,则会对原有文件内容进行覆盖。(默认情况下, 从头覆盖)

  • 可以通过操作,实现RandomAccessFile“插入”的效果,使用seek()定位,将该位置后面的所有字符转移到内存中,"插入"完成后再将内存中的字符复写到原文件中;存在内存占用过多的问题
public class Random {
    @Test
    public void test(){
        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            raf1 = new RandomAccessFile(new File("zmj.jpg"),"r");//可读
            raf2 = new RandomAccessFile(new File("zmj2.jpg"),"rw");//可读写

            byte[] bytes = new byte[1024];
            int len;
            while ((len=raf1.read(bytes))!=-1){
                raf2.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                raf1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                raf2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void test2()throws Exception{

        RandomAccessFile rw = new RandomAccessFile(new File("zmj.txt"), "rw");
        rw.seek(3);
        rw.write(123);
        rw.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

King'sLanding

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

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

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

打赏作者

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

抵扣说明:

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

余额充值