Java I/O 流详解

标签: Java I/O流详解  FIleOutputStream  FileWriter  FileInputStream  FileReader

目录

字节流

1.FileOutputStream与FileInputStream

2.BufferedOutputStream与BufferedInputStream

3.ObjectOutputStream与ObjectOutputStream

4.DateInputStream与DateOutputStream

字符流

1.FiletWriter与FiletReader

2.BufferedWriter与BufferedReader

3.OutputStreamWriter与InputStreamReader


前言:

java.io包官方对其表述是:
Provides for system input and output through data streams, serialization and the file system

可以将Java I/O 大分为两类,字符流和字节流,字符流处理的单元为2个字节的Unicode字符,而字节流处理单元为1个字节,字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点。

I/O体系的基本结构如下(详细结构下文说明):

 

字节流

字节输出流由抽象类 OutputStream 及其实现类构成,具体结构如下:

字节输入流由抽象类 InputStream 及其实现类构成,具体结构如下:

 

1.FileOutputStream与FileInputStream

用于将数据以字节流的方式读写,FileOutputStream用于写原始字节流,例如图像数据。如要编写字符流,请考虑使用 FileWriter,同样可以使用FileReader代替 FileInputStream。

示例代码:

public class Main {
    public static void main(String[] args) {
        File file = new File("src/test.txt");
        /*
        字节流的写出
         */
        try (
                FileOutputStream fileOutputStream = new FileOutputStream(file, false)//将append设置为true 表示每次再文件后添加数据
        ) {
            String string = "你的名字";
            byte[] bytes = string.getBytes();
            fileOutputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*
        字节流的读入
         */
        try (
                FileInputStream fileInputStream = new FileInputStream(file)
        ) {
            /*int count = 0;//记录该字节流读取的字节数
            while (fileInputStream.read() != -1) {  //read操作类似于指针,逐次读取字节流中的字节,当无可读字节时,返回—1
                count++;
            }
            System.out.println(count);//此处输出值为12,再uft-8,汉字使用3个字节编码*/
            byte[] bytes = new byte[20];
            int i = fileInputStream.read(bytes);//将字节流中的数据逐次写入bytes中,并返回总共读取的字节数
            String string = new String(bytes);
            System.out.println(string);
            System.out.println(i);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果如下:

2.BufferedOutputStream与BufferedInputStream

缓冲字节流,再流中间提供一个缓冲区,提高数据读取和写入的速度

示例代码:

public class Main {
    public static void main(String[] args) {
        File file=new File("src/test.txt");
        StringBuilder stringBuilder=new StringBuilder();
        for (int i=0;i<100000;i++){
            stringBuilder.append("你难道没有见过江流奔涌的样子吗?\n");
        }
        String string=stringBuilder.toString();
        byte[] bytes=string.getBytes();
        /*
        缓冲输出字节流,它是对输出字节流的包装
         */
        try {
            if(!file.exists()) file.createNewFile();
            OutputStream outputStream=new FileOutputStream(file);
            long date1=System.currentTimeMillis();
            outputStream.write(bytes);
            outputStream.flush();
            long date2=System.currentTimeMillis();
            System.out.println("输出字节流使用时间:"+(date2-date1));
            BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(outputStream,1024);//设置缓冲区大小为1024个字节
            long date3=System.currentTimeMillis();
            bufferedOutputStream.write(bytes);
            bufferedOutputStream.flush();
            long date4=System.currentTimeMillis();
            System.out.println("缓冲输出字节流使用时间:"+(date4-date3));
            bufferedOutputStream.close();
            outputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        /*
        缓冲输入字节流,它是对输入字节流的包装
         */
        try{
            InputStream inputStream=new FileInputStream(file);
            long date1=System.currentTimeMillis();
            byte[] bytes1=new byte[10000000];
            inputStream.read(bytes1);
            long date2=System.currentTimeMillis();
            System.out.println("输入字节流使用时间:"+(date2-date1));
            String string1=new String(bytes1);
            BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream,1024);
            long date3=System.currentTimeMillis();
            byte[] bytes2=new byte[10000000];
            bufferedInputStream.read(bytes2);
            long date4=System.currentTimeMillis();
            System.out.println("缓冲输入字节流使用时间:"+(date4-date3));
            bufferedInputStream.close();
            inputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

运行结果:

可见,当数据量较大时,缓冲流可以提高读写效率

 

3.ObjectOutputStream与ObjectOutputStream

对象输出输入流,用于对象的序列化与反序列化,一个对象要想被序列化则必须实现Serializable ​​接口,如果要设置该对象中的某个属性是不可序列化的,则需使用 transient 关键字声明该属性是短暂的,对它的赋值将不会被序列化,序列化文件以xxx.ser后缀。

整个过程都是Java虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象

示例代码:

import java.io.*;

/**
 * @Author: QianQian
 * @CreateDate: 2019/11/30 17:17
 */
public class Main {
    public static void main(String[] args) {
        File file=new File("src/student1.ser");
        Student student=new Student("康康",19);
        student.setScore(100);
        System.out.println(student.toString());
        /*
        对象的序列化
         */
        try{
            if(!file.exists()) file.createNewFile();
            OutputStream outputStream=new FileOutputStream(file);
            ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(student);
            objectOutputStream.close();
            outputStream.close();
        }catch (IOException e){
            e.printStackTrace();
        }
        /*
        对象的反序列化
         */
        try{
            InputStream inputStream=new FileInputStream(file);
            ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
            Student student1= (Student) objectInputStream.readObject();
            System.out.println(student1.toString());
            objectInputStream.close();
            inputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

class Student implements Serializable{
    private String name;
    private int age;
    private transient int score;

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

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

    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 int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}


运行结果:

4.DateInputStream与DateOutputStream

数据输入输出流可以将Java的基本类型写入到文件或读取,与机器本身的环境无关

示例代码:

public class Main {
    public static void main(String[] args) {
        File file=new File("src/test.txt");
        try(
                FileOutputStream fileOutputStream=new FileOutputStream(file);
                DataOutputStream dataOutputStream=new DataOutputStream(fileOutputStream);
                ){
            dataOutputStream.writeInt(23);
            dataOutputStream.writeBoolean(true);
            dataOutputStream.writeFloat(3.2312f);
            dataOutputStream.writeUTF("hello world");
            dataOutputStream.flush();
        }catch (IOException e){
            e.printStackTrace();
        }
        try(
                FileInputStream fileInputStream=new FileInputStream(file);
                DataInputStream dataInputStream=new DataInputStream(fileInputStream);
                ){
            //要按照写入的顺序依次读取,否则会抛出异常
            System.out.println(dataInputStream.readInt());
            System.out.println(dataInputStream.readBoolean());
            System.out.println(dataInputStream.readFloat());
            System.out.println(dataInputStream.readUTF());
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

运行结果:

 

字符流

字符输出流是抽象类Writer及其实现类组成:

字符输入流是抽象类Reader及其实现类组成:

1.FiletWriter与FiletReader

此类方便读写字符类文件,以字符为单位进行读写,该类的构造函数默认字符编码和缓冲区大小都是可以接受的,如果要自己定义编码方式和缓冲区大小,则可通过OutputStreamWriter使用FileOutputStream构建一个FileWriter。

代码示例:

public class Main {
    public static void main(String[] args) {
        File file=new File("src/test.txt");
       try(
               FileWriter fileWriter=new FileWriter(file,false)
               ){
           String string="你难道没有见过江流奔涌的样子吗?";
           fileWriter.write(string);
       }catch (IOException e){
           e.printStackTrace();
       }
       try(
               FileReader fileReader=new FileReader(file)
               ){
           char[] chars=new char[100];
           int len=fileReader.read(chars);
           System.out.println(new String(chars,0,len));
       }catch (IOException e){
           e.printStackTrace();
       }
    }
}

2.BufferedWriter与BufferedReader

输入与输出的字符缓冲流,可以用以包装FileWriter和FileReader, 提高字符流的读写效率,提供了一个newLine()方法,它使用平台自己的系统属性line.separator定义的行分隔符概念。 并非所有平台都使用换行符('\ n')来终止行。 因此,调用此方法来终止每个输出行,因此优选直接写入换行符

示例代码:

public class Main {
    public static void main(String[] args) {
        File file=new File("src/test.txt");
       try(
               FileWriter fileWriter=new FileWriter(file,false);
               BufferedWriter bufferedWriter=new BufferedWriter(fileWriter,1024)//指定缓冲区大小
               ){
           String string="你难道没有见过江流奔涌的样子吗?";
           bufferedWriter.write(string);
           bufferedWriter.newLine();
           bufferedWriter.write(string);
       }catch (IOException e){
           e.printStackTrace();
       }
       try(
               FileReader fileReader=new FileReader(file);
               BufferedReader bufferedReader=new BufferedReader(fileReader)
               ){
           String string=null;
           while((string=bufferedReader.readLine())!=null){//判断读取的一行是否为空
               System.out.println(string);
           }
       }catch (IOException e){
           e.printStackTrace();
       }
    }
}

运行结果:

3.OutputStreamWriter与InputStreamReader

这两个个类是字节流转化为字符流的桥梁,在转换时可以指定字符流的编码形式,否则使用平台的默认字符集

代码示例:

public class Main {
    public static void main(String[] args) {
        File file=new File("src/test.txt");
        String string="你难道没有见过江流奔涌的样子吗?";
       try(
               FileOutputStream fileOutputStream=new FileOutputStream(file,false);
               OutputStreamWriter outputStreamWriter=new OutputStreamWriter(fileOutputStream,"gbk");//设置输出字符流的编码方式为GBK
               BufferedWriter bufferedWriter=new BufferedWriter(outputStreamWriter)
               ){
           bufferedWriter.write(string);
       }catch (IOException e){
           e.printStackTrace();
       }
       try(
               FileInputStream fileInputStream=new FileInputStream(file);
               InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"gbk");//设置输入字符流的编码方式也为GBK,否则读取乱码
               BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
               ){
           System.out.println(bufferedReader.readLine());
       }catch (IOException e){
           e.printStackTrace();
       }
    }
}

运行结果:(因为IDEA的默认编码方式为UTF-8,所以文件里的数据显示乱码,但如果同样使用GBK的方式读取数据,那么数据依然可以正常显示)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

版权声明:本文为qq_42013035原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42013035/article/details/103332956

智能推荐

【Network Security!】信息的扫描与嗅探

文章目录 确定扫描目标 确定目标主机IP地址 网站架构探测 确定扫描目标 确定目标主机IP地址 1.获取本机IP地址 2.获取网站地址信息 3.获取指定网站的IP地址 4.确定可能开放的端口和服务 Zenmap是一款非常流行的端口扫描软件(nmap的GUI界面化)。它是用Python语言编写而成的开源的图形界面,能够运行在不同操作系统平台上(Windows/Linux/Unix/Mac OS)) ...

太赞了!Linux 架构师总结的学习笔记,提供下载

  本文字数:1247,阅读时长大约:1分钟 导读:你想学习 Linux 吗? 最近很多小伙伴找我要一些 Linux 基础资料,于是我翻箱倒柜,把这份技术大牛总结的 Linux 归纳笔记找出来,免费共享给大家! 据说有小伙伴靠这份笔记顺利进入 BAT 哦,所以一定要好好学习这份资料! 资料介绍 这份资料非常全面且详细,从 Linux 常用命令到 Linux 常用操作,再到shell编程、...

【底层原理】高级开发必须懂的"字节对齐"

认识字节对齐之前,假定int(4Byte),char(1Byte),short(2Byte) 认识字节对齐 先看段代码:   sizeof(Data1)和sizeof(Data2)分别表示Data1和Data2内存占用字节数,输出结果不一样是因为编译时对Data1和Data2做了不同的字节对齐。Data1的对齐为4Byte,Data2的对齐是2Byte。   假定存储起始地址为...

爬lol全英雄皮肤

初学爬虫简单的爬取一下lol全英雄皮肤,自己写的,和网上CV的好不一样,觉得文章说得过去的记得留下足迹。 一 分析页面 1.英雄列表 首先在英雄页面找到hero_list.js;至于为什么是这个文件,看图: 观察该文件响应头,获取访问的url,打开新的窗口,访问该链接,能获取对应数据。(这边显示在一行很男查看,推荐一款好用的chrome插件JSONView,可以帮帮我们格式化json数据,可以在g...

解决VUE项目重复点击菜单报错:Avoided redundant navigation to current location: “/xxxxx“. 问题

描述: 报错见下图: 解决方法: 在router文件夹下添加下面一段代码...

猜你喜欢

Nginx 入门指南(十)

负载均衡模块 负载均衡模块用于从upstream指令定义的后端主机列表中选取一台主机。Nginx 先使用负载均衡模块找到一台主机,再使用 upstream 模块实现与这台主机的交互。为了方便介绍负载均衡模块,做到言之有物,以下选取 Nginx 内置的 ip hash 模块作为实际例子进行分析。 配置 要了解负载均衡模块的开发方法,首先需要了解负载均衡模块的使用方法。因为负载均衡模块与之前书中提到的...

文本和输入:复制和粘贴

Android提供了一个功能强大的基于剪贴板的复制和粘贴框架。 它支持简单和复杂的数据类型,包括文本字符串,复杂数据结构,文本和二进制流数据,甚至应用程序资产。 简单的文本数据直接存储在剪贴板中,而复杂数据则作为粘贴应用程序与内容提供者解析的参考进行存储。 复制和粘贴在应用程序中以及在实现框架的应用程序之间工作。 由于框架的一部分使用内容提供者,因此本主题假定您熟悉Android内容提供程序API...

[unity]代码批量修改图片、文本文件的AssetBundle的Name

  当项目工程内有大量文件,需要打包成AssetBundle的时候,一个一个打包是一件非常麻烦的事情。 批量修改AssetBundle的Name并对AssetBundle包 进行批量 打包。   批量修改项目工程文件的图片、文本文件的AssetBundle   1.批量建立AssetBundle 1.1修改文件的.meta文件的文本内容 来自参考资料1   ...

[Python] 用K-means算法进行客户分群

目录 一、背景 1.项目描述 2.数据描述 二、相关模块 三、数据可视化 1.数据读取 2.数据可视化 2.1 平行坐标图 2.2 年龄/年收入/消费分数的分布 2.3 年龄/年收入/消费分数的柱状图 2.4 不同性别用户占比 2.5 两两特征之间的关系 2.6 两两特征之间的分布 四、K-means聚类分析 0.手肘法简介 1.基于年龄和消费分数的聚类 2.基于年收入和消费分数的聚类 3.基于年...

CUDA9.0+win10+Visual Studio2017版本配置安装教程

CUDA9.0+win10+Visual Studio2017版本配置安装教程 不幸掉入深度学习的深渊,从此以后无法自拔,哈哈,虽然电脑属于平民配置,但因为有师姐顶配DELL工作站的操练,可以肆无忌惮的配置安装自己想要的东西,一路踩坑,一路爬,一把辛酸泪。安装的时候特别要注意VS和CUDA版本的兼容问题,否则要么卸载重装,要么一系列的路径操作会让你绝望。 如果电脑配置够新,不妨试试安装最新版本的C...