IO流

IO流

I:input O:output

通过IO可以完成硬盘文件的读和写

分类

  1. 按流的方向分类

输入流:侧重于读,数据从数据源读入程序。(从磁盘中的文件读到程序里)
输出流:侧重于写,数据从程序写出到目的地。(从程序写到磁盘中的文件里)

  1. 按处理的数据单元分类

字节流:以 字节(1Byte=8bit) 为单位进行读取或者写出数据。
字符流:以 字符为单位进行读取或者写出数据。

这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件 等…

字节流:

InputStream:用于从输入源读取字节数据的抽象类。
FileInputStream:从文件中读取字节数据的类。
ByteArrayInputStream:从字节数组中读取字节数据的类。
BufferedInputStream:提供缓冲功能的字节输入流类。
DataInputStream:读取基本数据类型的字节输入流类。

字节流

FileInputStream(从磁盘中的文件写入程序里)

以字节流进行读取文件的类是FileInputStream,它是InputStream(字节输入流)抽象类的子类。

public static void main(String[] args) throws IOException {
	//1. 连接数据:FileInputStream 直接与数据源连接,因此属于节点流
	FileInputStream fis = new FileInputStream("D:\\1.txt");
	//2. 循环逐个读取字节
	int temp=0;
	StringBuilder sb = new StringBuilder();
	while ((temp=fis.read())!=-1)//如果文件中的字节读取完毕,则返回-1,否则返回该字节数值(0-255)
       	sb.append((char)temp);
	System.out.println(sb.toString());
	//3. 关闭流
	fis.close();
}

(一个字节一个字节进行读取)

FileOutputStream(从程序写入磁盘中的文件里)

以字节流进行写出数据的类是FileOutputStream,它是OutputStream(字节输出流)抽象类的子类。

//代码2
 public static void main(String[] args) throws IOException {
        //1. 连接数据源:直接与数据源连接,因此属于节点流
        FileInputStream fis_img = new FileInputStream("D:/1.jpg");
        //2. 连接目的地:直接与目的地连接,因此属于节点流
        FileOutputStream fos_img = new FileOutputStream("D:/2.jpg");
        //3. 逐个读取字节,并将字节逐个写出
        int temp=0;
        while ((temp=fis_img.read())!=-1)
        {
            fos_img.write(temp);
        }
        //4. 关闭流
        fos_img.flush();
        fis_img.close();
        fos_img.close();
    }

设置缓冲区 byte[] buffer = new byte[1024];

上面这俩都是一个字节一个字节 读取或者写出数据的,如果一次读取多个字节,或者将多个字节写出,那肯定比上面这个效率高。

所以要有一个缓冲区,这个缓冲区就是每次将多个字节装进缓冲区,然后一次性从缓冲区里写出多个字节。

//代码3
 public static void main(String[] args) throws IOException {
        FileInputStream fis_img = new FileInputStream("D:/1.jpg");
        FileOutputStream fos_img = new FileOutputStream("D:/2.jpg");
        int temp=0;
        byte[] buffer = new byte[1024];//设置缓冲区,缓冲区大小去2^n合适
        while ((temp=fis_img.read(buffer))!=-1)//每次读取多个字节存入缓冲区
        {
            fos_img.write(buffer,0,temp);//每次将缓冲区中的多个字节写出
        }
        fos_img.flush();
        fis_img.close();
        fos_img.close();
    }

自适应缓冲区大小available

上面这个是手动设置缓冲区大小,对于较小的文件来说,可以一次性搞定,就没必要分多次,因此将缓冲区的大小设置为文件内容的实际大小即可。

FileInputStream对象提供了一个估算文件字节个数的方法available,通过该方法获取文件字节个数。

缓冲区的空间来自内存,缓冲区越大,那么占用的空间越大,因此,一次性读写数据只适用于较小的数据。

