数据流和字节数组流

网络传输模型

在一个网络传输模型中,假如A电脑想把一个double类型的数值12.34传给另一个网络的电脑B,要如何实现?

1. 转为字节数组

无论网络上两个终端之间要传输什么类型的数据,实际在网线上传输都是二进制数据(bit)。

所以A电脑并不能字节把这个double类型的数据传送出去,而是必须将这个值12.34转换为字节类型(16个bit).

将一个double类型转换为字节类型并不简单,这设计到编码的问题,但是这些java封装好了,我们不用管。而一个double类型的数据并不是一个直接就能存放的,double类型的长度是64位,所以需要一个64为长度的字节数组才能完整存放一个double类型的数组。

有人就问了,既然网络上传输的是bit,为何不直接把变量转化为bit类型?绝大部分计算机的内存最小单位是8bit(就是一个地址),所以大部分变量的最小长度也是8bit(一个字节)。所以无论传输什么类型的变量,都不要把变量的数据转化为字节数据,然后存放在1个字节数组里面。为了尽量减少网络上传输的数据大小,我们通常把要传输的字节数组打包成一个压缩数据包,这样,在网络上传输的实际就是数据包。B电脑接收到数据包之后,就需要解压数据包得到A里面封装的字节数组,然后将该字节数组转换为原来的double。

实际上java中没有提供一个号的封装方法来将基本变量和字节数组进行转换。但是提供了两个流,它们嵌套使用的话,相当于实现了这个功能,将各种基本类型转换为字节数组,它们就是DataOutputStream和ByteArrayOutStream。

ByteArrayOutputStream

我们知道FileOutputStream是一个指向文件的字节流,同样地,ByteArrayOutputStream也可以理解为一个指向1个ByteArray的字节流。我们可以从这个流添加字节数据到一个字节数组。

构造方法

有必要提一提这个ByteArrayOutputStream的构造方法。既是指向ByteArray,必然要有1个core字节数组(目标数组)

例如FileOutputStream,有一个构造方法是new FileOutputStream(File f),作为参数,我们必须制定文件输出字节流的目标文件。而对于ByteArrayOutputStream(new ByteArrayOutputStream(byte[] b)),则没有,也就是讲我们不能制定数组output字节流的目标字节数组。实际上,对于ByteArrayOutputStream来讲,目标字节数组是builded in,也就是它对于程序员是隐藏的。但是它提供了另外一个方法,toByteArray(),这个方法new了一个新的字节数组,然后把隐藏的目标字节数组的数据复制到这个新的字节数字内,也就是说返回一个隐藏的字节数组的副本,而这个流提供了另外一个狗仔方法new BuyeArrayOutputStream(int bufferSize),参数只能用于指定缓冲区大小。

ByteArrayOutputStream的成员方法和FileOutputStream很类似,都具有

write(int) 写一个字节

write(byte[])写一个字节数组。

DataOutputStream

跟上面那个流不同,DataOutputStream不能理解为指向“Data”的字节流。实际上DataOutputStream是处理流(包裹流)的一种,必须基于一个原始流之上。

DataOutputStream提供的方法就强大得太多了,例如:

writeFloat(float f)写入1个float到流中

writeLong(long l)写入1个long类型到流中

可见,DataOutputStream实际提供了各种将基本类型写入到字节流的1中渠道,包裹ByteArrayOutputStream的话就能转换为字节数组。

在前面博文提过,java的Stream根据传输的最小单元。可以分为字符流和字节流。字节流引用更广,而字符流在某些情况(例如文本处理)会更加方便。而在编程中,有时程序收到的是一条字节流(前提是确定该流存储的是字符数据)。而程序员又想将其当字符流来处理,就可以利用java中的InputStreamReader和OutputStreamWriter。

什么是转换流

上面提到两个流:InputStreamReader和OutputStreamWriter在java中就被称为转换流。

InputStream和OutputStream代表的是字节流,而Reader和Writer代表字符流,那么如果它们写在一起是什么流呢?实际上它们是处理流的一种,必须包裹在1个字节流上,然后能当字符流来处理,相当于把一个字节流转换为一个字符流,而无需关心编码方式。

另外一个问题,有没有反过来,把字符流转为字节流的转换流呢?答案:java没有提供,但是有必要的话,字节可以写1个。

一个例子:

上面的转换流的常用方法就不一一介绍了,无非就是read()和write(),跟字符流的对应方法基本一样。

现在写一个例子:

接受用户键盘输入的1行字符(直到回车),放入1个字符串中。

首先题目看起来很简单,这个需求简单地就是接受由外部设备(键盘)发送的数据,接受到程序的1个String变量上。

首先我们要构造1个从键盘到程序的字节流

我们需要的字符,为什么要构造1个字节流呢?因为能直接连接键盘的流只有直接留。如果我们建立1个从文件(外部设备)到程序的InputStream,则必须利用文本流new FileInputStream(File f),而在java中,键盘同样会被当做1个外部输入设备,这个外部输入设备有点特殊,因为键盘会被当成默认的系统输入设备,也叫标准输入流。

而连接系统输入设备的字节流,java已经帮我们封装好了,它就是System.in。其实System是一个类,in是system类中的一个静态字段(非方法),它返回的就是标准输入流的对象。同样地,Java中也有一个标准输出流,它就是System.out(同样是一个静态字段,返回一个流向标准输出设备的OutputStream)这个流的输出目标默认就是计算机屏幕执行java程序的终端。当然,这个默认值是可以改变的,我们可以利用System.setOut()来修改。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值