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 关闭此输出流并释放与此流有关的所有系统资源

通过输入输出流复制图片的例子:

  1. public class Test {
  2. public static void main(String[] args) throws IOException{
  3. long startTime = System.currentTimeMillis();
  4. InputStream is = new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg"));
  5. OutputStream os = new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg"));
  6. int i = 0;
  7. while(i != -1){
  8. i = is.read();
  9. os.write(i);
  10. }
  11. is.close();
  12. os.close();
  13. long endTime = System.currentTimeMillis();
  14. System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
  15. }
  16. }
  17. //输出结果为:程序运行时间40231ms

通过缓冲流提高复制速度

  1. public class Test {
  2. public static void main(String[] args) throws IOException{
  3. long startTime = System.currentTimeMillis();
  4. BufferedInputStream bis = new BufferedInputStream(new
  5. FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg")));
  6. BufferedOutputStream bos = new BufferedOutputStream(new
  7. FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg")));
  8. int i = 0;
  9. while(i != -1){
  10. i = bis.read();
  11. bos.write(i);
  12. }
  13. bos.flush();
  14. bis.close();
  15. bos.close();
  16. long endTime = System.currentTimeMillis();
  17. System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
  18. }
  19. }
  20. //输出结果为:程序运行时间486ms

文件较大时,做一个缓冲处理

  1. public class Test {
  2. public static void main(String[] args) throws IOException{
  3. long startTime = System.currentTimeMillis();
  4. byte[] tmp = new byte[1024];
  5. InputStream is = new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg"));
  6. OutputStream os = new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg"));
  7. int i = 0;
  8. while(i != -1){
  9. i = is.read(tmp);
  10. os.write(tmp);
  11. }
  12. is.close();
  13. os.close();
  14. long endTime = System.currentTimeMillis();
  15. System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
  16. }
  17. }
  18. //输出结果为:程序运行时间61ms

双缓冲

  1. public class Test {
  2. public static void main(String[] args) throws IOException{
  3. long startTime = System.currentTimeMillis();
  4. byte[] tmp = new byte[1024];
  5. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg")));
  6. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg")));
  7. int i = 0;
  8. while(i != -1){
  9. i = bis.read(tmp);
  10. bos.write(tmp);
  11. }
  12. bos.flush();
  13. bis.close();
  14. bos.close();
  15. long endTime = System.currentTimeMillis();
  16. System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
  17. }
  18. }
  19. //输出结果为:程序运行时间29ms

可以看到第一种情况效率最低,所以若非特殊要求可以放弃这种方法。

InputStream和OutputStream及相关知识汇总的更多相关文章

  1. [转帖]xserver相关知识汇总

    xserver相关知识汇总 https://blog.csdn.net/QTVLC/article/details/81739984   本文主要是从以下几个方面介绍xorg-xserver 相关的知 ...

  2. Logback相关知识汇总

    例如:%-4relative 表示,将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为4格式修饰符,与转换符共同使用:可选的格式修饰符位于“%”和转换符之间.第一个可选修饰符是左对齐 标志 ...

  3. [skill][https][ssl/tls] HTTPS相关知识汇总

    结论前置: A 身份验证 证书, 服务器证书 B 密钥协商 RSA   DHE / ECDHE   PSK C 加密通信 加密通信采用对称加密,使用B阶段协商出来的密钥. B 阶段如果使用 RSA 协 ...

  4. Android安装包相关知识汇总 (编译过程图给力)

    转自: https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208008519&idx=1&sn=278b7793699 ...

  5. javascript 字符串相关知识汇总

    ① charAt(): 选中字符串内第几个元素 <script> var str="1234567389"; alert( str.charAt(1) ); // 2 ...

  6. java NIO中的Reactor相关知识汇总 (转)

    一.引子 nio是java的IO框架里边十分重要的一部分内容,其最核心的就是提供了非阻塞IO的处理方式,最典型的应用场景就是处理网络连接.很多同学提起nio都能说起一二,但是细究其背后的原理.思想往往 ...

  7. js获取元素宽高、位置相关知识汇总

    常见clientWidth.clientHeight.offsetWidth.offsetLeft,clientX.scrollTop等词语,比较混乱,现在总结下他们的区别. 1. clientWid ...

  8. CEF3相关知识汇总(不断更新)

    CEF全称是Chromium Embedded Framework,它是Chromium的Content API的封装库. CEF官网地址:https://bitbucket.org/chromium ...

  9. Java IO流操作汇总: inputStream 和 outputStream【转】

    我们在进行Android java 开发的时候,经常会遇到各种IO流操作.IO流操作一般分为两类:字符流和字节流.以“Reader”结尾都是字符流,操作的都是字符型的数据:以“Stream”结尾的都是 ...

随机推荐

  1. Spring Cloud-新一代Web框架微服务

    序言 springcloud是微服务架构的集大成者,将一系列优秀的组件进行了整合.基于springboot构建,对我们熟悉spring的程序员来说,上手比较容易. 通过一些简单的注解,我们就可以快速的 ...

  2. PHP系列 | PDO::prepare(): send of 68 bytes failed with errno=32 Broken pipe

    设计场景 1.开启Redis的键空间过期事件(键过期发布任务),创建订单创建一个过期的key,按照订单号为key,设置过期时间. 2.通过Redis的订阅模式(持久阻塞),获取到订单号进行组装. 3. ...

  3. exception: TypeError: Cannot read property '_modulesNamespaceMap' of undefined at getModuleByNamespac

    用 Vue.extend 创造的组件构造器和组件,默认是不集成 store 和 router 的. 比如 main.js 中的这个,其实是挂载在根组件 vm 中.并不是注入到全局 Vue 中.所以你用 ...

  4. 配置cisco设备记录用户命令

    R1(config)# aaa new-model R1(config)# aaa accounting commands 0 default start-stop group local R1(co ...

  5. 研发团队是该制定OKR还是KPI?

    绩效管理和OKR的目标管理,是前行的两条腿,缺谁都会寸步难行.正确的做法是把企业的使命和任务,转化为经营目标,然后再用KPI.OKR等绩效管理工具,分解.执行.考核.. KPI是一套绩效管理的方法.全 ...

  6. vue方法中传递dom对象示例

    <div id="app"> <input type="text" v-on:keyup="onlyNum($event)" ...

  7. ORA-01126: 数据库必须已装载到此实例并且不在任何实例中打开

    原因:修改归档模式的操作只能在 mount 状态下进行,不能处于 open 状态. SQL> alter database archivelog;alter database archivelo ...

  8. C# .net 提升 asp.net mvc, asp.net core mvc 并发量

    1.提升System.Net.ServicePointManager.DefaultConnectionLimit 2.提升最小工作线程数 ------ DefaultConnectionLimit在 ...

  9. Java 文件完整性校验 MD5 sha1 sha256 sha224 sha384 sha512

    由于项目中需要使用文件做备份,并且要提供备份文件的下载功能.备份文件体积较大,为确保下载后的文件与原文件一致,需要提供文件完整性校验. 网上有这么多此类文章,其中不少使用到了 org.apache.c ...

  10. 【ARM-Linux开发】Linux模块机制浅析

    Linux模块机制浅析   Linux允许用户通过插入模块,实现干预内核的目的.一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析. 模块的Hello World! ...