Java难点重构-IO(下)

简介: 在java 中有输入,输出两种 IO 流,每种输入,输出又分为字节流和字符流两大类。字节又是什么呢,每个字节(byte)右8bit 组成,每种数据类型又几个字节组成。

流的概念模型


Java 的IO流共设计 40 多个类,这些类看上去复杂,但实际上非常规则,而且彼此之间存在非常紧密的联系。它们都是从如下4 个抽象基类派生的。


  • InputStream/Reader:所有输入流的基类,前者是字节输出流,后者是字符输出流
  • OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流。

InputStream/Reader

对于InPutStream 和Reader 而言,它们把输入设备抽象成一个水管,这个水管里的每个水滴一次排列,如图



字节流和字符流的处理方式其实非常相似,只是它们处理的输入/输出单位不同而言。**输入流使用隐式的记录指针来表示 **当前正准备从哪个“水滴”开始读取,每当程序从 InputStream或 Reader 里取出一个或多个 “水滴” 后,记录指针自动向后移动;除此之外,InputSteam 和 Reader里都提供了一些方法来控制记录指针的移动。

OutputStream/Writer

对于OutputStream 和 Writer而言,它们同样把输出设备抽象成一个水管,只是这个水管里没有任何水滴。



当执行输出时,程序相当于依次把 “水滴” 放入到输出流的水管中,输出流同样采用隐式的记录指正来标识当前属地即将放入的位置,每当程序向 OutPutStream 或 Writer 里输出一个或多个水滴后,记录指针自动向后移动。


以上就是Java IO流的基本概念模型,除此之外,Java 的处理流模型则体现了 Java 输入/输出流设计的灵活性。处理流的功能主要体现在以下方面:


  • 性能的提高:主要以增加缓冲的方式来提高输入/输出的效率。
  • 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入/输出大批量的内容,而不是输入/输出一个或多个水滴


处理流可以 嫁接 在任何已存在的流的基础之上,这就允许 java 应用程序采用相同的代码,透明的方式来访问不同的输入,输出设备的数据流。



通过使用处理流,Java 程序无须理会 输入/输出 节点是磁盘,网络还是其他的输入/输出设备,程序只要讲这些节点包装成处理流,就可以使用相同的输入/输出代码来读写不同的输入/输出设备的数据。

InputStream,Reader

InputStream和Reader 都是将输入数据抽象成一条水管,所以程序既可以通过 read() 方法每次读取一个 水滴,也可以通过 read(char[] cbuf)或rea(byte[] b)方法来读取多个 “水滴”。当使用数组作为 read() 方法的参数时,可以理解为使用一个 “竹筒”到水管去取水,而read(char[] cbuf)方法中的数组就相当于一个 “竹筒” ,程序每次调用输入流的 read(char[] cbuf)或read(byte[] b)方法,就相当于用 “竹筒”从输入流中取出一筒 ”水滴“,程序得到 “竹筒” 里的 “水滴” 后,转换成相应的数据即可;程序多次重复这个取水过程,直到 read(char[] cbuf)或read(byte[] b)方法返回-1,表明到了输入流的结束点。内部每次又使用指针移动取水的下标。


InputStream是所有输入字节流的父类,是一个抽象类,主要包含三个方法

 //读取一个字节并以整数的形式返回(0~255),如果返回-1已到输入流的末尾。 
int read() ; 
//读取一系列字节并存储到一个数组buffer,返回实际读取的字节数,如果读取前已到输入流的末尾返回-1。 
int read(byte[] buffer) ; 
//读取length个字节并存储到一个字节数组buffer,从off位置开始存,最多len, 返回实际读取的字节数,如果读取前以到输入流的末尾返回-1。 
int read(byte[] buffer, int off, int len) ;

Demo

