輸入輸出流接收HttpURLConection獲取網頁內容時內容缺失

這是我在通過釘釘的開發者文檔獲取部門信息的時候所遇到的問題。

這裏寫圖片描述

錯誤提示是這個樣子,大致的意思就是json字符串格式錯誤,在將json字符串轉化成json對象的時候出現錯誤。

後來通過釘釘所提供的的url在瀏覽器上直接進行訪問,會顯示如下信息:

這裏寫圖片描述

這是一串json字符串的代碼。

後臺代碼如下:

JSONArray department = new JSONArray();

    try {

        URL urlGet = new URL(url);

        HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();

        http.setRequestMethod("GET"); // 必須是get方式請求
        http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        http.setDoOutput(true);
        http.setDoInput(true);

        System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 連接超時30秒
        System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 讀取超時30秒

        http.connect();

        InputStream is = http.getInputStream();
        int size = is.available();

        byte[] jsonBytes = toByteArray(is);
        String message = new String(jsonBytes, "UTF-8");

        JSONObject demoJson =JSONObject.fromObject(message);

        department = demoJson.getJSONArray("department");



        is.close();

    } catch (Exception e) {

        e.printStackTrace();

    }

    return department;

通過瀏覽器直接訪問得到的字符串與我後臺通過httpURLConection方式得到的字符串進行比較發現後臺方式得到的字符串缺失了一部分,這就導致json字符串格式不完整,所以報這個錯誤。

一開始是懷疑HttpURLConection的get方法限制了獲得內容的長度,因爲在別的地方用post方式獲取過內容更多的數據。但是釘釘獲取所有部門只提供get方式。

後來在網上查閱了HttpURLConection的使用方式,其中一部分代碼讓我開始考慮是輸入輸出流導致的問題:

package com.cn.testproject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpConnectionUrlDemo {
    public static void main(String[] args) throws Exception {
        //get();
        post();
    }



    public static void get() throws Exception {
        String path = "http://www.baidu.com";
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setRequestMethod("GET");
        InputStream inStream = conn.getInputStream();
        byte[] data = toByteArray(inStream);
        String result = new String(data, "UTF-8");
        System.out.println(result);
    }



    public static void post() throws Exception {
        String encoding = "UTF-8";
        //post的form參數(json兼職對)
        String params = "[{\"addTime\":\"2011-09-19 14:23:02\"[],\"iccid\":\"1111\",\"id\":0,\"imei\":\"2222\",\"imsi\":\"3333\",\"phoneType\":\"4444\",\"remark\":\"aaaa\",\"tel\":\"5555\"}]";
        String path = "http://www.baidu.com";
        byte[] data = params.getBytes(encoding);
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);

        conn.setRequestProperty("Content-Type", "application/x-javascript; charset=" + encoding);
        conn.setRequestProperty("Content-Length", String.valueOf(data.length));
        conn.setConnectTimeout(5 * 1000);
        OutputStream outStream = conn.getOutputStream();
        outStream.write(data);
        outStream.flush();
        outStream.close();
        System.out.println(conn.getResponseCode()); // 響應代碼 200表示成功
        if (conn.getResponseCode() == 200) {
            InputStream inStream = conn.getInputStream();
            String result = new String(toByteArray(inStream), "UTF-8");
            System.out.println(result); // 響應代碼 200表示成功
        }
    }
    private static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }
}

這裏貼出我一開始輸入輸出流的處理代碼:

InputStream is = http.getInputStream();

int size = is.available();

byte[] jsonBytes = new byte[size];

is.read(jsonBytes);

String message = new String(jsonBytes, "UTF-8");

JSONObject demoJson =JSONObject.fromObject(message);

他所使用的的是通過toByteArray(InputStream input)方法對輸入流進行處理,每當輸入流input中有內容的時候(即返回值不等於-1)就將內容讀到byte數組buffer中,再從buffer中將內容寫到輸出流output中,最終將output轉換成數組返回。

剛開始看到這段代碼是很懵逼不能理解的,後來通過debug發現,while循環執行了3次,第一次n=1241,第二次n=198,第三次n=-1跳出循環。

這裏對於循環執行了3次恨不能理解,但是如果是執行三次的話,我原先的代碼出現問題的原因就是顯而易見的了。因爲我只執行了一次read,所以網頁上的數據我只讀到1241個字節,後面的198個字節並沒有讀取。所以會出現這種錯誤。

這裏順便貼出read()和read(byte[]) 的區別:

1:read() :
從輸入流中讀取數據的下一個字節,返回0到255範圍內的int字節值。如果因爲已經到達流末尾而沒有可用的字節,則返回-1。在輸入數據可用、檢測到流末尾或者拋出異常前,此方法一直阻塞。

2:read(byte[] b) :
從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。以整數形式返回實際讀取的字節數。在輸入數據可用、檢測到文件末尾或者拋出異常前,此方法一直阻塞。如果 b 的長度爲 0,則不讀取任何字節並返回 0;否則,嘗試讀取至少一個字節。如果因爲流位於文件末尾而沒有可用的字節,則返回值 -1;否則,至少讀取一個字節並將其存儲在 b 中。將讀取的第一個字節存儲在元素 b[0] 中,下一個存儲在 b[1] 中,依次類推。讀取的字節數最多等於 b 的長度。設 k 爲實際讀取的字節數;這些字節將存儲在 b[0] 到 b[k-1] 的元素中,不影響 b[k] 到 b[b.length-1] 的元素。

由幫助文檔中的解釋可知,read()方法每次只能讀取一個字節,所以也只能讀取由ASCII碼範圍內的一些字符。這些字符主要用於顯示現代英語和其他西歐語言。而對於漢字等unicode中的字符則不能正常讀取。只能以亂碼的形式顯示。

對於read()方法的上述缺點,在read(byte[] b)中則得到了解決,就拿漢字來舉例,一個漢字佔有兩個字節,則可以把參數數組b定義爲大小爲2的數組即可正常讀取漢字了。當然b也可以定義爲更大,比如如果b=new byte[4]的話,則每次可以讀取兩個漢字字符了,但是需要注意的是,如果此處定義b 的大小爲3或7等奇數,則對於全是漢字的一篇文檔則不能全部正常讀寫了。

兩者區別轉載自: > http://wentao365.iteye.com/blog/1374731

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章