java按照io流向基类_Java IO详解

1 Java IO流的概念,分类

1.1 Java IO流的概念

java的IO是实现输入和输出的基础,可以方便的实现数据的输入和输出操作。在java中把不同的输入/输出源(键盘,文件,网络连接等)抽象表述为“流”(stream)。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

1.2.1按照流的流向分,可以分为输入流和输出流。

输入流:只能从中读入数据,而不能向其写出数据。

输出流:只能向其写出数据,而不能向其读入数据。

注:为什么叫写出和读入,这里涉及到一个方向问题,因为划分输入/输出流时是从程序运行所在的内存的角度来考虑的;将内存中的数据写出到硬盘中的文件,或者是将硬盘中文件的信息读入到内存。

注:java的输入流主要是InputStream和Reader作为基类,而输出流则是主要由OutputStream和Writer作为基类。它们都是一些抽象基类,无法直接创建实例。

1.2.2 按照操作单元划分,可以划分为字节流和字符流。

字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

字节流和字符流的区别:

读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

字节流:一次读入或读出是8位二进制。

字符流:一次读入或读出是16位二进制。

1.2.3 按照流的角色划分为节点流和处理流。

节点流(低级流):直接与数据源相连,读入或写出。直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。

处理流(高级流)和节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。如BufferedReader处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

1.3.1 流的原理浅析:

java IO流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java IO流的40多个类都是从如下4个抽象类基类中派生出来的。

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

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

对于InputStream和Reader而言,它们把输入设备抽象成为一个”水管“,这个水管的每个“水滴”依次排列。

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

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

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

注:Java的处理流模型则体现了Java输入和输出流设计的灵活性。处理流的功能主要体现在以下两个方面。

性能的提高:主要以增加缓冲的方式来提供输入和输出的效率。

操作的便捷:处理流可能提供了一系列便捷的方法来一次输入和输出大批量的内容,而不是输入/输出一个或者多个“水滴”。

1.3.2 java输入/输出流体系中常用的流的分类表

分类

字节输入流

字节输出流

字符输入流

字符输出流

抽象基类

InputStream

OutputStream

Reader

Writer

访问文件

FileInputStream

FileOutputStream

FileReader

FileWriter

访问数组

ByteArrayInputStream

ByteArrayOutputStream

CharArrayReader

CharArrayWriter

访问管道

PipedInputStream

PipedOutputStream

PipedReader

PipedWriter

访问字符串

StringReader

StringWriter

缓冲流

BufferedInputStream

BufferedOutputStream

BufferedReader

BufferedWriter

转换流

InputStreamReader

OutputStreamWriter

对象流

ObjectInputStream

ObjectInputStream

抽象基类

FilterInputStream

FilterOutputStream

FilterReader

FilterWriter

打印流

PrintStream

PrintWriter

推回输入流

PushbackInputStream

PushbackReader

特殊流

DataInputStream

DataOutputStreamn

注:表中粗体字所标出的类代表节点流,必须直接与指定的物理节点关联:斜体字标出的类代表抽象基类,无法直接创建实例。

2.1 IO体系的基类(InputStream/Reader,OutputStream/Writer)

字节流和字符流的操作方式基本一致,只是操作的数据单元不同——字节流的操作单元是字节,字符流的操作单元是字符。

InputStream和Reader是所有输入流的抽象基类,本身并不能创建实例来执行输入,但它们将成为所有输入流的模板,所以它们的方法是所有输入流都可使用的方法。

在InputStream里面包含如下3个方法。

int read(); 从输入流中读取单个字节(相当于从水管中取出一滴水),返回所读取的字节数据(字节数据可直接转换为int类型)。

int read(byte[] b)从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。

int read(byte[] b,int off,int len); 从输入流中最多读取len个字节的数据,并将其存储在数组b中,放入数组b中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。

在Reader中包含如下3个方法。

int read(); 从输入流中读取单个字符(相当于从水管中取出一滴水),返回所读取的字符数据(字节数据可直接转换为int类型)。

int read(char[] b)从输入流中最多读取b.length个字符的数据,并将其存储在字节数组b中,返回实际读取的字符数。

