Java程序設計第章文件和流解讀_第1頁
Java程序設計第章文件和流解讀_第2頁
Java程序設計第章文件和流解讀_第3頁
Java程序設計第章文件和流解讀_第4頁
Java程序設計第章文件和流解讀_第5頁
已閱讀5頁,還剩68頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第八章文件和流圖形圖像研究所計算機科學與技術、軟件學院

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

b)throwsIOException將數據讀入byte[],返回實際讀取的字節數intread(byte[]

b,int

off,int

len)throwsIOException讀取最多len個字節到數組b中,返回實際讀取數量publiclongskip(long

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

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

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

b,int

off,int

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

InputStreamReader和OutputStreamWriter來關聯,實際上是通過byte[]和String來關聯。在實際開發中出現的漢字問題實際上都是在字符流和字節流之間轉化不統一而造成的。在從字節流轉化為字符流時,也就是從byte[]轉化為String時,使用如下構造方法: public

String(byte

bytes[],

String

charsetName) 這個方法中有一個關鍵的字符集編碼參數charsetName,通常我們都省略了,那系統就用操作系統的默認的language。而在字符流轉化為字節流時,實際上是String轉化為byte[]時,是使用如下方法進行轉化: byte[]

String.getBytes(String

charsetName)字符流和字節流是根據處理數據的不同來區分的。字節流按照8位傳輸,字符流按照16位傳輸由于字符流使用Unicode字符集,支持多國文字,因此假設流要跨越多種平臺傳輸,應使用字符流。字符流的傳輸效率比字節流的高。小節安排文件和流8.2.1輸入字節流:InputStream8.3、字符流8.4、文件8.2.2輸出字節流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節流和字符流的異同、文件File文件相關屬性例如://假設當前目錄為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()//創立目錄publicString[]list()//返回一個字符串數組,是給定目錄下的文件與子目錄publicFile[]listFiles()////返回File對象數組,是給定目錄下的文件、文件/*打印某目錄下(包含子目錄)所有文件和文件大小*/importjava.io.*;publicclassTestFileLIST{publicstaticvoidmain(Stringargs[])throwsIOException{Filefiles=newFile(".");//"."表示當前目錄(與TestFileLIST.java所在的同一個目錄)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();}}}}}、隨機訪問文件類:RandomAccessFileRandomAccessFile類提供了對文件的隨機訪問方式,即可在文件的任意位置讀或寫數據而且可以同時進行讀和寫的操作RandomAccessFile構造方法及常用的方法方法定義功能說明RandomAccessFile(Filefile,Stringmode)throwsFileNotfoundExceptionfile待訪問的文件,mode設定訪問方式:"r"表示只讀,"w"表示寫,"rw"表示讀寫RandomAccessFile(Stringname,Stringmode)throwsFileNotfoundExceptionname是文件名字符串longlength()throwsIOException返回文件的長度,以字節為單位voidseek(longpos)throwsIOException改變文件指針的位置finalintreadInt()throwsIOException讀一個整型數據finalvoidwriteInt(intv)throwsIOException寫入一個整型數據longgetFilePointer()throwsIOException返回文件指針的位置close()throwsIOException關閉文件、隨機訪問文件類:RandomAccessFile提供了類似于readInt()的其他方法用于讀取byte、boolean、char、double、float、long、short、unsignedbyte、unsignedshort等數據類型的方法,即readByte()、readBoolean()、readChar()、readDouble()、readFloat()、readLong()、readShort()、readUnsignedByte()、readUnsignedShort()等提供了writeByte()、writeBoolean()、writeChar()、writeDouble()、writeFloat()、writeLong()、writeShort()等方法用于寫入數據。、隨機訪問文件類:RandomAccessFile/*向文件中寫入10個數據,第i個數據=圓周率*i(i=0,1,2,…,9),然后將第2個(i=2)改為0,最后將10個數據全部輸出*/import;import;publicclassTestFileRAF{publicstaticvoidmain(Stringargs[]){try{RandomAccessFilef=new RandomAccessFile("TestFileRAF.txt","rw");//可讀寫inti;doubled;//寫:向文件寫入10個數據for(i=0;i<10;i++)f.writeDouble(Math.PI*i);、隨機訪問文件類:RandomAccessFile//修改:對文件中第2個double數據改為0f.seek(16);//文件指針往前走16個字節(2個double數據)f.writeDouble(0);f.seek(0);//文件指針回到文件首部//讀?。簩⑷繑祿x出并打印到屏幕中for(i=0;i<10;i++){d=f.readDouble();("["+i+"]:"+d);}f.close();}catch(IOExceptione){("發生異常:"+e);e.printStackTrace();}}}、隨機訪問文件類:RandomAccessFile、文件過濾接口:FileFilter和FilenameFilterFileFilter和FilenameFilter是為開發者提供在文件系統中進行過濾或者說是搜索所需要文件的功能,均有accept()方法:

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

publicboolean

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

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

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

其中,filter須是第①步中實現了FileFilter或FilenameFilter接口中的accept方法的過濾器類的對象。、文件過濾接口:FileFilter和FilenameFilterimportjava.io.*;//第①步:聲明過濾類ListFilter并實現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//實現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()進行過濾publicclassTestFileSearch{publicstaticvoidmain(Stringargs[]){//要求兩個參數:第一個參數表示目錄,第二參數表示要過濾的文件StringstrDir,strExtension;switch(args.length){case1:strDir=".";strExtension=args[0];break;case2:strDir=args[0];strExtension=args[1];break;default:("需兩個參數!");return;} Filef=newFile(strDir);ListFilterls=newListFilter(strExtension);Stringstr[]=f.list(ls);for(inti=0;i<str.length;i++)System.out.println(str[i]);}}小節安排文件和流8.2.1輸入字節流:InputStream8.3、字符流8.4、文件8.2.2輸出字節流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節流和字符流的異同8.5、對象序列化什么是對象序列化保存內存中某個對象的方法很多,但是Java給你提供一種更好的保存對象狀態的機制,那就是對象序列化。java中對象序列化的過程就是將對象寫入字節流和從字節流中讀取對象。將對象狀態轉換成字節流之后,可以保存到文件、通過管道輸出到另一線程或通過網絡連接將對象數據發送到另一主機。8.5、對象序列化什么情況下需要序列化把內存中的對象保存到一個文件中或者數據庫中用套接字(socket)在網絡上傳送對象通過RMI傳輸對象8.5、對象序列化實現序列化的步驟第一步:創立一個FileOutputStream對象,如下:FileOutputStreamfs=newFileOutputStream("foo.ser");第二步:負責將對象寫入字節流。因此第二步是利用第一步創立的FileOutputStream對象創新一個ObjectOutputStream對象,如下:ObjectOutputStreamos=newObjectOutputStream(fs);第三步:將對象寫入FoomyFoo1=newFoo();FoomyFoo2=newFoo();FoomyFoo3=newFoo();os.writeObject(myFoo1);os.writeObject(myFoo2);os.writeObject(myFoo3);第四步:關閉ObjectOutputStreamos.close();8.5、對象序列化序列化對象的條件被序列化的對象必須是實現接口的類對象。接口中沒有方法需要實現,之所以要implements該接口,只是告訴JVM,該類對象是可被序列化而已。例如:importsjava.io.*;classFooimplementsSerializable{intwidth;intheight;DatetodayDate;……}8.5、對象序列化反序列化反序列化是翻開字節流并重構對象。對象序列化不僅要將根本數據類型轉換成字節表示,有時還要恢復數據。反序列化通常使用從字節流重構對象。例如: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);("學號:"+m_id);("身高:"+m_height);}}8.5、對象序列化/*將Student對象數據寫入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){("發生異常:"+e);e.printStackTrace();}}}8.5、對象序列化/*從object.dat讀出Student對象數據*/import;import;publicclassTestReadObject{publicstaticvoidmain(Stringargs[]){try{ObjectInputStreamf=newObjectInputStream(newFileInputStream("object.dat"));Students=(Student)(f.readObject());s.output();f.close();}catch(Exceptione){("發生異常:"+e);e.printStackTrace();}}}8.5、對象序列化序列化本卷須知只有對象的數據被保存,方法與構造函數不被序列化。聲明為transient或static的變量不能被序列化。小節安排文件和流8.2.1輸入字節流:InputStream8.3、字符流8.4、文件8.2.2輸出字節流:OutputStream8.3.1輸入字符流:Reader8.3.2輸出字符流:Writer8.3.3BufferedReader和BufferedWriter8.1、流的根本概念8.2、字節流8.5、對象序列化8.6、Java中的亂碼問題8.3.4字節流和字符流的異同、Java中字符的表達Java中字符表達charbyte網絡傳輸或存儲的序列化形式內存形式一個字節8bits一個Unicode字符16bits

String一組char、Java中字符的表達例如:Stringying="英";charcy=ying.charAt(0);//取得首字符//將"英"轉換成java默認編碼字符(UTF-16)StringyingHex=Integer.toHexString(cy);System.out.println(yingHex.toUpperCase());//輸出默認編碼:82F1//將"英"轉換成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,又稱為統一碼、萬國碼或單一碼,它為每種語言中的每個字符設定了統一并且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求,即為每種語言的每個字符設定一個統一的序數。ISO與Unicode獨立開展,至1992年合并協同。從Unicode2.0開始,Unicode采用了與ISO10646-1相同的字庫和字碼;ISO也承諾,ISO10646將不會替超出0x10FFFF的UCS-4編碼賦值,以使二者保持一致。、Unicode編碼方式Unicode編碼基于ISO10646定義的通用字符集〔UniversalCharacterSet,UCS〕,有UCS-2和UCS-4,分別用2個字節和4個字節編碼。UCS-4定義如下,而UCS-4的高位的兩個字節為0即為UCS-2

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

溫馨提示

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

評論

0/150

提交評論