androidbase64圖片-ag真人国际官网
① android webservice開發過程中 介面上需要的base64binary參數 我應該用什麼類型的參數去對應求答案
1、參考http://pointonline.iteye.com/blog/736356
byte[] d ; // d中存放需要傳遞的數據
string data = new string(base64.encode(d));
soapobject request= new soapobject(namespace, function);
request.addproperty(str,new soapprimitive(soapenvelope.enc,"base64binary",data));
2、我自己開發的項目中,直接傳遞的,也成功了
bytearrayoutputstream baos; // baos中存放需要傳遞的數據
// 進行base64編碼
string uploadbuffer = new string(base64.encode(baos.tobytearray()));
soapobject request= new soapobject(namespace, function);
request.addproperty(str,uploadbuffer );
② android 程序 從資料庫獲取的base64類型的字元串轉換成圖片 再通過hashmap 傳進入 但是圖片顯示不了
可以把bitmap圖片和base64字元串來互相轉換~ 從此媽媽再也不用擔心我處理bitmap啦~
/**
* 將bitmap轉換成base64字元串
*
* @param bitmap
* @return base64 字元串
*/
public string bitmaptostring(bitmap bitmap, int bitmapquality) {
// 將bitmap轉換成字元串
string string = null;
bytearrayoutputstream bstream = new bytearrayoutputstream();
bitmap.compress(compressformat.png, bitmapquality, bstream);
byte[] bytes = bstream.tobytearray();
string = base64.encodetostring(bytes, base64.default);
return string;
}
/**
* 將base64轉換成bitmap圖片
*
* @param string base64字元串
* @return bitmap
*/
public bitmap stringtobitmap(string string) {
// 將字元串轉換成bitmap類型
bitmap bitmap = null;
try {
byte[] bitmaparray;
bitmaparray = base64.decode(string, base64.default);
bitmap = bitmapfactory.decodebytearray(bitmaparray, 0,
bitmaparray.length);
} catch (exception e) {
e.printstacktrace();
}
return bitmap;
}
③ 如何查看android產生的異常
android程序如果出問題,因為實際是java程序,所以會拋出異常,比如這樣。
彈出的警告對話框中沒有異常信息,如果需要看到日誌內容,可執行:
「adb logcat」
即可見到異常信息。或者通過ddms,通過device》run logcat通過圖形界面查看日誌,和上面的命令效果一樣。(比如http://www.tiecou.com)
這是一個異常的內容:
w/dalvikvm(26121): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
e/androidruntime(26121): uncaught handler: thread main exiting e to uncaught exception
e/androidruntime(26121): java.lang.runtimeexception: unable to start activity componentinfo{com.easymorse.activity/com.easymorse.activity.activitytest}: java.lang.securityexception: requires read_phone_state: neither user 10032 nor current process has android.permission.read_phone_state.
e/androidruntime(26121): at android.app.activitythread.performlaunchactivity(activitythread.java:2268)
e/androidruntime(26121): at android.app.activitythread.handlelaunchactivity(activitythread.java:2284)
e/androidruntime(26121): at android.app.activitythread.access$1800(activitythread.java:112)
e/androidruntime(26121): at android.app.activitythread$h.handlemessage(activitythread.java:1692)
e/androidruntime(26121): at android.os.handler.dispatchmessage(handler.java:99)
e/androidruntime(26121): at android.os.looper.loop(looper.java:123)
e/androidruntime(26121): at android.app.activitythread.main(activitythread.java:3948)
e/androidruntime(26121): at java.lang.reflect.method.invokenative(native method)
e/androidruntime(26121): at java.lang.reflect.method.invoke(method.java:521)
e/androidruntime(26121): at com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:782)
e/androidruntime(26121): at com.android.internal.os.zygoteinit.main(zygoteinit.java:540)
e/androidruntime(26121): at dalvik.system.nativestart.main(native method)
e/androidruntime(26121): caused by: java.lang.securityexception: requires read_phone_state: neither user 10032 nor current process has android.permission.read_phone_state.
e/androidruntime(26121): at android.os.parcel.readexception(parcel.java:1234)
e/androidruntime(26121): at android.os.parcel.readexception(parcel.java:1222)
e/androidruntime(26121): at com.android.internal.telephony.iphonesubinfo$stub$proxy.getline1number(iphonesubinfo.java:223)
e/androidruntime(26121): at android.telephony.telephonymanager.getline1number(telephonymanager.java:498)
e/androidruntime(26121): at com.easymorse.activity.activitytest.oncreate(activitytest.java:18)
e/androidruntime(26121): at android.app.instrumentation.callactivityoncreate(instrumentation.java:1123)
e/androidruntime(26121): at android.app.activitythread.performlaunchactivity(activitythread.java:2231)
e/androidruntime(26121): … 11 more
④ android 圖片轉base64上傳提示java.lang.outofmemoryerror
我最近也碰到了這個問題,但是網上沒有找到相關有效的直接解決方法。
後來看到了一篇解釋base64編碼原理的文章,研究了一番後解決了。
一般碰到這個問題的,都涉及到"大文件上傳"的問題,"大文件上傳"過程中除了base64編碼時可能oom,其實還有其他問題,雖然提問中沒有提出,可能是因為這個問題還沒有解決,所以還沒有遇到其它問題,我就圍繞著"大文件上傳"來解決這個問題吧。
(提問時間在下看的清楚)
————————————————————
做項目的過程中碰到一個需求:
在java客戶端,使用http通信,把客戶端的本地文件通過http發送上傳到伺服器;
請求格式是xml(不管是json還是xml都是字元串,所以這個無所謂),中間包含[文件流字元串];
之前的做法是,把文件流通過base64編碼轉換為base64byte,然後和其它字元串信息放到一起,post的時候通過httpurlconnection的write方法寫入到伺服器中去,這個上傳的過程就完成了。
——————————
但是碰到一個問題,當文件體積較大時,從文件流轉換成base64byte後,體積會很大,可能會導致oom;
(以二進制流的方式保存,體積最小;以byte數組的方式保存,體積會相對變大一些;以string形式保存,體積最大;)
出錯原因是:
fileinputstream fis = new fileinputstream(file); //這一步打開了一個對准file准備進行讀取的文件指針,但是還沒有開始讀寫,file的相關數據沒有從本地載入到內存中來;所以即使file的體積有10g那麼大,這一步也是不會oom的
//把文件流轉換為位元組數組
byte[] filebytes;
bytearrayoutputstream baos = new bytearrayoutputstream();
byte[] bytebuf = new byte[1024];
int count;
while((count=fis.read(buf))!=-1)
{
baos.write(buf,0,count); //實際上,如果文件體積比較大的話,不用轉碼,在這一步就可能oom了
}
filebytes= baos.tobytearray();
byte[] base64bytes = base64.encodebase64(filebytes); //在這一步也可能oom
(文件轉換為byte[]時,是有可能oom的;而轉換為base64bytes後,體積會增大1/3,所以有可能前一步沒有oom,卻在這一步出現oom;
為什麼轉碼後體積會增大1/3,後面我會解釋)
——————————
解決方法
既然file在本地沒有載入到內存來的時候不會出現內存溢出的情況,我就想到了一個解決的方法:分段上傳
(加大內存並不能從根本上解決內存溢出的問題,問題的根本原因不是內存不夠大,而是代碼有問題)
在本地的file通過httpurlconnection的getoutputstream()進行write時,不是一次性全部寫入,而是循環配合flush進行寫入:
fileinputstream fis = new fileinputstream(file);
byte[] buf = new byte[1024];
int count;
while((count = fis.read(buf)) != -1)
{
os.write(base64.encodebase64(buf), 0, count);
os.flush();
}
(我從本地讀1024位元組,然後馬上上傳到伺服器,清空本地緩存,然後再從本地讀1024位元組,這樣循環讀取,即使文件有20g,理論上也不有oom問題出現,因為我從本地文件中讀到的數據不會在內存中駐留)
——————————
解決問題的思路對了,但是出現了其他的細節問題
os.write(base64.encodebase64(buf), 0, count); //這一行代碼報錯了,出現了oom
我搜集了一下資料,發現原因是:
httpurlconnection的getoutputstream的實際對象是sun.net.,這個對象的flush方法代碼是空的,write配合flush,並沒有達到即時上傳數據的效果。posteroutputstream其實是自己在本地維護了一個緩沖區,你通過write寫入的數據其實還是在這個本地的緩沖區里,只有當你getinputstream後,httpurlconnection才會把這段緩沖區中的數據上傳到伺服器上。而flush達不到上傳數據,清空本地緩存的效果。
——————————
(我是不能通過getinputstream來刷新緩沖流的,因為那就不是分段上傳而是"分次"上傳了)
那這就不是我的思路的問題了。再去搜索解決方法後,得知:
在創建httpurlconnection對象的時候,要調用一個方法
hurlc.setchunkedstreamingmode(1024); //設置分塊流模式 也就是分塊上傳 1024是getoutputstream維護的本地緩沖區的大小
調用該方法後,只要本地緩存區滿了,httpurlconnection就會自動把緩沖區里的數據發送到伺服器,同時清空本地緩存(ps:httpurlconnection的getoutputstream似乎是個抽象的工廠方法,在調用setchunkedstreamingmode方法後,我發現getoutputstream獲取到的實例對象從sun.net.變成了sun.net.)
——————————
果然,調用setchunkedstreamingmode方法後,os.write(base64.encodebase64(buf), 0, count);沒有再出現oom異常了
但是,又出現了一個新的問題
我發現
fileinputstream fis = new fileinputstream(file);
byte[] buf = new byte[1024];
int count;
while((count = fis.read(buf)) != -1)
{
os.write(base64.encodebase64(buf), 0, count);
os.flush();
}
這段分段編碼寫入的代碼,其編碼所得結果,與非分段編碼所得結果是不一樣的
通過分段編碼上傳的圖片內容出現了錯誤
我通過下面代碼測試:
//分段編碼
bytearrayoutputstream os1 = new bytearrayoutputstream();
inputstream file1 = new fileinputstream(path);
byte[] buf1 = new byte[1024];
int count1;
while((count1 = file1.read(buf1)) != -1)
{
os1.write(base64.encodebase64(buf1), 0, count1);
os1.flush();
}
file1.close();
system.out.println(os1.tostring());
//非分段編碼
bytearrayoutputstream os2 = new bytearrayoutputstream();
inputstream file2 = new fileinputstream(path);
byte[] buf2 = new byte[1024];
int count2;
while((count2 = file2.read(buf2)) != -1)
{
os2.write(buf2, 0, count2);
os2.flush();
}
file2.close();
system.out.println(new string(base64.encodebase64(os2.tobytearray())));
兩者的結果:
/9j/4aaqskzjr...wdtuavs7ef...
/9j/4aaqskzjr...wdt89ymnxj...
前面一段還是相同的,轉到後面,就開始南轅北轍了
——————————
原因我去網上找了一下但是沒有找到直接答案,但是看到一篇解釋base64編碼原理的文章
原文鏈接:
假設有文件a(txt文件,包含文本內容"abcdefg"),轉換為inputstream->byte[]後
它們的asiic碼分別對應65、66、67、68、69、70、71
二進製表現形式為:
1000001 1000010 1000011 1000100 1000101 1000110 1000111
對高位補零後:
01000001 01000010 01000011 01000100 01000101 01000110 01000111
在內存中的實際表現:
而base64編碼,使用的字元包括(a-z、a-z、0-9、 、/、=)這些常規可讀字元,使用base64編碼的原因,用途,在於把一些亂碼字元、不可讀字元轉換為常規可讀字元;
(因為java底層的通信協議、或者說其它的通信協議,很多地方用到遠程通信這一塊的,對一些亂碼字元不支持傳輸,所以需要把亂碼字元轉換成常規可讀字元才能進行傳輸)
比如對於'矙'這個字元,部分傳輸協議的編碼集就不認識它,所以無法直接傳輸,必須base64轉碼
'矙'的utf-8編碼值為30681,二進製表現形式為111011111011001->(0)111011111011001
需要兩個位元組來存儲01110111 11011001
base64編碼只有(a-z、a-z、0-9、 、/、=)這些字元來表示。需要強調的是,在base64編碼規范中,字元'a'不等於65、'b'也不是66...。base64字元與數值(二進制值)的對應關系如下:
也就是說,常規字元'a'=65=01000001;而base64字元'a'=0=00000000;
base64字元代表的二進制值是無法直接表示'矙'這個字元的,因為base64字元的值范圍在0~63之間(二進制值在(00)000000~(00)111111之間)。
那如何通過(00)000000~(00)111111之間的數值來表示01110111 11011001呢?
這就是base64的編碼演算法了
一個base64字元的二進制值在(00)000000~(00)111111之間,也就是說它可以表示000000~111111之間的二進制數,一個base64字元的有效位為後6位。如何通過以6bit為單位的base64字元表示以8bit為單位的常規位元組?
6和8的最小公倍數為24,即 每4個base64字元可以表示3個常規位元組;
回到剛才的文件a,編碼過程:
(初始文件a)->"abcdefg"
(轉utf-8碼 int)->65 66 67 68 69 70 71
("abcdefg"的二進製表示;7位元組)->1000001 1000010 1000011 1000100 1000101 1000110 1000111
(高位補零)->01000001 01000010 01000011 01000100 01000101 01000110 01000111
(連寫)->
(按6bit為單位對所有bit進行分割;得到10位元組)->010000 010100 001001 000011 010001 000100 010101 000110 010001 11
(按6bit*4=8bit*3的對應關系再分割;得到3組6*4位元組)->(010000 010100 001001 000011) (010001 000100 010101 000110) (010001 11)
(高位補2個零;末尾的低位也補零)->(00010000 00010100 00001001 00000011) (00010001 00000100 00010101 00000110) (00010001 00110000)
(二進制值換算成十進制)->(16 20 9 3) (17 4 21 6) (17 48)
(按base64編碼的值-字元對應表,得出上面的十進制值對應的base64字元)->(q u j d) (r e v g) (r w)
(每組base64字元都要求是4個,空白的位置補'='字元)->(q u j d) (r e v g) (r w = =)
(文件a的最終轉碼結果)->qujdrevgrw==
這里以文本文件作為演示,因為文本文件機器可讀人也可讀;實際情況中,很多時候轉碼的目標文件並不是文本文件,那就不能以可讀字元串形式表示了,會直接以二進制格式表示
體積增大的原因,是因為3位元組=24bit=分割成4個6bit-,對4個6bit高位補零後,就得到4個位元組
也就是說3個常規位元組經base64編碼後會生成4個base64位元組,這就是文件經base64轉碼後體積會增加1/3的原因
——————————
base64編碼原理解釋了,再看剛才的分段編碼
bytearrayoutputstream os1 = new bytearrayoutputstream();
inputstream file1 = new fileinputstream(path);
byte[] buf1 = new byte[1024];
int count1;
while((count1 = file1.read(buf1)) != -1)
{
os1.write(base64.encodebase64(buf1), 0, count1); //可以發現一個問題:base64.encodebase64(buf1)編碼後,體積會增加1/3,所以這里的base64.encodebase64(buf1)編碼轉換後的實際長度和count1並不相等,所以實際寫入到os1中的base64字元數只有base64.encodebase64(buf1)編碼產生的字元數的3/4
os1.flush();
}
file1.close();
system.out.println(os1.tostring());
修改後:
bytearrayoutputstream os1 = new bytearrayoutputstream();
inputstream file1 = new fileinputstream(path);
byte[] bytebuf = new byte[1024];
byte[] base64bytebuf;
while(file1.read(bytebuf) != -1)
{
base64bytebuf = base64.encodebase64(bytebuf);
os1.write(base64bytebuf, 0, base64bytebuf.length);
os1.flush();
}
file1.close();
system.out.println(os1.tostring());
——————————
修改後,發現分段編碼的結果發生了變化,跟之前不一樣了
但仍然不是正確的結果
原因在於,base64字元的基礎單位是(6bit*4=4位元組),而3個常規位元組(8bit*3)才能剛好產生4個base64位元組
根本原因在於,如果進行編碼的常規位元組數不是3的倍數,最後就會餘下1或2個位元組,而這1、2個位元組編碼的結果就會產生'='字元;
使用1024作為分段編碼緩沖時,編碼的結果是3 3 3 ... 1
也就是每次都會餘1位元組
而沒有使用分段編碼時,當編碼到第1024個位元組時,"餘下"的1位元組會跟後面的位元組形成連續,就不會產生'='字元
(對一段byte字元進行base64編碼時,中間是絕不會產生'='字元的,因為只有在結尾才可能餘下1或2個位元組,所以對一段byte字元進行編碼時,只有結尾才可能產生1或2個'='補全字元)
——————————
解決方法是,使用3的公倍數作為緩沖區大小
修改後:
bytearrayoutputstream os1 = new bytearrayoutputstream();
inputstream file1 = new fileinputstream(path);
byte[] bytebuf = new byte[3*1000];
byte[] base64bytebuf;
while(file1.read(bytebuf) != -1)
{
base64bytebuf = base64.encodebase64(bytebuf);
os1.write(base64bytebuf, 0, base64bytebuf.length);
os1.flush();
}
file1.close();
system.out.println(os1.tostring());
測試結果再次發生了改變
中間不再有'='字元了,因為中間每次都是3位元組3位元組的編碼,沒有餘下多餘的位元組
對比之後發現,中間段的結果已經正常了
——————————
但是,發現,結尾處兩個轉碼的結果有些許不同
原因在於,假設文件a的長度為3001個位元組;
在第二次循環讀取時,只讀到1個有效位元組,而bytebuf的剩餘2999個位元組都是無效位元組,而此時編碼時,卻把多餘的2999個無效位元組也編碼了進去
(如果是非分段轉碼,就不會出現這種情況)
解決方法:
bytearrayoutputstream os1 = new bytearrayoutputstream();
inputstream file1 = new fileinputstream(path);
byte[] bytebuf = new byte[3*1000];
byte[] base64bytebuf;
int count1; //每次從文件中讀取到的有效位元組數
while((count1=file1.read(bytebuf)) != -1)
{
if(count1!=bytebuf.length) //如果有效位元組數不為3*1000,則說明文件已經讀到尾了,不夠填充滿bytebuf了
{
byte[] = arrays.of(bytebuf, count1); //從bytebuf中截取包含有效位元組數的位元組段
base64bytebuf = base64.encodebase64(); //對有效位元組段進行編碼
}
else
{
base64bytebuf = base64.encodebase64(bytebuf);
}
os1.write(base64bytebuf, 0, base64bytebuf.length);
os1.flush();
}
file1.close();
system.out.println(os1.tostring());
至此,base64分段編碼才算大功告成。大文件上傳核心代碼才算大功告成。
其實代碼改起來非常簡單,但是不知道原因不知道原理的話,是無法無中生有的
對我本人來說原本只是想隨便答一下,但沒想到答的過程中發現自己有很多坑沒有發現。答的過程中把自己不懂的地方沒有發現的坑也完善了。不說碰到一個知識點就要追根究底,但實際開發中,每一個自己能親身碰到的實際問題都是鍛煉自己的絕佳機會,這種近距離觸碰問題、解決問題的機會是難得的。雖然開發中還有很多其它問題也很重要,但你沒有親手碰到過,是無法共鳴的。所以自己在開發中碰到了問題,還是建議大概弄清原因。
弄清原理後,即使以後出現這個問題的其它"變種",也能找到原因並自己解決,但僅僅粘貼復制無法做到這一點。
⑤ android base64.decode 報錯
android 解碼 base64 圖片數據時報錯
data:image/jpeg;base64,/9j/4aaqskzjrgabaqeakacqaad/axndq0hyc5ptgypc4zndl/iymjiymjiymjiymjiymjl/waarcak2ayadasiaahebaxeb//8
base64.decode(data, base64.default)
經過測試把開頭的 data:image/jpeg;base64, 去掉就好了
⑥ android ,base64轉bitmap
1 把圖像文件讀如byte數組中。
2 然後調用encodebase64函數,把byte數組傳入,函數返回base64的字元串。
以上即可完成base64轉換。
反方向
1 然後調用decodebase64函數,把byte64字元串傳入,函數返回byte數組。
2 把bye數組內容寫入文件,文件名為bitmap點陣圖的bpm文件即可。
⑦ android 將圖片轉成base64,小圖片可以正常轉換,當遇到大圖片是拿到的字元串是null
因為太大了,一般超過2m就不要用這種方式直接存儲處理圖片,建議使用縮略圖。
⑧ android,base64.encodetostring(bitmapbytes, base64.default);內存溢出
如果圖片過大的話,分幾次讀取圖片,每次讀取到數組後轉碼成string,轉碼完成後再拼接string,建議轉換完成的string存儲到文件中,畢竟轉碼後會比源文件到了不少,也會內存溢出吧;如果要上傳文件,每次轉碼完成發送一次,只要服務端處理好就沒有問題,文件不會出錯的。望採納。