int read(char[] b,int off,int len); 从输入流中最多读取len个字符的数据,并将其存储在数组b中,放入数组b中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。

InputStream和Reader提供的一些移动指针的方法:

void mark(int readAheadLimit); 在记录指针当前位置记录一个标记(mark)。

boolean markSupported(); 判断此输入流是否支持mark()操作,即是否支持记录标记。

void reset(); 将此流的记录指针重新定位到上一次记录标记(mark)的位置。

long skip(long n); 记录指针向前移动n个字节/字符。

OutputStream和Writer的用法也非常相似,两个流都提供了如下三个方法:

void write(int c); 将指定的字节/字符输出到输出流中,其中c即可以代表字节,也可以代表字符。

void write(byte[]/char[] buf); 将字节数组/字符数组中的数据输出到指定输出流中。

void write(byte[]/char[] buf, int off,int len ); 将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中。

因为字符流直接以字符作为操作单位,所以Writer可以用字符串来代替字符数组,即以String对象作为参数。Writer里面还包含如下两个方法。

void write(String str); 将str字符串里包含的字符输出到指定输出流中。

void write (String str, int off, int len); 将str字符串里面从off位置开始,长度为len的字符输出到指定输出流中。

2.2 IO体系的基类文件流的使用(FileInputStream/FileReader ,FileOutputStream/FileWriter)

使用FileInputStream读取文件:

@Test

public void fileInputStreamTest() throws IOException {

FileInputStream fis = null;

try {

// 创建字节输入流

fis = new FileInputStream(

"D:/test/test.txt");

// 创建一个长度为1024的竹筒

byte[] b = new byte[1024];

// 用于保存的实际字节数

int hasRead = 0;

// 使用循环来重复取水的过程

while ((hasRead = fis.read(b)) > 0) {

// 取出竹筒中的水滴(字节),将字节数组转换成字符串进行输出, 后面的gbk是为了处理中文乱码问题

System.out.print(new String(b, 0, hasRead, "gbk"));

}

} catch (IOException e) {

e.printStackTrace();

} finally {

fis.close();

}

}

注:上面程序最后使用了fis.close()来关闭该文件的输入流,与JDBC编程一样,程序里面打开的文件IO资源不属于内存的资源,垃圾回收机制无法回收该资源,所以应该显示的关闭打开的IO资源。Java 7改写了所有的IO资源类,它们都实现了AntoCloseable接口,因此都可以通过自动关闭资源的try语句来关闭这些IO流。

使用FileReader读取文件:

@Test

public void fileReaderTest() throws IOException{

FileReader fis = null;

try {

// 创建字节输入流

fis = new FileReader("D:/test/test.txt");

// 创建一个长度为1024的竹筒

char[] b = new char[1024];

// 用于保存的实际字节数

int hasRead = 0;

// 使用循环来重复取水的过程

while ((hasRead = fis.read(b)) > 0) {

// 取出竹筒中的水滴(字节),将字节数组转换成字符串进行输出

System.out.print(new String(b, 0, hasRead));

}

} catch (IOException e) {

e.printStackTrace();

} finally {

fis.close();

}

}

可以看出使用FileInputStream和FileReader进行文件的读写并没有什么区别,只是操作单元不同而且。

FileOutputStream的用法:

@Test

public void fileOutputStreamTest() throws IOException {

FileInputStream fis = null;

FileOutputStream fos = null;

try {

// 创建字节输入流

fis = new FileInputStream("D:/test/test.txt");

// 创建字节输出流

fos = new FileOutputStream("D:/test/test2.txt");

byte[] b = new byte[1024];

int hasRead = 0;

// 循环从输入流中取出数据

while ((hasRead = fis.read(b)) > 0) {

// 每读取一次,即写入文件输入流,读了多少,就写多少。

fos.write(b, 0, hasRead);

}

} catch (IOException e) {

e.printStackTrace();

} finally {

fis.close();

fos.close();

}

}

注: 使用java的IO流执行输出时,不要忘记关闭输出流,关闭输出流除了可以保证流的物理资源被回收之外,可能还可以将输出流缓冲区中的数据flush到物理节点中里(因为在执行close()方法之前,自动执行输出流的flush()方法)。java很多输出流默认都提供了缓存功能,其实我们没有必要刻意去记忆哪些流有缓存功能,哪些流没有,只有正常关闭所有的输出流即可保证程序正常。