public class Test {
    public static void main(String[] args) throws IOException {
        try{
            //创建字节输入流
            FileInputStream fis=new FileInputStream("E:\\Android\\Mvp_Test\\app\\src\\main\\java\\com\\example\\pettepr\\mvp_test\\aaa.txt");
            //创建一个长度为32的字节数组
            byte[] bbuf=new byte[32];
            //用于保存实际读取的字节数
            int hasRead=0;
            while ((hasRead=fis.read(bbuf))>0){
                System.out.println(new String(bbuf,0,hasRead));
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

解决中文乱码问题

//创建字节输入流
FileInputStream fis = new FileInputStream("E:\\Android\\Mvp_Test\\app\\src\\main\\java\\com\\example\\pettepr\\mvp_test\\aaa.txt");
InputStreamReader input = new InputStreamReader(fis, "GBK");
BufferedReader bbuf = new BufferedReader(input);
String next;
while ((next=bbuf.readLine())!=null) {
    System.out.println(next);
}

InputStream与Reader最大不同,一个是操作字节,一个是操作字符


除了上面的方法之外,InputStream和Reader还支持如下方法来移动流中的指针位置:

//在此输入流中标记当前的位置
//readlimit - 在标记位置失效前可以读取字节的最大限制。
void mark(int readlimit)
// 测试此输入流是否支持 mark 方法
boolean markSupported()
// 跳过和丢弃此输入流中数据的 n 个字节/字符
long skip(long n)
//将此流重新定位到最后一次对此输入流调用 mark 方法时的位置
void reset()
OutputStream 和 Writer

OutputStream 是所有的输出字节流的父类,它是一个抽象类,主要包含如下4个方法:

//向输出流中写入一个字节数据,该字节数据为参数b的低8位。 
void write(int b) ; 
//将一个字节类型的数组中的数据写入输出流。 
void write(byte[] b); 
//将一个字节类型的数组中的从指定位置(off)开始的,len个字节写入到输出流。 
void write(byte[] b, int off, int len); 
//将输出流中缓冲的数据全部写出到目的地。 
void flush();

Writer 是所有的输出字符流的父类,它是一个抽象类,主要包含如下六个方法:

//向输出流中写入一个字符数据,该字节数据为参数b的低16位。 
void write(int c); 
//将一个字符类型的数组中的数据写入输出流, 
void write(char[] cbuf) 
//将一个字符类型的数组中的从指定位置(offset)开始的,length个字符写入到输出流。 
void write(char[] cbuf, int offset, int length); 
//将一个字符串中的字符写入到输出流。 
void write(String string); 
//将一个字符串从offset开始的length个字符写入到输出流。 
void write(String string, int offset, int length); 
//将输出流中缓冲的数据全部写出到目的地。 
void flush()

可以看出,Writer比OutputStream多出两个方法,主要是支持写入字符和字符串类型的数据。


Demo

public class Test {
    public static void main(String[] args) throws IOException {
        try{
            //创建字节输入流
            FileInputStream fis=new FileInputStream("E:\\Android\\Mvp_Test\\app\\src\\main\\java\\com\\example\\pettepr\\mvp_test\\Test.java");
            //创建字节输出流
            FileOutputStream fos=new FileOutputStream("E:\\Android\\Mvp_Test\\app\\src\\main\\java\\com\\example\\pettepr\\mvp_test\\aaa.txt",true);  //true指将内容添加到原内容后面
             byte[] buuf=new byte[32];
            int hashRead=0;
            //循环从输入流中取出数据
            while((hashRead=fis.read(buuf))>0){
                fos.write(buuf,0,hashRead);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

使用Java的IO流执行输出时,不要忘记关闭输出流,关闭输出流除了可以保证流的物理资源被回收之外,还能将输出流缓冲区的数据flush到物理节点里(因为在执行close()方法之前,自动执行输出流的flush()方法)

处理流

处理流可以隐藏底层设备上节点流的差异,并对外提供更加方便的输入/输出方法,让程序员只需关心高级流的操作。


使用处理流时的典型思路是,使用处理流老包装节点流,程序通过处理流来执行输入输出功能,让节点流与底层的 I/O设备,文件交互。

它的优势为以下两点:


  1. 对开发人员来说,使用处理流进行输入、输出操作更简单
  2. 使用处理流效率更高
public class Test {
    public static void main(String[] args){
        try{
            FileOutputStream fos=new FileOutputStream("E:\\Android\\Mvp_Test\\app\\src\\main\\java\\com\\example\\pettepr\\mvp_test\\aaa.txt");
            PrintStream ps=new PrintStream(fos);
             //使用PrintStream执行输出
            ps.println("Petterp");
        }catch (Exception e){
        }
    }
}

转换流

转换流用于实现将字节流转换成字符流。


IntputStreamReader 将字节输入流转换成字符输入流,OutputStreamWriter 将字节输出流转换成字符输出流。

为什么没有把字符流转成字节流的呢?

字节流比字符流的应用范围更广,但字符流比字节流操作方面。如果有一个流已经是字符流了,也就是说,是一个用起来更方便的流,为什么要转换成字节流呢?反之,如果现在有一个字节流,但可以确定这个字节流的内容都是文本内容,那么把他转为字符流来处理就会更方便一些,所以 java只提供了 将字节流转换成字符流的转换。

public class Test {
    public static void main(String[] args) throws IOException {
        //创建字节输入流
        FileInputStream fis = new FileInputStream("E:\\Android\\Mvp_Test\\app\\src\\main\\java\\com\\example\\pettepr\\mvp_test\\aaa.txt");
        InputStreamReader input = new InputStreamReader(fis, "GBK");
        //将普通的 Reader包装成 BufferedReader
        BufferedReader bbuf = new BufferedReader(input);
        String next;
        //readLine() 每次读入一行
        while ((next=bbuf.readLine())!=null) {
            System.out.println(next);
        }
    }
}


目录
相关文章
|
7月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
308 1
|
8月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
|
9月前
|
Java 测试技术 API
Java IO流(二):文件操作与NIO入门
本文详解Java NIO与传统IO的区别与优势,涵盖Path、Files类、Channel、Buffer、Selector等核心概念,深入讲解文件操作、目录遍历、NIO实战及性能优化技巧,适合处理大文件与高并发场景,助力高效IO编程与面试准备。
|
9月前
|
SQL Java 数据库连接
Java IO流(一):字节流与字符流基础
本文全面解析Java IO流,涵盖字节流、字符流及其使用场景,帮助开发者理解IO流分类与用途,掌握文件读写、编码转换、异常处理等核心技术,通过实战案例提升IO编程能力。
|
10月前
|
存储 Java Linux
操作系统层面视角下 Java IO 的演进路径及核心技术变革解析
本文从操作系统层面深入解析Java IO的演进历程,涵盖BIO、NIO、多路复用器及Netty等核心技术。分析各阶段IO模型的原理、优缺点及系统调用机制,探讨Java如何通过底层优化提升并发性能与数据处理效率,全面呈现IO技术的变革路径与发展趋势。
224 3
|
10月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
310 0
|
10月前
|
存储 Java 程序员
Java 基础知识点全面梳理包含核心要点及难点解析 Java 基础知识点
本文档系统梳理了Java基础知识点,涵盖核心特性、语法基础、面向对象编程、数组字符串、集合框架、异常处理及应用实例,帮助初学者全面掌握Java入门知识,提升编程实践能力。附示例代码下载链接。
405 0
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
628 23
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
529 0
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
334 10

热门文章

最新文章