//代码4
 public static void main(String[] args) throws IOException {
        FileInputStream fis_img = new FileInputStream("D:/1.jpg");
        FileOutputStream fos_img = new FileOutputStream("D:/2.jpg");
        int temp=0;
        //fis_img.available()直接获取数据的长度,类似一次搬完,不用分批,
        //但这比较占内存,因此适用于小文件,比如一个人只能扛100斤苹果,你让他一次扛200斤,那就累趴了。
        byte[] buffer = new byte[fis_img.available()];
        fis_img.read(buffer);
        fos_img.write(buffer);
        fos_img.flush();

        fis_img.close();
        fos_img.close();
    }

BufferedInputStream和BufferedOutputStream

根据通过缓冲区提高IO效率的思想,Java提供了BufferedInputStream和BufferedOutputStream两个处理流,来实现通过缓冲区读写文件。

//代码5
public static void main(String[] args) {
        FileInputStream fis=null;//节点流
        FileOutputStream fos=null;//节点流

        BufferedInputStream bis=null;//处理流:缓冲流,实现原理就是通过缓冲区提高读效率
        BufferedOutputStream bos=null;//处理流:缓冲流,实现原理就是通过缓冲区提高写效率
        try {
            fis = new FileInputStream("D:/1.jpg");
            bis=new BufferedInputStream(fis);
            fos=new FileOutputStream("D:/2.jpg");
            bos=new BufferedOutputStream(fos);

            //默认缓冲区大小:DEFAULT_BUFFER_SIZE = 8192;
            int temp=0;
            while ((temp=bis.read())!=-1)
            {
                bos.write(temp);
            }
            bos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //流的关闭顺序:后开的先关
            try {
                if (bis!=null)
                    bis.close();
               if (fis!=null)
                   fis.close();
               if (bos!=null)
                   bos.close();
               if (fos!=null)
                   fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

字节数组流

ByteArrayInputStream(从磁盘中的文件写入程序里)

将内存中的字节数组对象作为数据源

//代码6
 public static void main(String[] args) throws IOException {
        byte[] source="mekeater".getBytes();
        //内存中的字节数组对象作为数据源
        ByteArrayInputStream bis = new ByteArrayInputStream(source);
        int temp=0;
        StringBuilder sb = new StringBuilder();
        while ((temp=bis.read())!=-1)
        {
            sb.append((char) temp);
        }
        System.out.println(sb.toString());

        bis.close();
    }

ByteArrayOutputStream(从程序写入磁盘中的文件里)

将读取的数据写入到字节数组输出流中

//代码7
 public static void main(String[] args) throws IOException {
        //将流中的数据写入到字节数组中
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bos.write('m');
        bos.write('e');
        bos.write('k');
        bos.write('e');
        bos.write('a');
        bos.write('t');
        bos.write('e');
        bos.write('r');
        byte[] bytes = bos.toByteArray();
        for (byte b : bytes) {
            System.out.print((char) b);
        }
        bos.close();
    }

随机访问流(可以根据指定位置,开始查找字节位置)

RandomAccessFile可以指定开始查找的字节位置

//代码8
public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("D:/2.txt", "rw");
        for (int i = 0; i < 10; i++) {
            raf.writeInt(i);
        }
        raf.seek(4);//seek指定开始查找的位置从第4个字节开始,一个int整数占4个字节,因此从第二个位置查找
        System.out.println(raf.readInt());
        //隔一个位置查找一个
        for (int i = 0; i < 10; i+=2) {
            raf.seek(i*4);
            System.out.printf(raf.readInt()+"\t");
        }
        System.out.println();
        //seek指定位置,重新写入该位置的数据,替换原有数据
        raf.seek(4);//指定第4个字节位置,即第二个整数
        raf.writeInt(66);

        raf.seek(0);//重新定位查找的起始位置
        for (int i = 0; i < 10; i++) {
            System.out.print(raf.readInt()+"\t");
        }
    }

数据流(实现基本类型数据序列化到文件)

DataOutputStream将基本数据类型的数据以字节流形式输出到本地文件(类似序列化,但是它只能对基本数据类型进行操作,不能对java自定义对象进行操作)

//代码9
public static void main(String[] args) throws IOException {
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("D:/data")));
        //写出基本数据类型数据文件中
        dos.writeChar('m');
        dos.writeBoolean(false);
        dos.writeDouble(Math.random());
        dos.writeInt(66);
        dos.writeUTF("Mekeater");
        dos.flush();

        dos.close();
    }

