接口保存返回流

最近在做一个需求时,遇到流的问题,在这总结下:
需求是,我要调别人的接口,对方给我返回一个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

 

posted @ 2019-12-05 16:40  猿族小新  阅读(1437)  评论(0编辑  收藏  举报