Java程序設(shè)計(jì)第章文件和流解讀_第1頁
Java程序設(shè)計(jì)第章文件和流解讀_第2頁
Java程序設(shè)計(jì)第章文件和流解讀_第3頁
Java程序設(shè)計(jì)第章文件和流解讀_第4頁
Java程序設(shè)計(jì)第章文件和流解讀_第5頁
已閱讀5頁,還剩68頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第八章文件和流圖形圖像研究所計(jì)算機(jī)科學(xué)與技術(shù)、軟件學(xué)院

浙江工業(yè)大學(xué)高飛,陸佳煒等。Java程序設(shè)計(jì)實(shí)用教程。北京:清華大學(xué)出版社,2021〔ISBN:978-7-302-31695-4)高飛,趙小敏等。Java程序設(shè)計(jì)實(shí)用教程習(xí)題集。北京:清華大學(xué)出版社,2021〔ISBN:978-7-302-32051-7)高飛教授,博士生導(dǎo)師Tel.RL:://前言本章的目的:什么是流?什么是字節(jié)流和字符流?如何訪問磁盤上的文件屬性?如何將對象保存到磁盤文件中〔對象序列化〕?Java中亂碼問題是如何形成的?回憶關(guān)鍵詞:用戶的輸入是邪惡的!Try-catch-finally、throws、throw小節(jié)安排文件和流8.2.1輸入字節(jié)流:InputStream8.3、字符流8.4、文件8.2.2輸出字節(jié)流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節(jié)流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節(jié)流和字符流的異同8.1、流的根本概念8.2、字節(jié)流8.2、字節(jié)流輸入字節(jié)流:InputStreamInputStream類常用的public方法方法定義功能說明abstractintread()throwsIOException讀一個(gè)字節(jié)并按int類型返回intread(byte[]

