Java IO流

Java IO流

什么是IO流?

I:Input O:Output (java.io.*)
通过IO可以完成硬盘文件的读和写

IO流的分类:输入流,输出流,字节流,字符流

(1)按照流的方向进行分类:以内存为参照物
----------- 往内存中去,叫做输入(Input),或者叫做读(Read)
----------- 从内存中出来,叫做输出(Output),或者叫做写(Write)
(2)按照读取数据方式不同进行分类
-----------有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频
-----------有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取文本文件而存在的,这种流不能读取:图片,声音,视频等文件,只能读取纯文本文件,连Word文件都无法读取。

四个流

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结尾的都是字符流

Java.IO包下常用的流

文件专属:
Java.io.FileInputStream
Java.io.FilePutputStream
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.DateInputStream
Java.io.DateOutputStream

标准输出流:
Java.io.PrintWriter
Java.io.PrintStream

对象专属流:
Java.io.ObjectInputStream
java.io.ObjectOutputStream

Java.io.FileInputStream(文件字节输入流) (重要)

字节文件的读取:
int read(byte[] b)

  • 这个方法返回的是读取到的字节数量(不是字节本身)
  • 一次最多读取b.length个字节,往byte[] 数组当中读
  • 减少硬盘和内存的交互,提高程序的执行效率
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest {
    public static void main(String[] args){
    
        FileInputStream file  = null;
        try {
                  file =  new FileInputStream("/home/liang/software/idea/test.txt"); //注意:工程Projects的根就是IDEA的默认路径
                  //新建一个byte数组
                  byte[] bytes = new byte[4];

                  int readCount = 0;
                  while ((readCount = file.read(bytes)) != -1){
                      System.out.print(new String(bytes, 0, readCount));    //把byte数组转换成字符串,读到多少转多少个
            }


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

FileInputStream类的其他常用方法:

  • int available() :返回流当中剩余的没有读到的字节数量
  • long skip(long n) :跳过几个字节不读
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest02 {
    public static void main(String[] args) {
        FileInputStream files = null;
        try {
            files = new FileInputStream("/home/liang/software/idea/test02.txt");
            //读一个字节
            //int readCount = files.read();
            //System.out.println("还剩下多少个字节没有读:" + files.available());
            files.skip(2);  跳过2个字节不读取
            //System.out.println(files.read());
            byte[] b = new byte[files.available()];  //这种方式不适合太大的文件,byte【】数组不能太大
            int readCount  = files.read(b);
            System.out.println(new String(b));    //cdefgh

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

    }
}
FileOutputStream类(文件字节输出流)(重要)
import java.io.IOException;

public class FileOutputStreamTest {
    public static void main(String[] args) {
       FileOutputStream fileOutput = null;
        try {
            //这种方式会将原文件内容清空,再重写写入
            //fileOutput = new FileOutputStream("/home/liang/software/idea/write.txt");//write.txt文件不存在的话,会自动新建
            fileOutput = new FileOutputStream("/home/liang/software/idea/write.txt", true);//直接在原文件后面写入(保留原文件内容)


            byte[] b = {101, 97, 98, 99, 100};
            fileOutput.write(b);  //byte数组中的元素全部写入
            fileOutput.write(b, 0, 2);//从数组下标0开始,只写入byte数组的前两个字节

            //写入字符串
            String s = "你在干什么?";
            byte[] bytes = s.getBytes();  //将字符串类型转化为byte类型
            fileOutput.write(bytes);



            fileOutput.flush(); //写完之后一定要刷新一下
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutput != null){
                try {
                    fileOutput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
文件复制

使用FileInputStream + FileOutputStream 完成文件的拷贝
拷贝的过程是一边读,一边写,什么文件都能拷贝


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


public class FileCopy {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("/home/liang/software/idea/test.txt");  //读文件
            fos = new FileOutputStream("/home/liang/桌面/copy.txt");           //写文件

            byte[] bytes = new byte[1024 * 1024];
            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 {
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}
FileReader 文件字符输入流(只能读取普通文本)
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderTest {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("/home/liang/software/idea/test.txt");//创建文件字符输入流
            char[] chars = new char[4];//一次读取4个字符
            int readCount = 0;
            while ((readCount = reader.read(chars)) != -1){
                System.out.print(new String(chars, 0, readCount)); //一次读取一个字符
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
FileWriter 文件字符输出流(只能输出普通文本)
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter out = null;
        try {
            out = new FileWriter("/home//liang/桌面/1.txt", true);
            char[] chars = {'我', '是', '谁'};
            out.write("\n");  //另起一行输入
            out.write(chars);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
BufferedReader:带有缓冲区的字符输入流

使用这个流不需要自定义char数组,或者说不需要自定义byte数。自带缓冲

package com.study.www.io;

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

public class BufferedReaderTest {
    public static void main(String[] args) {
        //顶一个流的构造方法中需要另一个流的时候,这个被传进来的流叫做节点流
        //外部负责包装的流叫做包装流,也叫处理流
        try {
           //BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
           //new FileInputStream("copyTest.txt")));                //可以用转换流将字节输入流转化为字符输入流
            FileReader fileReader = new FileReader("copyTest.txt");
            BufferedReader br = new BufferedReader(fileReader);

            String s1 = null;
            while ((s1 = br.readLine()) != null){           //br.readLine()方法不带换行符
                System.out.println(s1);
            }
            br.close();                 //对于包装流来说,只需要关闭最外层的流,里边的流会自动关闭
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

BufferedWriter同理

java.io.PrintStream 标准输出流
package com.study.www.io;


import java.io.FileOutputStream;
import java.io.PrintStream;

public class PrintStreamTest {
    public static void main(String[] args) throws Exception {
        // java.io.PrintStream  标准的字节输出流,默认输出到控制台.标准输出流不需要手动close()关闭
        PrintStream ps = System.out;
        ps.println("A");
        ps.println("B");
        ps.println("C");
        ps.println("D");

        //标准输出流不再指向控制台,指向log文件
        PrintStream printStream = new PrintStream(new FileOutputStream("log"));
        System.setOut(printStream);  //改变输出方向
        System.out.println("Hello World");
        System.out.println("Hello java");
        System.out.println("Hello C++");   //以上三句都将写入log文件,不再输出到控制台

    }
}
File类(java.io.File)

File对象代表什么?
文件和目录路径名的抽象表示形式

File类的常用方法:

package com.study.www.io;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileTest {
    public static void main(String[] args) throws Exception{
        File file = new File("/home/liang/桌面/file");
        System.out.println(file.exists());  //判断文件是否存在

        //if (!file.exists()){
        //    file.createNewFile();// 以文件形式新建
        //}

        //如果home/liang/桌面/file不存在,则以目录形式创建出来
        if (!file.exists()){
            file.mkdir();
        }

        File file2 = new File("/home/liang/桌面/A/B/C");
        if (!file2.exists()){
            file2.mkdirs(); //以多重目录新建
        }

        File file3 = new File("/home/liang/IDEA常用快捷键.txt");
        String parentPath = file3.getParent();  //获取file3的父路径
        System.out.println(parentPath);
        System.out.println(file3.getAbsolutePath()); //获取file3绝对路径

        System.out.println(file3.getName()); //获取文件的名字
        //file.delete(); //删除文件
        System.out.println(file3.isDirectory()); //判断是否是一个目录
        System.out.println(file3.isFile());   // 判断是否是一个文件

        long haoMiao = file3.lastModified();//获取文件最后一次修改时间,这个毫秒是从1970年到现在的总毫秒数
        Date time = new Date(haoMiao);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String s = sdf.format(time);
        System.out.println(s);

        System.out.println(file3.length()); //获取文件大小

    }
}
目录拷贝
import java.io.*;

public class CopyAllTest {
    public static void main(String[] args) {
        File srcFile = new File("/home/liang/桌面/学习资料");  //拷贝源
        File destFile = new File("/home/liang/下载/");            //拷贝目标
        copyDir(srcFile, destFile);

    }

    private static void copyDir(File srcFile, File destFile) {
        if (srcFile.isFile()){
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream(srcFile);
                String path = (destFile.getAbsolutePath().endsWith("/") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "/") + srcFile.getAbsolutePath().substring(15);

                out = new FileOutputStream(path);

                byte[] bytes = new byte[1024 * 1024];
                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 (in != null){
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null){
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }


            return;
        }
        //获取源下面的子目录
        File[] files = srcFile.listFiles();
        for (File file : files){
            if (file.isDirectory()){
                //System.out.println(file.getAbsolutePath()); //获取所有文件(包括目录和文件)的绝对路径
                String srcDir = file.getAbsolutePath();
                String destDir = (destFile.getAbsolutePath().endsWith("/") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "/") + srcDir.substring(15);
                File newFile = new File(destDir);
                if (!newFile.exists()){
                    newFile.mkdirs();
                }
            }
            copyDir(file, destFile);
        }
    }
}
序列化和反序列化(重要)
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

/**
 * *参与序列化和反序列化的对象,必须实现Serializable接口,Serializable接口只是一个标志接口
 */
public class ObjectOutputStreamTest {
    public static void main(String[] args) throws Exception{
        Student student = new Student(111, "Jay");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));//序列化

        oos.writeObject(student);
        oos.flush();  //刷新
        oos.close(); //关闭流
    }

}

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class ObjectInputStreamTest {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
        //开始反序列化,读取
        Object object = ois.readObject();  //反序列化回来的是一个学生对象
        System.out.println(object);
        ois.close();
    }

}
public class Student implements Serializable {
    //java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号
    //Java虚拟机会默认提供这个序列化版本号
    private static final long serialVersionUID = 1L;//手动写一个序列化版本号
    int no;
    String name;

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

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

多个对象的序列化和反序列化


import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception {
        List<Student> list = new ArrayList<>();
        list.add(new Student(222, "A"));
        list.add(new Student(223, "B"));
        list.add(new Student(224, "C"));
        list.add(new Student(225, "D"));

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("students"));
        objectOutputStream.writeObject(list);  //一次序列化多个对象(序列化一个集合,集合中有很多对象)

        objectOutputStream.flush();
        objectOutputStream.close();
    }
}

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;

public class ObjectInputStreamTest03 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("students"));
        List<Student> studentList = (List<Student>) objectInputStream.readObject();
        for (Student student : studentList){
            System.out.println(student);
        }
        objectInputStream.close();

    }
}

transient关键字表示游离的,不参加序列化,例如 private transient int no; 表示no不参加序列化操作

注意:建议将序列化版本号手动的写出来,不建议自动生成。因为当我们改动一个类的时候,这个类的默认版本序列号会发生改变,这时反序列化就会出错,自己手动写的版本化序列号不会发生改变,即使改动类,也不会影响反序列化

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值