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”结尾的都是 ...
随机推荐
- 前端知识点回顾之重点篇——CSS中flex布局
flex布局 来源: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool 采用 Flex 布局的元素 ...
- spring cloud java: 无法访问redis.clients.jedis.JedisPoolConfig 找不到redis.clients.jedis.JedisPoolConfig的类文件
spring cloud <spring-cloud.version>Greenwich.SR3</spring-cloud.version> 注入Redis 时候: @Bea ...
- Consider defining a bean of type 'com.*.*.feign.*FeignClient' in your configuration.
Description: Field *FeignClient in com.*.*.service.* required a bean of type '***********' that coul ...
- python非官方扩展库
https://www.lfd.uci.edu/~gohlke/pythonlibs/ 安装方法: 1.下载自己需要的库文件 例如:Twisted-19.2.1-cp37-cp37m-win32.wh ...
- Mac下进入MySQL命令行
/usr/local/MySQL/bin/mysql -u root -p 其中,root为数据库用户名
- makefile那些事儿
一.好处 自动化编译,一条make命令,整个工程可以完全自动编译,make命令是构建大型项目的首选方案. makefile就像一个shell脚本一样,用来定义规则,一个名称包含一条或多条命令,在终端m ...
- docker load tar.gz包失败解决方法
执行docker load -i xxx.tar.gz时候报错 open /var/lib/docker/xxx No such file or directory 这种情况属于容器快照文件缺乏基础镜 ...
- Centos7——无法访问Windows系统的分区
我的Windows分区是Ntfs格式的,所以我直接安装ntfs即可解决年 yum -y install ntfs*
- web page popup window model
jQuery UI dialog: https://jqueryui.com/dialog/ Semantic UI https://semantic-ui.com/modules/modal.htm ...
- Kubernetes之在k8s中部署Java应用
部署好了k8s以后 部署参考https://www.cnblogs.com/minseo/p/12055731.html 怎么在k8s部署应用 项目迁移到k8s平台是怎样的流程 1,制作镜像 2,控制 ...