InputStream和OutputStream及相关知识汇总
https://www.jianshu.com/p/e5bc7ea5f948
最近帮学姐写爬虫的时候遇到奇怪的问题,同样的程序在Mac上可以正常运行而在Windows上返回结果错误,最后经排查发现是Linux与Windows的默认编码方式不同,而自己的程序没有设置编码方式自动采用了默认的编码方式,所以导致错误发生。之后尝试了多种编码方式均告失败,最后发现是由于自己对输入输出流的认识不到位,没有正确使用的原因,故进行整理学习。
首先认识一下字节流与字符流。程序中的输入输出都是通过流的形式保存的,流中保存的全是字节文件。根据处理数据类型不同可以分为字节流和字符流。字节流是字符流的基础。
字节流:字节流处理单元为一个字节,操作字节和字节数组。如果是音频、图片等建议用字节流。
字符流:字符流处理单元为两个字节的UNICODE字符,操作字符家、字符数组和字符串,对多国语言支持性较好,如果是文本建议用字符流。
基于字节流的Stream:通常以OutputStream和InputStream结尾,DataOutputStream、DataInputStream、FileOutputStream……
**基于字符流的Stream:通常以Writer和Reader结尾,PrintWriter、FileWriter、FileReader、StringWriter……
可以发现绝大部份流都是成对出现的,包括输入流和输出流。可以这样理解输入输出流
输入流(InputStream和Reader)可以看作一个出水的水龙头,具有流出水流的功能,即向程序产生数据的功能,read便相当于打开开关,之后便会流出水流(数据)。
输出流(OutputStream和Writer)可以看作一个进水的水龙头,具有储存水流的功能,即接收程序产生的数据,write后也相当于打开开关,水流(数据)流进进水水龙头。
介绍完了基本概念,现在来看一下基本用法。
| InputStream | |
|---|---|
| 从流中读取数据 | |
| public abstract int read() throws IOException | 从输入流中读取下一字节。返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回-1。 |
| public int read(byte[] b) throws IOException | 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。以整数形式返回实际读取的字节数。等同于read(byte[],int,int) |
| public int read(byte[] b, int off, int len) throws IOException | 将输入流中最多len个数据字节读入byte数组。尝试读取len个字节,但读取的字节也可能小于该值。将读取的第一个字节存储在元素b[off]到b[off+k-1]的元素中,以此类推。 |
| public long skip(long n) throws IOException | 跳过和丢弃此输入流中数据的 n 个字节。出于各种原因,skip 方法结束时跳过的字节数可能小于该数,也可能为 0。导致这种情况的原因很多,跳过 n 个字节之前已到达文件末尾只是其中一种可能。返回跳过的实际字节数。如果 n 为负,则不跳过任何字节。此类的 skip 方法创建一个 byte 数组,然后重复将字节读入其中,直到读够 n 个字节或已到达流末尾为止。建议子类提供此方法更为有效的实现。例如,可依赖搜索能力的实现。 |
| public int available() throws IOException | 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数(流中尚未被读取的字节数)。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。注意,有些 InputStream 的实现将返回流中的字节总数,但也有很多实现不会这样做。试图使用此方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的。如果已经调用 close() 方法关闭了此输入流,那么此方法的子类实现可以选择抛出 IOException。类 InputStream 的 available 方法总是返回 0。此方法应该由子类重写。 |
| 关闭流 | |
| public void close() throws IOException | 关闭输入流并释放与该流关联的所有系统资源 |
| 使用输入流中的标记 | |
| public void mark(int readlimit) | 在此输入流中标记当前位置。对 reset 方法的后续调用会在最后标记的位置重新定位此流,以便后续读取重新读取相同的字节。readlimit 参数表示读取readmit个字节数后标记失效。 |
| public void reset() throws IOException | 将读指针重新指向mark方法记录的位置。 |
| public boolean markSupported() | 测试此输入流是否支持mark()和reset()方法。 |
| OutputStream | |
|---|---|
| 输出数据 | |
| public abstract void write(int b) throws IOException | 将指定的字节写入输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 |
| public void write(byte[] b) throws IOException | 将b.length个字节从指定的byte数组写入此输出流。与write(b, 0, b.length)等同 |
| public void write(byte[] b, int off, int len) throws IOException | 将指定数组中从偏移量off开始的len个字节写入此输出流。 |
| 刷新流 | |
| public void flush() throws IOException | 刷新此输出流并强制写出所有缓冲的字节。如果此流的预期目标是由基础操作系统提供的一个抽象(如一个文件),则刷新此流只能保证将以前写入到流的字节传递给操作系统进行写入,但不保证能将这些字节实际写入到物理设备(如磁盘驱动器)。 |
| 关闭流 | |
| public void close() throws IOException | 关闭此输出流并释放与此流有关的所有系统资源 |
通过输入输出流复制图片的例子:
public class Test {
public static void main(String[] args) throws IOException{
long startTime = System.currentTimeMillis();
InputStream is = new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg"));
OutputStream os = new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg"));
int i = 0;
while(i != -1){
i = is.read();
os.write(i);
}
is.close();
os.close();
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
}
}
//输出结果为:程序运行时间40231ms
通过缓冲流提高复制速度
public class Test {
public static void main(String[] args) throws IOException{
long startTime = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new
FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg")));
BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg")));
int i = 0;
while(i != -1){
i = bis.read();
bos.write(i);
}
bos.flush();
bis.close();
bos.close();
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
}
}
//输出结果为:程序运行时间486ms
文件较大时,做一个缓冲处理
public class Test {
public static void main(String[] args) throws IOException{
long startTime = System.currentTimeMillis();
byte[] tmp = new byte[1024];
InputStream is = new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg"));
OutputStream os = new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg"));
int i = 0;
while(i != -1){
i = is.read(tmp);
os.write(tmp);
}
is.close();
os.close();
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
}
}
//输出结果为:程序运行时间61ms
双缓冲
public class Test {
public static void main(String[] args) throws IOException{
long startTime = System.currentTimeMillis();
byte[] tmp = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg")));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg")));
int i = 0;
while(i != -1){
i = bis.read(tmp);
bos.write(tmp);
}
bos.flush();
bis.close();
bos.close();
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
}
}
//输出结果为:程序运行时间29ms
可以看到第一种情况效率最低,所以若非特殊要求可以放弃这种方法。
InputStream和OutputStream及相关知识汇总的更多相关文章
- [转帖]xserver相关知识汇总
xserver相关知识汇总 https://blog.csdn.net/QTVLC/article/details/81739984 本文主要是从以下几个方面介绍xorg-xserver 相关的知 ...
- Logback相关知识汇总
例如:%-4relative 表示,将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为4格式修饰符,与转换符共同使用:可选的格式修饰符位于“%”和转换符之间.第一个可选修饰符是左对齐 标志 ...
- [skill][https][ssl/tls] HTTPS相关知识汇总
结论前置: A 身份验证 证书, 服务器证书 B 密钥协商 RSA DHE / ECDHE PSK C 加密通信 加密通信采用对称加密,使用B阶段协商出来的密钥. B 阶段如果使用 RSA 协 ...
- Android安装包相关知识汇总 (编译过程图给力)
转自: https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208008519&idx=1&sn=278b7793699 ...
- javascript 字符串相关知识汇总
① charAt(): 选中字符串内第几个元素 <script> var str="1234567389"; alert( str.charAt(1) ); // 2 ...
- java NIO中的Reactor相关知识汇总 (转)
一.引子 nio是java的IO框架里边十分重要的一部分内容,其最核心的就是提供了非阻塞IO的处理方式,最典型的应用场景就是处理网络连接.很多同学提起nio都能说起一二,但是细究其背后的原理.思想往往 ...
- js获取元素宽高、位置相关知识汇总
常见clientWidth.clientHeight.offsetWidth.offsetLeft,clientX.scrollTop等词语,比较混乱,现在总结下他们的区别. 1. clientWid ...
- CEF3相关知识汇总(不断更新)
CEF全称是Chromium Embedded Framework,它是Chromium的Content API的封装库. CEF官网地址:https://bitbucket.org/chromium ...
- Java IO流操作汇总: inputStream 和 outputStream【转】
我们在进行Android java 开发的时候,经常会遇到各种IO流操作.IO流操作一般分为两类:字符流和字节流.以“Reader”结尾都是字符流,操作的都是字符型的数据:以“Stream”结尾的都是 ...
随机推荐
- H3C交换机如何删除VLAN
H3C交换机如何删除VLAN,如果直接使用“undo vlan”是删不干净的,因为配置VLAN时还配置过接口. 1.首先通过console口或telnet连接三层交换机,进入用户视图模式”<H3 ...
- HandlerMethodArgumentResolver的抽象實現AbstractNamedValueMethodArgumentResolver下的子类
Annotation-based argument resolution 部分2 org.springframework.web.servlet.mvc.method.annotation.Reque ...
- 超简易简易PHP爬虫
利用CURL和DOMDocument.通过xpath筛选数据,实现的简易PHP爬虫 <?php header('Content-type: text/plain; charset=utf-8') ...
- windows系统下设置mtu值的方法
说起 MTU 值,可能许多朋友连听都没听说过.简单来说,我们上网时所进行的操作,都是通过传输一个又一个“数据包”来实现的,而 MTU 值就是用来设定可传输数据包的最大尺寸的.很显然,MTU 值设置得过 ...
- Ubuntu16.04安装Supervisor
安装 sudo apt-get install supervisor 启动,否则会报 unix:///tmp/supervisor.sock no such file service supervis ...
- (转载)Pytorch中的仿射变换(affine_grid)
转载于:Pytorch中的仿射变换(affine_grid) 参考:详细解读Spatial Transformer Networks (STN) 假设我们有这么一张图片: 下面我们将通过分别通过手 ...
- start & stop kafka cluster shell script
kafka_start_cluster.sh #!/bin/bash brokers="kafka-server-1 kafka-server-2 kafka-server-3" ...
- python装饰器 语法糖
简介: 装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数. 比如说我们写flask,路由就是用装饰器定义的.如果写权限控制,那么权限控制一般也是 ...
- 【NPDP笔记】第五章 工具与度量
5.1 创意工具 Ideation 创意开发 创意工具 Scamper Substitute Combine Adapter Modify Put to another use Eliminate ...
- 如何优雅的使用telnet测试端口连通性
telnet命令是TELNET协议的用户接口,它支持两种模式:命令模式和会话模式,虽然telnet支持许多命令,但大部分情况下,我们只是使用它查看目标主机是否打开了某端口(默认是23). 其执行结果有 ...