4.缓冲流的使用(BufferedInputStream/BufferedReader, BufferedOutputStream/BufferedWriter):

字节缓冲流

@Test

public void bufferedTest() throws IOException {

FileInputStream fis = null;

FileOutputStream fos = null;

BufferedInputStream bis = null;

BufferedOutputStream bos = null;

try {

// 创建字节输入流

fis = new FileInputStream("D:/test/test.txt");

// 创建字节输出流

fos = new FileOutputStream("D:/test/test3.txt");

// 创建字节缓存输入流

bis = new BufferedInputStream(fis);

// 创建字节缓存输出流

bos = new BufferedOutputStream(fos);

byte[] b = new byte[1024];

int hasRead = 0;

// 循环从缓存流中读取数据

while ((hasRead = bis.read(b)) > 0) {

// 向缓存流中写入数据,读取多少写入多少

bos.write(b, 0, hasRead);

}

} catch (IOException e) {

e.printStackTrace();

} finally {

bis.close();

bos.close();

}

}

可以看到使用字节缓存流读取和写入数据的方式和文件流(FileInputStream,FileOutputStream)并没有什么不同,只是把处理流套接到文件流上进行读写。

上面代码中我们使用了缓存流和文件流,但是我们只关闭了缓存流。这个需要注意一下,当我们使用处理流套接到节点流上的使用的时候,只需要关闭最上层的处理就可以了。java会自动帮我们关闭下层的节点流。

2.3 转换流的使用(InputStreamReader/OutputStreamWriter):

下面以获取键盘输入为例来介绍转换流的用法。java使用System.in代表输入。即键盘输入,但这个标准输入流是InputStream类的实例,使用不太方便,而且键盘输入内容都是文本内容,所以可以使用InputStreamReader将其包装成BufferedReader,利用BufferedReader的readLine()方法可以一次读取一行内容,如下代码所示:

转换流的使用

@Test

public void changeStreamTest(){

try {

// 将System.in对象转化为Reader对象

InputStreamReader reader=new InputStreamReader(System.in);

//将普通的Reader包装成BufferedReader

BufferedReader bufferedReader=new BufferedReader(reader);

String buffer=null;

while ((buffer=bufferedReader.readLine())!=null){

// 如果读取到的字符串为“exit”,则程序退出

if(buffer.equals("exit")){

System.exit(1);

}

//打印读取的内容

System.out.print("输入内容:"+buffer);

}

}catch (IOException e){

e.printStackTrace();

}finally {

}

}

上面程序将System.in包装成BufferedReader,BufferedReader流具有缓存功能,它可以一次读取一行文本——以换行符为标志,如果它没有读到换行符,则程序堵塞。等到读到换行符为止。运行上面程序可以发现这个特征,当我们在控制台执行输入时,只有按下回车键,程序才会打印出刚刚输入的内容。

2.4 对象流的使用(ObjectInputStream/ObjectOutputStream)的使用:

对象类:

package com.design.prompt;

import java.io.Serializable;