b)throwsIOException將數(shù)據(jù)讀入byte[],返回實(shí)際讀取的字節(jié)數(shù)intread(byte[]

b,int

off,int

len)throwsIOException讀取最多l(xiāng)en個(gè)字節(jié)到數(shù)組b中,返回實(shí)際讀取數(shù)量publiclongskip(long

n)throwsIOException跳過n個(gè)字節(jié)publicvoidclose()throwsIOException關(guān)閉輸入流并釋放與該流有關(guān)聯(lián)的系統(tǒng)資源8.2、字節(jié)流/*從mytext.txt文件讀出并顯示在屏幕上*/importjava.io.*;publicclassFileIn{publicstaticvoidmain(Stringargs[]){try{FileInputStreamrf=newFileInputStream("H:/java/temp/mytext.txt");//翻開文件intb;while((b=rf.read())!=-1)//用read()方法逐個(gè)字節(jié)讀取 System.out.print((char)b);//轉(zhuǎn)換成char并顯示rf.close();}catch(IOExceptionie){System.out.println(ie);}catch(Exceptione){System.out.println(e);}}}8.2、字節(jié)流輸出字節(jié)流:OutputStreamOutputStream類常用的public方法方法定義功能說明abstractvoidwrite(int

b)throwsIOException將一個(gè)字節(jié)b輸出,根據(jù)java規(guī)定,實(shí)際輸出的是參數(shù)b的低8位,其余24個(gè)高位將被忽略。例如,若b=825373492,即十六進(jìn)制0x31323334,則只輸出低8位即0x34,即最后輸出為字符'4'voidwrite(byte[]

b)throwsIOException將數(shù)組b逐字節(jié)輸出voidwrite(byte[]

b,int

off,int

len)throwsIOException將數(shù)組b中從off開始的len個(gè)字節(jié)輸出8.2、字節(jié)流/*以下例如用于說明如何利用FileOutputStream進(jìn)行文件復(fù)制*/importjava.io.*;publicclassTestFileCopy{publicstaticvoidmain(Stringargs[]){try{//復(fù)制的源文件TestVector.javaFileInputStreamrf=newFileInputStream("G:/java/TestVector.java");//復(fù)制的目的文件TV2.txt,假設(shè)不存在,那么會(huì)自動(dòng)創(chuàng)立FileOutputStreamwf=newFileOutputStream("G:/java/TV2.txt");byteb[]=newbyte[512];intcount=-1;//每次讀取512個(gè)字節(jié),count用于記錄實(shí)際讀取的字節(jié)數(shù)while((count=rf.read(b,0,512))!=-1)wf.write(b,0,count);rf.close();wf.close();}catch(IOExceptionie){System.out.println(ie.toString());}catch(Exceptione){System.out.println(e.toString());}}}小節(jié)安排文件和流8.2.1輸入字節(jié)流:InputStream8.3、字符流8.4、文件8.2.2輸出字節(jié)流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節(jié)流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節(jié)流和字符流的異同8.3、字符流8.3、字符流輸入字符流:ReaderReader類常用的public方法方法定義功能說明intread()throwsIOException讀單個(gè)字符,以int類型返回intread(char[]cbuf)throwsIOException讀字符放入數(shù)組cbuf中intread(char[]cbuf,intoffset,intlength)throwsIOException讀字符放入數(shù)組的指定位置booleanready()throwsIOException測試當(dāng)前流是否準(zhǔn)備好進(jìn)行讀voidclose()關(guān)閉流longskip(longn)跳過n個(gè)字符8.3、字符流/*讀取G:/aillo.txt文件的內(nèi)容(一行一行讀),并將其內(nèi)容寫入G:/jacky.txt中知識(shí)點(diǎn):java讀文件、寫文件---<以字符流方式>*/importjava.io.*;publicclassTestFileWR{publicstaticvoidmain(String[]args){try{//創(chuàng)立FileReader對象,用來讀取字符流FileReaderfr=newFileReader("G:/aillo.txt");//緩沖指定文件的輸入BufferedReaderbr=newBufferedReader(fr);//創(chuàng)立FileWriter對象,用來寫入字符流FileWriterfw=newFileWriter("G:/jacky.txt");//將緩沖對文件的輸出BufferedWriterbw=newBufferedWriter(fw);StringstrLine;//用來保存每次讀取的一行8.3、字符流while(br.ready()){strLine=br.readLine();//讀取一行bw.write(strLine);//寫入文件bw.newLine();System.out.println(strLine);//在屏幕上輸出}bw.flush();//刷新該流的緩沖,即將該流輸出到目的bw.close();br.close();fw.close();fr.close();}catch(IOExceptione){e.printStackTrace();}}}8.3、字符流輸出字符流:WriterWriter類常用的public方法方法定義功能說明intwrite(intc)throwsIOException輸出單個(gè)字符。要輸出的字符c包含在給定整數(shù)值的16個(gè)低位中,16高位被忽略。例如,若b=825360437,即十六進(jìn)制0x31320035,則只輸出低16位即0x0035(為字符'5'的ASCII碼),即最后輸出為字符'5'intwrite(char[]cbuf)throwsIOException輸出字符數(shù)組cbufintwrite(char[]cbuf,intoffset,intlen)throwsIOException將字符數(shù)組中從offset開始的len個(gè)字符輸出intwrite(Stringstr)throwsIOException輸出字符串strintwrite(Stringstr,intoffset,intlength)throwsIOException輸出字符串str中從offset開始的len個(gè)字符abstractvoidclose()關(guān)閉輸出字符流abstractvoidflush()強(qiáng)行寫8.3、字符流/*從鍵盤輸入一行文字,寫入文件TestFileOut.txt中*/importjava.io.*;publicclassTestFileOut{publicstaticvoidmain(Stringargs[]){charc[]=newchar[512];byteb[]=newbyte[512];intn,i;try{FileWriterwf=newFileWriter("TestFileOut.txt");//從鍵盤讀入文字并存入字節(jié)數(shù)組b中n=(b);for(i=0;i<n;i++)c[i]=(char)b[i];wf.write(c);wf.close();}catch(IOExceptione){System.out.println(e);}}}輸入"123456ABCDEF"并回車輸入"Java是一門優(yōu)秀的語言!"并回車8.3、字符流/*從鍵盤輸入一行文字〔可輸入中文字符〕,寫入文件TestFileOut.txt中*/importjava.io.*;publicclassTestFileOutCH{publicstaticvoidmain(Stringargs[]){charc[]=newchar[512];intn,i;try{FileWriterwf=newFileWriter("TestFileOutCH.txt");//利用InputStreamReader正確讀取中文("請輸入中文:");InputStreamReaderisr=newInputStreamReader(System.in);n=isr.read(c,0,512);//一次性讀取512個(gè)字符,n表示實(shí)際讀取的字符數(shù)wf.write(c);wf.close();("剛輸入的數(shù)據(jù)為:"+String.valueOf(c,0,n));}catch(IOExceptione){System.out.println(e);}}}8.3、字符流字符緩沖流:BufferedReader和BufferedWriter以緩沖區(qū)方式對數(shù)據(jù)進(jìn)行輸入輸出。所謂緩沖區(qū),是指一片臨時(shí)的內(nèi)存區(qū)域。BufferedReader和BufferedWriter分別擁有8192個(gè)字符(16384個(gè)字節(jié))的緩沖區(qū)。當(dāng)BufferedReader從源〔文件、網(wǎng)絡(luò)、鍵盤或其他進(jìn)程〕讀取字符數(shù)據(jù)時(shí),會(huì)先盡量從源中讀入字符數(shù)據(jù)并置入緩沖區(qū),而之后假設(shè)使用read()方法,會(huì)先從緩沖區(qū)中進(jìn)行讀取。如果緩沖區(qū)數(shù)據(jù)缺乏,才會(huì)再從源中讀取。使用BufferedWriter時(shí),寫入的數(shù)據(jù)并不會(huì)先輸出到目的地,而是先存儲(chǔ)至緩沖區(qū)中。如果緩沖區(qū)中的數(shù)據(jù)滿了,才會(huì)一次對目的地進(jìn)行寫入。例如一個(gè)文件,通過緩沖區(qū)可減少對硬盤的輸入/輸出動(dòng)作,以提高文件存取的效率。8.3、字符流/*本程序首先在控制臺(tái)輸入字符(逐行輸入),程序?qū)⑤斎氲奈淖执鎯?chǔ)至指定的文件中,如果要結(jié)束程序,輸入quit字符串即可。*/importjava.util.*;importjava.io.*;publicclassTestFileBRW{publicstaticvoidmain(String[]args){try{//緩沖System.in輸入流//System.in是字節(jié)流,通過InputStreamReader將其轉(zhuǎn)換為字符流BufferedReaderbufReader=newBufferedReader(newInputStreamReader(System.in));//緩沖FileWriterBufferedWriterbufWriter=newBufferedWriter(newFileWriter(args[0]));Stringinput=null;//每讀一行進(jìn)行一次寫入動(dòng)作while(!(input=bufReader.readLine()).equals("quit")){bufWriter.write(input);8.3、字符流/*newLine()方法寫入與操作系統(tǒng)相依的換行字符,依執(zhí)行環(huán)境當(dāng)時(shí)的OS來決定該輸出那種換行字符*/bufWriter.newLine();}bufReader.close();bufWriter.close();}catch(ArrayIndexOutOfBoundsExceptione){("沒有指定文件");}catch(IOExceptione){e.printStackTrace();}}}8.3、字符流字節(jié)流和字符流的異同本質(zhì)區(qū)別在于byte和char。字節(jié)流采用二進(jìn)制直接傳輸,用字符流那么牽涉到本地系統(tǒng)的編碼問題,在網(wǎng)絡(luò)通訊中,強(qiáng)烈建議使用byte字節(jié)流方式。字節(jié)流與字符之間的轉(zhuǎn)化通過

InputStreamReader和OutputStreamWriter來關(guān)聯(lián),實(shí)際上是通過byte[]和String來關(guān)聯(lián)。在實(shí)際開發(fā)中出現(xiàn)的漢字問題實(shí)際上都是在字符流和字節(jié)流之間轉(zhuǎn)化不統(tǒng)一而造成的。在從字節(jié)流轉(zhuǎn)化為字符流時(shí),也就是從byte[]轉(zhuǎn)化為String時(shí),使用如下構(gòu)造方法: public

String(byte

bytes[],

String

charsetName) 這個(gè)方法中有一個(gè)關(guān)鍵的字符集編碼參數(shù)charsetName,通常我們都省略了,那系統(tǒng)就用操作系統(tǒng)的默認(rèn)的language。而在字符流轉(zhuǎn)化為字節(jié)流時(shí),實(shí)際上是String轉(zhuǎn)化為byte[]時(shí),是使用如下方法進(jìn)行轉(zhuǎn)化: byte[]

String.getBytes(String

charsetName)字符流和字節(jié)流是根據(jù)處理數(shù)據(jù)的不同來區(qū)分的。字節(jié)流按照8位傳輸,字符流按照16位傳輸由于字符流使用Unicode字符集,支持多國文字,因此假設(shè)流要跨越多種平臺(tái)傳輸,應(yīng)使用字符流。字符流的傳輸效率比字節(jié)流的高。小節(jié)安排文件和流8.2.1輸入字節(jié)流:InputStream8.3、字符流8.4、文件8.2.2輸出字節(jié)流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節(jié)流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節(jié)流和字符流的異同、文件File文件相關(guān)屬性例如://假設(shè)當(dāng)前目錄為G:/Java1,有文件"G:/Java1/TestFilePRO.java"和目錄//"G:/Java1/gfei"Filef=newFile("TestFilePRO.java");Filed=newFile("Gfei");

System.out.println("f.getName="+f.getName());//輸出TestFilePRO.javaSystem.out.println("f.getPath="+f.getPath());////輸出TestFilePRO.java//以下語句輸出G:\Java1\TestFilePRO.javaSystem.out.println("f.getAbsolutePath="+f.getAbsolutePath());System.out.println("f.getParent="+f.getParent());//輸出nullSystem.out.println("f.length="+f.length());//筆者例如中輸出668System.out.println("d.getName="+d.getName());//輸出GfeiSystem.out.println("d.getPath="+d.getPath());//輸出GfeiSystem.out.println("d.getAbsolutePath="+d.getAbsolutePath());//輸出G:\java1\GfeiSystem.out.println("d.getParent="+d.getParent());//輸出nullSystem.out.println("d.length="+d.length());//輸出0、文件File文件操作例如:Fileds=newFile("subdir");Filedd=newFile("gfei1");Filefs=newFile("TestFileSRC.java");Filefd=newFile("TestFileDEST.txt");ds.renameTo(dd);//改為gfei1fs.renameTo(fd);//改為TestFileDEST.txtpublicbooleanrenameTo(File

dest)//重新命名文件或目錄//刪除文件或目錄。如果是目錄,那么該目錄必須為空才能刪除。publicbooleandelete()、文件目錄操作publicbooleanmkdir()//創(chuàng)立目錄publicString[]list()//返回一個(gè)字符串?dāng)?shù)組,是給定目錄下的文件與子目錄publicFile[]listFiles()////返回File對象數(shù)組,是給定目錄下的文件、文件/*打印某目錄下(包含子目錄)所有文件和文件大小*/importjava.io.*;publicclassTestFileLIST{publicstaticvoidmain(Stringargs[])throwsIOException{Filefiles=newFile(".");//"."表示當(dāng)前目錄(與TestFileLIST.java所在的同一個(gè)目錄)listPath(files);}publicstaticvoidlistPath(Filef)throwsIOException{Stringfile_list[]=f.list();for(inti=0;i<file_list.length;i++){Filecf=newFile(f.getPath(),file_list[i]);if(cf.isDirectory()){//判斷是否為子目錄 listPath(cf);//列舉該子目錄下的文件}if(cf.isFile()){//判斷是否為文件try{//輸出文件大小System.out.println(cf.getCanonicalPath()+":"+cf.length());}catch(IOExceptione){e.printStackTrace();}}}}}、隨機(jī)訪問文件類:RandomAccessFileRandomAccessFile類提供了對文件的隨機(jī)訪問方式,即可在文件的任意位置讀或?qū)憯?shù)據(jù)而且可以同時(shí)進(jìn)行讀和寫的操作RandomAccessFile構(gòu)造方法及常用的方法方法定義功能說明RandomAccessFile(Filefile,Stringmode)throwsFileNotfoundExceptionfile待訪問的文件,mode設(shè)定訪問方式:"r"表示只讀,"w"表示寫,"rw"表示讀寫RandomAccessFile(Stringname,Stringmode)throwsFileNotfoundExceptionname是文件名字符串longlength()throwsIOException返回文件的長度,以字節(jié)為單位voidseek(longpos)throwsIOException改變文件指針的位置finalintreadInt()throwsIOException讀一個(gè)整型數(shù)據(jù)finalvoidwriteInt(intv)throwsIOException寫入一個(gè)整型數(shù)據(jù)longgetFilePointer()throwsIOException返回文件指針的位置close()throwsIOException關(guān)閉文件、隨機(jī)訪問文件類:RandomAccessFile提供了類似于readInt()的其他方法用于讀取byte、boolean、char、double、float、long、short、unsignedbyte、unsignedshort等數(shù)據(jù)類型的方法,即readByte()、readBoolean()、readChar()、readDouble()、readFloat()、readLong()、readShort()、readUnsignedByte()、readUnsignedShort()等提供了writeByte()、writeBoolean()、writeChar()、writeDouble()、writeFloat()、writeLong()、writeShort()等方法用于寫入數(shù)據(jù)。、隨機(jī)訪問文件類:RandomAccessFile/*向文件中寫入10個(gè)數(shù)據(jù),第i個(gè)數(shù)據(jù)=圓周率*i(i=0,1,2,…,9),然后將第2個(gè)(i=2)改為0,最后將10個(gè)數(shù)據(jù)全部輸出*/import;import;publicclassTestFileRAF{publicstaticvoidmain(Stringargs[]){try{RandomAccessFilef=new RandomAccessFile("TestFileRAF.txt","rw");//可讀寫inti;doubled;//寫:向文件寫入10個(gè)數(shù)據(jù)for(i=0;i<10;i++)f.writeDouble(Math.PI*i);、隨機(jī)訪問文件類:RandomAccessFile//修改:對文件中第2個(gè)double數(shù)據(jù)改為0f.seek(16);//文件指針往前走16個(gè)字節(jié)(2個(gè)double數(shù)據(jù))f.writeDouble(0);f.seek(0);//文件指針回到文件首部//讀?。簩⑷繑?shù)據(jù)讀出并打印到屏幕中for(i=0;i<10;i++){d=f.readDouble();("["+i+"]:"+d);}f.close();}catch(IOExceptione){("發(fā)生異常:"+e);e.printStackTrace();}}}、隨機(jī)訪問文件類:RandomAccessFile、文件過濾接口:FileFilter和FilenameFilterFileFilter和FilenameFilter是為開發(fā)者提供在文件系統(tǒng)中進(jìn)行過濾或者說是搜索所需要文件的功能,均有accept()方法:

//FileFilter:file表示要過濾目錄中的文件對象

publicboolean

accept(Filefile);/*FilenameFilter:參數(shù)dir是要過濾的目錄,

name是目錄中的文件名*/publicboolean

accept(Filedir,Stringname);區(qū)別:FileFilter提供文件對象的訪問方法,而FilenameFilter是按照目錄和文件的名稱的方式來工作。、文件過濾接口:FileFilter和FilenameFilter實(shí)現(xiàn)文件或目錄過濾所需步驟聲明一個(gè)過濾器類并實(shí)現(xiàn)FileFilter或FilenameFilter接口中的accept方法。使用File類的list()和listFiles()進(jìn)行過濾,其參數(shù)為第①步中的過濾器類的對象作為參數(shù),就可實(shí)現(xiàn)對文件名的過濾。File類的list()和listFiles()方法聲明如下:publicString[]list(FilenameFilterfilter)publicFile[]listFiles(FilenameFilterfilter)publicFile[]listFlies(FileFilterfilter)

其中,filter須是第①步中實(shí)現(xiàn)了FileFilter或FilenameFilter接口中的accept方法的過濾器類的對象。、文件過濾接口:FileFilter和FilenameFilterimportjava.io.*;//第①步:聲明過濾類ListFilter并實(shí)現(xiàn)FilenameFilter接口中的accept方法classListFilterimplementsFilenameFilter{privateStringpre=“〞,ext=“〞;//pre表示文件前綴,ext表示文件后綴publicListFilter(Stringfilterstr){inti,j;filterstr=filterstr.toLowerCase();i=filterstr.indexOf("*");j=filterstr.indexOf(".");if(i>0)pre=filterstr.substring(0,i);if(i==-1&j>0)pre=filterstr.substring(0,j);if(j>=0)ext=filterstr.substring(j+1);}、文件過濾接口:FileFilter和FilenameFilter//實(shí)現(xiàn)accept方法publicbooleanaccept(Filedir,Stringfilename){booleany=true;try{filename=filename.toLowerCase();y=filename.startsWith(pre)&filename.endsWith(ext);}catch(NullPointerExceptione){}returny;}}、文件過濾接口:FileFilter和FilenameFilter//第②步:使用File類的list()和listFiles()進(jìn)行過濾publicclassTestFileSearch{publicstaticvoidmain(Stringargs[]){//要求兩個(gè)參數(shù):第一個(gè)參數(shù)表示目錄,第二參數(shù)表示要過濾的文件StringstrDir,strExtension;switch(args.length){case1:strDir=".";strExtension=args[0];break;case2:strDir=args[0];strExtension=args[1];break;default:("需兩個(gè)參數(shù)!");return;} Filef=newFile(strDir);ListFilterls=newListFilter(strExtension);Stringstr[]=f.list(ls);for(inti=0;i<str.length;i++)System.out.println(str[i]);}}小節(jié)安排文件和流8.2.1輸入字節(jié)流:InputStream8.3、字符流8.4、文件8.2.2輸出字節(jié)流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節(jié)流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節(jié)流和字符流的異同8.5、對象序列化什么是對象序列化保存內(nèi)存中某個(gè)對象的方法很多,但是Java給你提供一種更好的保存對象狀態(tài)的機(jī)制,那就是對象序列化。java中對象序列化的過程就是將對象寫入字節(jié)流和從字節(jié)流中讀取對象。將對象狀態(tài)轉(zhuǎn)換成字節(jié)流之后,可以保存到文件、通過管道輸出到另一線程或通過網(wǎng)絡(luò)連接將對象數(shù)據(jù)發(fā)送到另一主機(jī)。8.5、對象序列化什么情況下需要序列化把內(nèi)存中的對象保存到一個(gè)文件中或者數(shù)據(jù)庫中用套接字(socket)在網(wǎng)絡(luò)上傳送對象通過RMI傳輸對象8.5、對象序列化實(shí)現(xiàn)序列化的步驟第一步:創(chuàng)立一個(gè)FileOutputStream對象,如下:FileOutputStreamfs=newFileOutputStream("foo.ser");第二步:負(fù)責(zé)將對象寫入字節(jié)流。因此第二步是利用第一步創(chuàng)立的FileOutputStream對象創(chuàng)新一個(gè)ObjectOutputStream對象,如下:ObjectOutputStreamos=newObjectOutputStream(fs);第三步:將對象寫入FoomyFoo1=newFoo();FoomyFoo2=newFoo();FoomyFoo3=newFoo();os.writeObject(myFoo1);os.writeObject(myFoo2);os.writeObject(myFoo3);第四步:關(guān)閉ObjectOutputStreamos.close();8.5、對象序列化序列化對象的條件被序列化的對象必須是實(shí)現(xiàn)接口的類對象。接口中沒有方法需要實(shí)現(xiàn),之所以要implements該接口,只是告訴JVM,該類對象是可被序列化而已。例如:importsjava.io.*;classFooimplementsSerializable{intwidth;intheight;DatetodayDate;……}8.5、對象序列化反序列化反序列化是翻開字節(jié)流并重構(gòu)對象。對象序列化不僅要將根本數(shù)據(jù)類型轉(zhuǎn)換成字節(jié)表示,有時(shí)還要恢復(fù)數(shù)據(jù)。反序列化通常使用從字節(jié)流重構(gòu)對象。例如:FileInputStreamin=newFileInputStream("foo.ser");ObjectInputStreamois=newObjectInputStream(in);FoomyFoo1=(Foo)ois.readObject();FoomyFoo2=(Foo)ois.readObject();FoomyFoo3=(Foo)ois.readObject();8.5、對象序列化import;/*Student定義為序列化類*/publicclassStudentimplementsSerializable{staticfinallongserialVersionUID=123456L;Stringm_name;intm_id;intm_height;publicStudent(Stringname,intid,inth){m_name=name;m_id=id;m_height=h;}publicvoidoutput(){("姓名:"+m_name);("學(xué)號(hào):"+m_id);("身高:"+m_height);}}8.5、對象序列化/*將Student對象數(shù)據(jù)寫入object.dat*/import;import;publicclassTestWriteObject{publicstaticvoidmain(Stringargs[]){try{ObjectOutputStreamf=newObjectOutputStream( newFileOutputStream("object.dat"));Students=newStudent("張三",2003001,172);f.writeObject(s);s.output();f.close();}catch(Exceptione){("發(fā)生異常:"+e);e.printStackTrace();}}}8.5、對象序列化/*從object.dat讀出Student對象數(shù)據(jù)*/import;import;publicclassTestReadObject{publicstaticvoidmain(Stringargs[]){try{ObjectInputStreamf=newObjectInputStream(newFileInputStream("object.dat"));Students=(Student)(f.readObject());s.output();f.close();}catch(Exceptione){("發(fā)生異常:"+e);e.printStackTrace();}}}8.5、對象序列化序列化本卷須知只有對象的數(shù)據(jù)被保存,方法與構(gòu)造函數(shù)不被序列化。聲明為transient或static的變量不能被序列化。小節(jié)安排文件和流8.2.1輸入字節(jié)流:InputStream8.3、字符流8.4、文件8.2.2輸出字節(jié)流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節(jié)流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節(jié)流和字符流的異同、Java中字符的表達(dá)Java中字符表達(dá)charbyte網(wǎng)絡(luò)傳輸或存儲(chǔ)的序列化形式內(nèi)存形式一個(gè)字節(jié)8bits一個(gè)Unicode字符16bits

String一組char、Java中字符的表達(dá)例如:Stringying="英";charcy=ying.charAt(0);//取得首字符//將"英"轉(zhuǎn)換成java默認(rèn)編碼字符(UTF-16)StringyingHex=Integer.toHexString(cy);System.out.println(yingHex.toUpperCase());//輸出默認(rèn)編碼:82F1//將"英"轉(zhuǎn)換成GBK編碼byte[]yingGBBytes=ying.getBytes("GBK");Stringhex;for(inti=0;i<yingGBBytes.length;i++){hex=Integer.toHexString(yingGBBytes[i]&0xFF);System.out.print(hex.toUpperCase());//"英"的GBK編碼:D3A2}、Unicode簡介什么是Unicode呢?Unicode,又稱為統(tǒng)一碼、萬國碼或單一碼,它為每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求,即為每種語言的每個(gè)字符設(shè)定一個(gè)統(tǒng)一的序數(shù)。ISO與Unicode獨(dú)立開展,至1992年合并協(xié)同。從Unicode2.0開始,Unicode采用了與ISO10646-1相同的字庫和字碼;ISO也承諾,ISO10646將不會(huì)替超出0x10FFFF的UCS-4編碼賦值,以使二者保持一致。、Unicode編碼方式Unicode編碼基于ISO10646定義的通用字符集〔UniversalCharacterSet,UCS〕,有UCS-2和UCS-4,分別用2個(gè)字節(jié)和4個(gè)字節(jié)編碼。UCS-4定義如下,而UCS-4的高位的兩個(gè)字節(jié)為0即為UCS-2

Unicode是UCS-4的子集,方案使用第0分組的17個(gè)平面,因此其編碼數(shù)為:17(平面)*256(行)*256(碼位)=1114112個(gè)編碼,編碼范圍為0~11141121,即0~0x10FFFF。實(shí)際定義了238605個(gè),分布在平面0、1、2、14〔00001110〕、15〔00001111〕、16〔00010000〕,其中15和16平面只是分別定義了兩個(gè)專用區(qū),平面0的0xE000-0xF8FF為專用區(qū),0xD800-0xDFFF為代理區(qū),因此目前真正定義的字符有238605-65534*2-6400-2048=99089個(gè)。因此,編碼集的取值范圍如下:UCS-2UnicodeUCS-4。、Unicode實(shí)現(xiàn)方式整個(gè)Unicode編碼系統(tǒng)或者說Unicode編碼標(biāo)準(zhǔn)可分為編碼方式和實(shí)現(xiàn)方式兩個(gè)層次。編碼方式是指Unicode如何對各種語言的每個(gè)字符進(jìn)行編號(hào)的;而實(shí)現(xiàn)方式那么是指同一個(gè)字符的Unicode編碼在不同的系統(tǒng)中的程序?qū)崿F(xiàn)方式,比方漢語中的“字〞在Unicode中的編號(hào)為23383,那么它在Windows或MacOS操作系統(tǒng)中分別占幾個(gè)字節(jié)?如何存儲(chǔ)與表達(dá)?等等,這些問題就是指Unicode的實(shí)現(xiàn)方式。例:漢字“嚴(yán)〞的Unicode是十六進(jìn)制數(shù)0x4E25,轉(zhuǎn)換成二進(jìn)制數(shù)足足有15位〔100111000100101〕,也就是說這個(gè)符號(hào)的表示至少需要2個(gè)字節(jié)。表示其他更大的符號(hào),可能需要3個(gè)字節(jié)或者4個(gè)字節(jié),甚至更多。如何才能區(qū)分Unicode和ASCII?計(jì)算機(jī)怎么知道三個(gè)字節(jié)表示一個(gè)符號(hào),而不是分別表示三個(gè)符號(hào)呢?如果Unicode統(tǒng)一規(guī)定,每個(gè)符號(hào)用三個(gè)或四個(gè)字節(jié)表示,那么每個(gè)英文字母前都必然有二到三個(gè)字節(jié)是0,這對于存儲(chǔ)來說是極大的浪費(fèi),文本文件的大小會(huì)因此大出二三倍,這是無法接受的。它們造成的結(jié)果是:1〕出現(xiàn)了Unicode的多種存儲(chǔ)方式,也就是說有許多種不同的二進(jìn)制格式,可以用來表示Unicode。2〕Unicode在很長一段時(shí)間內(nèi)無法推廣,直到互聯(lián)網(wǎng)的出現(xiàn)。、Unicode實(shí)現(xiàn)方式在Unicode中,漢語"字"對應(yīng)的編碼是23383。在Unicode中,我們有很多方式將數(shù)字23383表示成程序中的數(shù)據(jù),包括:UTF-8、UTF-16、UTF-32。UTF是"UCSTransformationFormat"的縮寫,可以翻譯成Unicode字符集轉(zhuǎn)換格式,即怎樣將Unicode定義的數(shù)字轉(zhuǎn)換成程序數(shù)據(jù)。例如,"漢字"對應(yīng)的數(shù)字是0x6C49和0x5B57,而編碼的程序數(shù)據(jù)是:BYTEdata_utf8[]={0xE6,0xB1,0x89,0xE5,0xAD,0x97};//UTF-8WORDdata_utf16[]={0x6C49,0x5B57};//UTF-16編碼DWORDdata_utf32[]={0x6C49,0x5B57};//UTF-32編碼這里用BYTE、WORD、DWORD分別表示無符號(hào)8位整數(shù),無符號(hào)16位整數(shù)和無符號(hào)32位整數(shù)。UTF-8、UTF-16、UTF-32分別以BYTE、WORD、DWORD作為編碼單位。"漢字"的UTF-8編碼需要6個(gè)字節(jié)。"漢字"的UTF-16編碼需要兩個(gè)WORD,大小是4個(gè)字節(jié)。"漢字"的UTF-32編碼需要兩個(gè)DWORD,大小是8個(gè)字節(jié)。、Unicode實(shí)現(xiàn)方式:UTF-8UTF-8對Unicode的實(shí)現(xiàn)方式Unicode符號(hào)UTF-8實(shí)現(xiàn)方式(二進(jìn)制)說明00000000-0000007F0xxxxxxx00000080-000007FF110xxxxx10xxxxxx00000800-0000FFFF1110xxxx10xxxxxx10xxxxxx00010000-0010FFFF11110xxx10xxxxxx10xxxxxx10xxxxxx00200000-03FFFFFF111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx已經(jīng)廢除04000000-7FFFFFFF1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx、Unicode實(shí)現(xiàn)方式:UTF-8、Unicode實(shí)現(xiàn)方式:UTF-16UTF-16編碼以16位無符號(hào)整數(shù)為單位。令某個(gè)字符的Unicode編碼為U,那么用UTF-16實(shí)現(xiàn)該編碼的規(guī)那么如下:如果U<0x10000,U的UTF-16編碼就是U對應(yīng)的16位無符號(hào)整數(shù)〔為書寫簡便,下文將16位無符號(hào)整數(shù)記作WORD〕。如果U≥0x10000,我們先計(jì)算U'=U-0x10000,然后將U'寫成二進(jìn)制形式:yyyyyyyyyyxxxxxxxxxx,U的UTF-16編碼〔二進(jìn)制〕就是:110110yyyyyyyyyy110111xxxxxxxxxx。UTF-16的編碼規(guī)則Unicode編碼范圍(十六進(jìn)制)UTF-16實(shí)現(xiàn)(二進(jìn)制)10進(jìn)制范圍字節(jié)數(shù)00000000-0000FFFFxxxxxxxxxxxxxxxx0-65535200010000-0010FFFF110110yyyyyyyyyy110111xxxxxxxxxx65536-11141114、Unicode實(shí)現(xiàn)方式:UTF-16例:Unicode編碼,計(jì)算其UTF-16編碼U=0x20C30∵U≥0x10000∴U'=U-0x10000=0x10C30=00010000110000110000用前10位依次替代模板中的y,用后10位依次替代模板中的x,得:11011000010000111101110000110000,即0xD8430xDC30,此為4字節(jié)的UTF-16編碼。、Unicode實(shí)現(xiàn)方式:UTF-16根據(jù)規(guī)那么,U≥0x10000,用四個(gè)字節(jié)表示,其中第一個(gè)WORD是110110yyyyyyyyyy,其最小為1101100000000000,最大為1101101111111111,即0xD800-0xDBFF,同理第二個(gè)WORD為0xDC00-0xDFFF,這2048個(gè)編碼在Unicode中為專用,正是使用于此。也就是說,沒有單個(gè)字符的編碼是位于0xD800-0xDFFF之間的,如果出現(xiàn)在此范圍內(nèi),說明是由四個(gè)字節(jié)構(gòu)成一個(gè)字符;否那么是由兩個(gè)字節(jié)構(gòu)成一個(gè)字符。那么,給定UTF-16編碼序列,怎么知道這是一個(gè)WORD的UTF-16編碼還是兩個(gè)WORD的UTF-16編碼呢?、Unicode實(shí)現(xiàn)方式:UTF-16UTF-16的4字節(jié)代理說明UTF-16實(shí)現(xiàn)的編碼范圍英文說明中文說明0xD800-0xDB7FHighSurrogates高位替代0xDB80-0xDBFFHighPrivateUseSurrogates高位專用替代0xDC00-0xDFFFLowSurrogates低位替代高位替代是指這個(gè)范圍(0xD800-0xDB7F)的碼位是兩個(gè)WORD的UTF-16編碼的第一個(gè)WORD。低位替代就是指這個(gè)范圍(0xDC00-0xDFFF)的碼位是兩個(gè)WORD的UTF-16編碼的第二個(gè)WORD。高位專用替代是兩個(gè)WORD的UTF-16編碼的第一個(gè)WORD在此范圍內(nèi)對應(yīng)的是Unicode專用區(qū)編碼0xF0000-0x10FFFF,它在Unicode中沒有定義、Unicode實(shí)現(xiàn)方式:UTF-16例:從網(wǎng)絡(luò)上讀取到一個(gè)字節(jié)序列(16進(jìn)制表示:D9E2DDE5),同時(shí)假設(shè)該字節(jié)序列是UTF-16字符,并使用BigEndian(即高位在低地址,低位在高地址)的字節(jié)序,判斷該序列是一個(gè)字符(4字節(jié)編碼)還是兩個(gè)字符(2字節(jié)編碼):①每次讀入兩個(gè)字節(jié)(先讀入D9E2),根據(jù)BigEndian規(guī)那么,該數(shù)據(jù)為0xD9E2。我們先檢查一下,這兩個(gè)字節(jié)是不是在0xD800-0xDB7F范圍內(nèi)?如果是,那表示我們讀到了一個(gè)超過兩個(gè)字節(jié)的字符,在本例中,0xD9E2正好是在這個(gè)范圍內(nèi),因此,我們就知道這兩個(gè)字節(jié)跟接下來的兩個(gè)字節(jié)0xDDE5才能組成一個(gè)真正的字符;如果不在0xD800-0xDBFF范圍內(nèi),那簡單了,這就是一個(gè)雙字節(jié)的字符而已。②由此,本例中的字符即為0xD9E2DDE5,根據(jù)UTF-16編碼規(guī)那么,將其展開為二制位如下: 1101100111100010 1101110111100101再根據(jù)UTF-16編碼規(guī)那么,得到U'=01111000100111100101,再計(jì)算U=U'+0x10000=0x889E5,這就是該字符對應(yīng)的Unicode碼。、Unicode實(shí)現(xiàn)方式:UTF-16根據(jù)UTF-16編碼規(guī)那么,假設(shè)第一個(gè)WORD位于高位替代范圍(0xD800-0xDB7F),那么第二個(gè)WORD必然位于低位替代范圍(0xDC00-0xDFFF),否那么必然導(dǎo)致亂碼;假設(shè)第一個(gè)WORD位于高位專用替代范圍(0xDB80-0xDBFF),那么第二個(gè)WORD必須位于低位替代范圍(0xDC00-0xDFFF),否那么必然導(dǎo)致亂碼;假設(shè)第一個(gè)WORD位于高位專用替代范圍(0xDB80-0xDBFF),且第二個(gè)WORD位于低位替代范圍(0xDC00-0xDFFF),但接受方與發(fā)送方在該范圍內(nèi)的Unicode編碼實(shí)現(xiàn)方式不一致,那么導(dǎo)致亂碼。、Unicode實(shí)現(xiàn)方式:UTF-32UTF-32編碼以32位無符號(hào)整數(shù)為單位。Unicode的UTF-32編碼就是其對應(yīng)的32位無符號(hào)整數(shù)。、字節(jié)序:LittleEndian和BigEndian名稱來自英國作家斯威夫特的?格列佛游記?:因人們爭論吃雞蛋時(shí)究竟是從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開前后爆發(fā)了六次戰(zhàn)爭,一個(gè)皇帝送了命,另一個(gè)皇帝丟了王位。LittleEndian和BigEndian是CPU處理多字節(jié)數(shù)的不同方式。例如“漢〞的Unicode編碼是0x6C49。那么寫到文件里或從網(wǎng)絡(luò)發(fā)送出去時(shí)(按字節(jié)流)時(shí),究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是BigEndian;如果將49寫在前面,就是LittleEndian。為什么電子郵件常常出現(xiàn)亂碼?就是因?yàn)榘l(fā)信人和收信人使用的編碼方式、字節(jié)序不一樣。、字節(jié)序:LittleEndian和BigEndianUnicode標(biāo)準(zhǔn)中定義,每一個(gè)文件的最前面分別參加一個(gè)表示編碼順序的字符,這個(gè)字符的名字叫做“零寬度非換行空格〞〔ZEROWIDTHNO-BREAKSPACE〕,用FEFF表示,正好是兩個(gè)字節(jié),而且FF比FE大1。定義:如果一個(gè)序列的頭兩個(gè)字節(jié)是FEFF,就表示該文件采用BigEndian方式;如果是FFFE,就表示該文件采用LittleEndian方式。根據(jù)字節(jié)序的不同,Unicode編碼可實(shí)現(xiàn)為UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE字節(jié)序舉例Unicode編碼UTF-16LEUTF-16BEUTF32-LEUTF32-BE0x6C49496C6C49496C000000006C490x20C3043D830DCD843DC30300C020000020C30、字節(jié)序:LittleEndian和BigEndian怎么判斷字節(jié)流(文件流、網(wǎng)絡(luò)數(shù)據(jù)流)的字節(jié)序呢?Unicode標(biāo)準(zhǔn)建議用BOM〔ByteOrderMark〕

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論