zoukankan      html  css  js  c++  java
  • 接口保存返回流

    最近在做一个需求时,遇到流的问题,在这总结下:
    需求是,我要调别人的接口,对方给我返回一个pdf的电子发票流,我接收后进行保存到本地
    首先贴一张猿友的图,

    IO流分两种;字符流&字节流

    百度===>字节流和字符流

    什么是流
    流是个抽象的概念,是对输入输出设备的抽象,输入流可以看作一个输入通道,输出流可以看作一个输出通道。
    输入流是相对程序而言的,外部传入数据给程序需要借助输入流。
    输出流是相对程序而言的,程序把数据传输到外部需要借助输出流。

    字节流与字符流
    字节流是由字节组成的,字符流是由字符组成的

    字节与字符
    :数据存储的最小单位。每个二进制数字0或者1就是1个位;
    字节:8个位构成一个字节;即:1 byte (字节)= 8 bit(位);
    字符:a、A、中、+、*、の......均表示一个字符;一般utf-8 编码下,一个汉字字符占用3个字节;一般gbk 编码下,一个汉字字符占用2个字节;

    继续百度
    字节数据是二进制形式的,是我们计算机存储的一种形式;
    字符就是我们在各种客户端看到的各种文字,是内存中的一种状态;
    字节与字符之间差了一个编码;

    回到最初的需求,要在别人接口中获取一个pdf流,那么获取到的是什么?
    我们知道网络传输的都是二级制数据,字符流又不是二级制,那么不论对方是怎么处理的文件,他最终传给我的一定是字节流。
    所以不管接到后怎么处理,反正直接节流就对了,

             // 获取一个浏览器
                DefaultHttpClient httpclient = new DefaultHttpClient();
                // 获取get请求
                HttpGet httpget = new HttpGet(url);
                // 请求对方服务器
                HttpResponse response = httpclient.execute(httpget);
                // 获取返回数据
                InputStream inputStream = response.getEntity().getContent();

    事实证明了上面的结论,返回的确实是字节流;

    然后怎么处理呢?
    那就直接把字节流保存吧,反正保存后也是字节,

                // new 一个本地文件
                File file = new File("D:\11111.pdf");
                // 创建相对于程序的输出流
                OutputStream outputStream = null;
                try {
                    outputStream = new FileOutputStream(file);
                    // 读取数据
                    byte[] b = new byte[1024];// b - 数据
                    int off = 0;// off - 数据中的起始偏移量。
                    int len = -1;// len - 要写入的字节数。
                    while ((len = inputStream.read(b)) != -1) {// 从输入流读取一些字节数,并将它们存储到缓冲区b。实际读取的字节数作为整数返回,如果没有字节可用,因为流在文件末尾,则返回值-1;否则,读取至少一个字节并存储到b。
                        outputStream.write(b, off, len);// 数组b中的一些字节按顺序写入输出流; 元素off是写入的第一个字节,len是此操作写入的最后一个字节。
                    }
                    outputStream.flush();// 刷新此输出流并强制任何缓冲的输出字节被写出。
                } catch (IOException e) {
                    System.out.println("异常");
                    e.printStackTrace();
                } finally {
                    inputStream.close();//关闭此输入流并释放与此流相关联的任何系统资源。
                    outputStream.close();//关闭此输出流并释放与此流相关联的任何系统资源。
                }

    然后尝试他们的子类们,例:BufferedInputStream 与 BufferedOutputStream

                // 获取一个浏览器
                DefaultHttpClient httpclient = new DefaultHttpClient();
                // 获取get请求
                HttpGet httpget = new HttpGet(url);
                // 请求对方服务器
                HttpResponse response = httpclient.execute(httpget);
                // 获取返回数据
                BufferedInputStream inputStream = (BufferedInputStream)response.getEntity().getContent();
                // new 一个本地文件
                File file = new File("D:\11111.pdf");
                // 创建相对于程序的输出流
                BufferedOutputStream outputStream = null;
                try {
                    FileOutputStream fileOutputStream = new FileOutputStream(file);
                    outputStream = new BufferedOutputStream(fileOutputStream);
                    // 读取数据
                    byte[] b = new byte[1024];// b - 数据
                    int off = 0;// off - 数据中的起始偏移量。
                    int len = -1;// len - 要写入的字节数。
                    while ((len = inputStream.read(b)) != -1) {// 从输入流读取一些字节数,并将它们存储到缓冲区b。实际读取的字节数作为整数返回,如果没有字节可用,因为流在文件末尾,则返回值-1;否则,读取至少一个字节并存储到b。
                        outputStream.write(b, off, len);// 数组b中的一些字节按顺序写入输出流; 元素off是写入的第一个字节,len是此操作写入的最后一个字节。
                    }
                    outputStream.flush();// 刷新此输出流并强制任何缓冲的输出字节被写出。
                } catch (IOException e) {
                    System.out.println("异常");
                    e.printStackTrace();
                } finally {
                    inputStream.close();//关闭此输入流并释放与此流相关联的任何系统资源。
                    outputStream.close();//关闭此输出流并释放与此流相关联的任何系统资源。
                }

    他们的子类在使用中并没有太大的区别,网上扒了下他们各自的特点,至于具体选择使用哪个类,可以参考这篇文章:https://www.cnblogs.com/penghuster/p/4869153.html

    *********************************************
    *******************字符流*********************
    *********************************************

    然后,如果接口返回的是字符串应该怎么处理呢,于是我换了一个get地址,返回的是一个字符串。
    对于这样的返回,我们一般情况下肯定是不需要保存的的,肯定是在内存中转为字符串进行编辑展示什么的,但是为了理解流之间的关系,保存一下试试,

                // 获取一个浏览器
                DefaultHttpClient httpclient = new DefaultHttpClient();
                // 获取get请求
                HttpGet httpget = new HttpGet(url);
                // 请求对方服务器
                HttpResponse response = httpclient.execute(httpget);
                // 获取返回数据
                InputStream inputStream = response.getEntity().getContent();
                
                InputStreamReader inputStreamReader = null;
                OutputStreamWriter outputStreamWriter = null;
                try {
                    // 将返回的字节流转为字符流
                    inputStreamReader = new InputStreamReader(inputStream,"utf-8");
                    // 再将转出的字符流再转回字节流保存到磁盘
                    File file = new File("D:\11.txt");// 二级制字节文件
                    FileOutputStream fileOutputStream = new FileOutputStream(file);// 用于程序输出的字节流
                    outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");// 将字符流转为字节流
                    // 读取数据
                    char[] chars = new char[1024];
                    int off =0;
                    int len = -1;
                    while ((len=inputStreamReader.read(chars))!=-1){
                        System.out.println(len);
                        outputStreamWriter.write(chars,off,len);
                    }
                } catch (IOException e) {
                    System.out.println("异常");
                    e.printStackTrace();
                } finally {
                    // 关闭资源
                    outputStreamWriter.flush();
                    outputStreamWriter.close();
                    inputStreamReader.close();
                }

    事实证明是可以的,接口返回字节流,然后将字节流转为我们认识的字符,再将我们认识的字符转为二进制字节进行保存,基本可以明白流之间的关系了。

    那么正常情况下怎么转为字符串打印呢?

           // 获取一个浏览器
                DefaultHttpClient httpclient = new DefaultHttpClient();
                // 获取get请求
                HttpGet httpget = new HttpGet(url);
                // 请求对方服务器
                HttpResponse response = httpclient.execute(httpget);
                // 获取返回数据
                InputStream inputStream = response.getEntity().getContent();
                
                InputStreamReader inputStreamReader = null;
                BufferedReader bufferedReader = null;
                try {
                    // 将字节流转为字符流
                    inputStreamReader = new InputStreamReader(inputStream,"utf-8");
                    // BufferedReader类是从字符输入流中读取文本并缓冲字符,以便有效地读取字符,数组和行
                    bufferedReader = new BufferedReader(inputStreamReader);
                    // 创建保存字符串的StringBuffer
                    StringBuffer str = new StringBuffer();
                    String s = null;
                    while ((s=bufferedReader.readLine())!=null){
                        str.append(s);
                    }
                    // 打印
                    System.out.println(str.toString());
                } catch (IOException e) {
                    System.out.println("异常");
                    e.printStackTrace();
                } finally {
                    inputStreamReader.close();
                    bufferedReader.close();
                }

    这里有一点点不用,不再使用输出流,因为相对于程序没有写磁盘嘛,所以用不着输出流。

    使用了BufferedReader ,BufferedReader类是从字符输入流中读取文本并缓冲字符,以便有效地读取字符,数组和行,具体解释参考:https://blog.csdn.net/ai_bao_zi/article/details/81134801

    还用了StringBuffer ,补充一个String,StringBuffer,StringBuilder三者的使用方法和区别:https://blog.csdn.net/qq_37856300/article/details/84340288

  • 相关阅读:
    中綴表達式求值的兩種方法
    两次bfs求树的直径的正确性
    感染linux脚本程序技术
    C# 动态代码执行
    中秋写了个狼吃羊的智力游戏
    做一个让人喜欢的人
    MySQL数据库安全配置指南
    用 VS 2005 生成 .NET 1.1 程序
    防止入侵和攻击的主要技术措施
    .NETZ 原理分析
  • 原文地址:https://www.cnblogs.com/zhxb/p/11958175.html
Copyright © 2011-2022 走看看