public class UserTest implements Serializable {

/**

*

*/

private static final long serialVersionUID = 6522988290199824802L;

private String username;

transient String password;

public UserTest(){

}

public UserTest(String username, String password) {

super();

this.username = username;

this.password = password;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

@Override

public String toString() {

return "UserTest [username=" + username + ", password=" + password

+ "]";

}

}

写出对象:

@Test

public void objectWriterTest() {

OutputStream outputStream = null;

BufferedOutputStream buf = null;

ObjectOutputStream obj = null;

try {

// 序列化文件輸出流

outputStream = new FileOutputStream("D:/test/test.txt");

// 构建缓冲流

buf = new BufferedOutputStream(outputStream);

// 构建字符输出的对象流

obj = new ObjectOutputStream(buf);

// 序列化数据写入

obj.writeObject(new UserTest("A", "123"));// Person对象

// 关闭流

obj.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

读入对象

@Test

public void objectReaderTest() {

try {

InputStream inputStream = new FileInputStream("D:/test/test.txt");

// 构建缓冲流

BufferedInputStream buf = new BufferedInputStream(inputStream);

// 构建字符输入的对象流

ObjectInputStream obj = new ObjectInputStream(buf);

UserTest tempPerson = (UserTest) obj.readObject();

System.out.println("UserTest对象为:" + tempPerson);

// 关闭流

obj.close();

buf.close();

inputStream.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

注:使用对象流的一些注意事项

1.读取顺序和写入顺序一定要一致,不然会读取出错。

2.在对象属性前面加transient关键字,则该对象的属性不会被序列化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/504814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go语言os.exit(1)_在Golang中各种永远阻塞的姿势

在Golang中各种永远阻塞的姿势Go的运行时的当前设计,假定程序员自己负责检测何时终止一个goroutine以及何时终止该程序。可以通过调用os.Exit或从main()函数的返回来以正常方式终止程序。而有时候我们需要的是使程序阻塞在这一行。使用sync.WaitGroup一直等待直到Wa…

基于java二手书论文_java毕业设计_springboot框架的二手书交易管理与实现

今天介绍一个java毕设题目, 题目内容为springboot框架的二手书交易管理与实现, 是一个采用b/s结构的javaweb项目, 采用java语言编写开发工具eclipse, 项目框架jspspringbootmybatis, 二手书交易管理与实现的信息存储于mysql中, 并基于mybatis进行了orm封装, 该二手书交易管理与…

vue 分享微信传参_vue实现微信分享链接添加动态参数的方法

微信分享时 分享链接携带参数可能不是固定的 需要在分享的前一刻才知道 这里就是动态设置分享链接的基本写法 代码不是那么详尽 但大致流程如下1.安装引用jssdknpm install --save weixin-js-sdkconst wxrequire(weixin-js-sdk)2.通过config接口注入配置信息const jsApiList […

linux挂载cifs磁盘_linux使用windows磁盘,挂载共享目录

实例说明:客户两台服务器,一台web服务器(linux)只有50G,课程资源太多太大导致磁盘不够用;客户的文档服务器(windows)磁盘很大超过1T,所以产生了,将web资源使用文档服务器磁盘的想法;windows文档服务器192.168.-.-用户名…

java怎么给list集合排序_java list集合排序按某一属性排序操作

我就废话不多说了,大家还是直接看代码吧~public List sortList(List list){Collections.sort(list, new Comparator(){Overridepublic int compare(FreightM o1, FreightM o2) {if(o1.getType()0){return -1;}else{return 1;}}});return list;}实现compareTo()方法&…

excel显著性检验_使用Excel2016比较两组数据显著性差异

软件信息:Excel for Mac版本:16.26(19060901)许可证:Office 365订阅步骤一:导入(输入)数据步骤二:为Excel添加分析工具的加载项插件,路径为:工具→Excel加载项→分析工具库步骤三:开…

java 标准输入流 关闭 打开_java--标准输入输出流

//读取键盘录入的数据写到a.txt//方式一private static void method() throws IOException {//创建输入流对象InputStream is System.in;Reader r new InputStreamReader(is);//创建输出流对象FileWriter fw new FileWriter("a.txt");//读取数据byte[] bys new b…

adb native raact 夜神_React-Native安装及环境搭建(夜神模拟机运行)

React-Native环境搭建及运行必须安装的依赖有:Node、JDK 和 Android Studio。Node去官方下载,安装一直下一步下一步就好,最好是改下安装路径。这里主要记录JAVA JDK和Android Studio.一.安装JAVA JDKJAVA和React Native没有直接关系。React N…

php object keys_原生js中Object.keys方法详解

实际开发中,有时需要知道对象的所有属性,原生js提供了一个方法Object.keys()。Object.keys(obj)返回的是一个数组,该数组的所有元素都是字符串。这些元素是来自于给定的obj可直接枚举的属性,这些属性的顺序与手动遍历该对象属性时…

中望3d快捷键命令大全_CAD、3D快捷命令

1、对象特性ADC, *ADCENTER(设计中心“Ctrl+2”)CH, MO *PROPERTIES(修改特性“Ctrl+1”)MA, *MATCHPROP(属性匹配)ST, *STYLE(文字样式)COL, *COLOR(设置颜色)LA, *LAYER(图层操作)LT, *LINETYPE(线形)LTS, *LTSCALE(线形比例)LW, *LWEIGHT(线宽)UN, *U…

php 字符串函数 教程_PHP 字符串获取 substr 与 strstr 函数

PHP 字符串获取用于从字符串中获取指定字符串。相关函数如下:substr():从字符串中获取其中的一部分strstr():查找字符串在另一个字符串中第一次出现的位置,并返回从该位置到字符串结尾的所有字符subchr():同 strstr()s…

can通道采样频率_CAN采样点设置为多少合适?设置不对会咋样?

网上有人说道&#xff1a;(1)一般配置在75-80%的位置(2)选择采样点位置在85%左右为佳(3)75% when 波特率 > 800K80% when 波特率 > 500K87.5% when 波特率 < 500K那么到底是多少呢&#xff1f;本博主在ISO11898-1没有找到确切的值。但是cia官网找到了(http:…

简单的php,php简单语句

标签&#xff1a;(01)PHP标记 <?php ?>?>(02)输出语句//echo 不加括号能打印多个值//print 有返回值不能打印多个值//die() 输出并退出程序//exit() 输出并退出程序//printf() 格式化输出//sprintf() 格式化返回//var_dump() 输出全部信息和内…

内固定取出术后护理_股骨内固定钢板取出术后护理查房记录范文

病情分析&#xff1a;2009年10月26日 手术后精神,饮食,睡眠,体重变化等指导意见&#xff1a;一, 护理业务查房&#xff1a;  1, 临床临床护理查房&#xff1a;  是对新入,危重病人的现存护理问题,措施,护理效果,护理质量进行的护理查房,目的是检查,指导责任护士的工作质量,…

python echo命令_如何用Python调用外部命令

解决方法方法1&#xff1a;我们可以使用subprocess&#xff0c;比如要执行 ls -l 命令import subprocesssubprocess.run("ls", "-l")Python3.5 之前的版本&#xff0c;需要使用 callimport subprocesssubprocess.call(["ls", "-l"])方…

vba php,VBA

【行业前景】很多时候&#xff0c;当我们提起VBA&#xff0c;就想到和Excel有关&#xff0c;其实这里所提到的VBA是依附在Excel平台上进行的二次开发&#xff0c;当然它还可以大量应用在其他的软件中&#xff0c;可用VBA进行二次开发。对于我们最常使用的Excel&#xff0c;VBA可…

ios 捕抓crash_ios crash的原因与抓取crash日志的方法

首先我们经常会闪退的异常有哪些呢&#xff1f;crash的产生来源于两种问题&#xff1a;违反iOS策略被干掉&#xff0c;以及自身的代码bug。1.IOS策略1.1低内存闪退前面提到大多数crash日志都包含着执行线程的栈调用信息&#xff0c;但是低内存闪退日志除外&#xff0c;这里就先…

php 多线程上传,PHP CURL 多线程操作代码实例

/** Curl 多线程类* 使用方法&#xff1a;* $urls array("http://baidu.com", "http://dzone.com", "http://google.com");$mp new MultiHttpRequest($urls);$mp->start();* */class MultiHttpRequest {public $urls array();public $curl…

jlabel 不能连续两次set_为什么有时连续多次setState只有一次生效?

例如下面的代码&#xff0c;两次打印出的结果是相同的&#xff1a;componentDidMount() {this.setState({ index: this.state.index 1 }, () > {console.log(this.state.index);})this.setState({ index: this.state.index 1 }, () > {console.log(this.state.index);}…

java字符流实际上也是字节,[Java教程]Java字节流与字符流的区别

[Java教程]Java字节流与字符流的区别0 2017-05-22 12:00:42字节流与和字符流的使用非常相似&#xff0c;两者除了操作代码上的不同之外&#xff0c;是否还有其他的不同呢&#xff1f;实际上字节流在操作时本身不会用到缓冲区(内存)&#xff0c;是文件本身直接操作的&#xff0c…