DataInputStream从文件中读取存储的基本数据类型的数据

//代码10
public static void main(String[] args) throws IOException {
        DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("D:/data")));
        //注意读取数据顺序要去写入数据一致
        System.out.println(dis.readChar());
        System.out.println(dis.readBoolean());
        System.out.println(dis.readDouble());
        System.out.println(dis.readInt());
        System.out.println(dis.readUTF());

        dis.close();
    }

对象流(实现基本类型数据及自定义对象数据序列化到文件)

Java IO中提供了ObjectOutputStream类实现对象的序列化。

反序列化:将二进制文件恢复为对象数据的过程。Java IO中提供了ObjecInputStream类实现对象的序列化。

通过对象序列化可以实现对象的持久化及网络通信功能。

//代码11
 public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("D:/data1")));
        //系列化基本数据类型
        oos.writeChar('m');
        oos.writeBoolean(false);
        oos.writeDouble(Math.random());
        oos.writeInt(66);
        oos.writeUTF("Mekeater");
        序列化自定义对象(对象能够序列化,必须实现Serializable标记接口)
        User user = new User(18, "mekeater", true);
        oos.writeObject(user);
        
        oos.flush();
        oos.close();
    }
 
 //实现序列化接口的对象
 public class User implements Serializable {
    private int age;
    private String name;
    private boolean isMan;

    public User() {
    }

    public User(int age, String name, boolean isMan) {
        this.age = age;
        this.name = name;
        this.isMan = isMan;
    }
    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public boolean isMan() {
        return isMan;
    }

    public void setMan(boolean man) {
        isMan = man;
    }

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

对上述所序列化的二进制文件进行反序列化,恢复对象数据的示例代码如下

//代码12
 public static void main(String[] args) throws IOException {
        ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("D:/data1")));
        //反序列化数据,读取必须和写入顺序一致
        System.out.println(ois.readChar());
        System.out.println(ois.readBoolean());
        System.out.println(ois.readDouble());
        System.out.println(ois.readInt());
        System.out.println(ois.readUTF());
        
        User user = (User)ois.readObject();
        System.out.println(user.getAge());
        System.out.println(user.getName());
        System.out.println(user.isMan());
        ois.close();
    }

字符流

文件字符读(输入)写(输出)流

FileWriter类是Writer抽象类的子类,它实现将数据以字符为单位写入文件。

//代码13
 public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("D:/2.txt");//如果文件存在,则默认覆盖
        //如需追加需要设置参数
        //FileWriter fw = new FileWriter("D:/2.txt",true);
        fw.write("hello IO Stream\r\n");//换行
        fw.write("Mekeater come on!");
        fw.flush();
        fw.close();
    }

FileReader类是Reader抽象类的子类,它实现将以字符为单位读取文件内容

//代码14
public static void main(String[] args) throws IOException {
        FileReader frd = new FileReader("D:/2.txt");
        int temp=0;
        while ((temp=frd.read())!=-1)
        {
            System.out.println((char) temp);
        }
        frd.close();
    }

基于缓冲区的文件字符读写流(高效)

与上述基于缓冲区的文件字节读写流思想一致。

文件字符流通常是逐个字符读写内容,效率较低,我们可以通过开辟一块空间(数组)每次将读写的数据装满该空间,达到一次读取或者写出多个字符的效果,进而提高读写效率。

逐个字符读写内容,实现文件拷贝功能

//代码15
 //通过字符流实现(但这是一个字符一个字符的读写,效率低)
    public static void CopyFile(String source, String target) throws IOException {
        FileReader fr = new FileReader(source);
        FileWriter fw = new FileWriter(target);
        int temp=0;
        while ((temp=fr.read())!=-1)
        {
            fw.write(temp);
        }
        fw.flush();

        fr.close();
        fw.close();
    }

通过缓冲机制

//代码16
 //通过字符流实现(通过缓冲区提高读写效率)
    public static void CopyFileBuffer(String source, String target) throws IOException {
        FileReader fr = new FileReader(source);
        FileWriter fw = new FileWriter(target);
        int temp=0;
        char[] buffer = new char[1024];//这个长度只能自己指定,不能像字节流可以获取大概的总长度
        while ((temp=fr.read(buffer))!=-1)
        {
            fw.write(buffer,0,temp);
        }
        fw.flush();

        fr.close();
        fw.close();
    }

BufferedReader类及BufferedWriter类两个处理流,实现缓冲区的思想

//代码17
public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("D:/2.txt");//节点流
        BufferedWriter bw= new BufferedWriter(fw);//缓冲处理流
        bw.write("BufferedWrite context");
        bw.newLine();
        bw.write("I am Mekeater");
        bw.flush();

        bw.close();
        fw.close();
    }
    
public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("D:/1.txt");//节点流
        BufferedReader br = new BufferedReader(fr);//处理流
        String temp="";
        while ((temp=br.readLine())!=null)
            System.out.println(temp);
        br.close();
        fr.close();
    }

转换流

有时候我们能够方便的获取字节流对象,但是我们需要将字节流转为字符流

如我们可以通过System.in获取用户输入的键盘数据,System.out向控制台输出用户输入的数据,但是System.in和System.out返回的都是字节流对象,而我们需要将字节流转为字符流进行操作更为方便,Java IO提供了InputStreamReader类实现输入字节流转为读取字符流,OutputStreamWriter类实现输出字节流转为写出字符流

//代码18
 public static void main(String[] args) throws IOException {
        //InputStreamReader将字节输入流转为字符输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //OutputStreamWriter将字节输出流转为字符输出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        String line="";
        while (true)
        {
            bw.write("请输入:");
            bw.flush();
            line=br.readLine();
            if (line.equals("exit"))
                break;
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
    }

File类

操作文件常用方法

    public static void main(String[] args) throws IOException {
        File file = new File("D:/2.txt");//连接文件
        System.out.println(file.createNewFile());//创建文件(若存在,则默认覆盖,不存在,则创建)
        System.out.println(file.exists());//判断文件是否存在
        System.out.println(file.getName());//获取文件名
        System.out.println(file.getAbsolutePath());//获取文件的绝对路径
        System.out.println(file.isHidden());//判断文件是否为隐藏文件
        System.out.println(file.delete());//删除文件
    }

操作目录常用方法

public static void main(String[] args) throws IOException {
        File file = new File("D:/a");//连接目录
        System.out.println(file.mkdir());//创建单级目录
        File file1 = new File("D:/a/b/c");
        System.out.println(file1.mkdirs());//创建多级目录
        System.out.println(file.isFile());//判断是否为文件
        System.out.println(file.isDirectory());//判断是否为目录
        System.out.println(file1.getParent());//获取目录的上一级目录路径

        File file2 = new File("D:/");
        String[] list = file2.list();//获取目录下的所有文件名
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("=====================");
        File[] files = file2.listFiles();//获取目录下的所有文件对应的File类
        for (File file3 : files) {
            System.out.println(file3.getAbsolutePath());//获取目录下的所有文件的绝对路径
        }
    }

原文连接:https://blog.csdn.net/qq_34720818/article/details/125840972

posted @   大菠萝zZ  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示