Java筆記(七 I/O操作與字節(jié)流) Sun公司提供的Java源代碼在安裝目錄下的scr壓縮包中\(zhòng)java下
java.io包中
File類An abstract representation of file and directory pathnames.
一個(gè)File類的對(duì)象,表示了磁盤上的文件或目錄 File類提供了與平臺(tái)無(wú)關(guān)的方法來(lái)對(duì)磁盤上的文件或目錄進(jìn)行操作 import java.io.*;
class FileTest { public static void main(String[] args) throws Exception { /*相對(duì)路徑 File f=new File("1.txt"); f.createNewFile();//boolean createNewFile():Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist. //f.mkdir();//boolean mkdir():Creates the directory named by this abstract pathname.在當(dāng)前目錄下 */ /*Windows平臺(tái)下 File f=new File("D:\\JAVA\\L6\\1.txt"); f.createNewFile(); */ File fDir=new File(File.separator);//static String separator:The system-dependent default name-separator character, represented as a string for convenience. 這里fDir表示當(dāng)前程序所在根目錄 String strFile="JavaLesson"+File.separator+"Lesson07"+File.separator+"1.txt"; File f=new File(fDir,strFile);//File(File parent, String child):Creates a new File instance from a parent abstract pathname and a child pathname string. //f.createNewFile(); //f.delete();//boolean delete():Deletes the file or directory denoted by this abstract pathname. f.deleteOnExit();//void deleteOnExit():Requests that the file or directory denoted by this abstract pathname be deleted when the virtual machine terminates. /* for(int i=0;i<5;i++) { File f=File.createTempFile("1",".txt");//static File createTempFile(String prefix, String suffix):Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its name. f.deleteOnExit(); } */ /* File fDir=new File(File.separator); String strFile="Java"+File.separator+"L6"; File f=new File(fDir,strFile); String[] names=f.list(); for(int i=0;i<names.length;i++) { System.out.println(names[i]); } */ File fDir=new File(File.separator); String strFile="Java"+File.separator+"L6"; File f=new File(fDir,strFile); String[] names=f.list(new FilenameFilter()// String[] list(FilenameFilter filter):Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter;Interface FilenameFilter { public boolean accept(File dir, String name)//boolean accept(File dir, String name):Tests if a specified file should be included in a file list { return name.indexOf(".java")!=-1;//int indexOf(String str):Returns the index within this string of the first occurrence of the specified substring. } }); for(int i=0;i<names.length;i++) { System.out.println(names[i]); } } } 流式I/O 流(Stream)是字節(jié)的源或目的 兩種基本的流是:輸入流(Input Stream)和輸入流(Output Stream)??蓮闹凶x出一系列字節(jié)的對(duì)象稱為輸入流。而能向其中寫入一系列字節(jié)的對(duì)象稱為輸入流 流的分類: 節(jié)點(diǎn)流:從特定的地方讀寫的流類,,例如:磁盤或一塊內(nèi)存區(qū)域 過(guò)濾流:使用節(jié)點(diǎn)流作為輸入或輸出,。過(guò)濾流是使用一個(gè)已經(jīng)存在的輸入流或輸出流連接創(chuàng)建的 抽象基類InputStream
三個(gè)基本的讀方法 abstract int read():讀取一個(gè)字節(jié)數(shù)據(jù)(但返回的是整型,,整型是四個(gè)字節(jié)的,也就是說(shuō)這個(gè)整型中只有第一個(gè)字節(jié)是有用的),,并返回讀到的數(shù)據(jù),如果返回-1,,表示讀到了輸入流的末尾 int read(byte[] b):將數(shù)據(jù)讀入一個(gè)字節(jié)數(shù)組,,同時(shí)返回實(shí)際讀取的字節(jié)數(shù),。如果返回-1,表示讀到了輸入流的末尾 int read(byte[] b,int off,int len):將數(shù)據(jù)讀入一個(gè)字節(jié)數(shù)組,,同時(shí)返回實(shí)際讀取的字節(jié)數(shù)。如果返回-1,,表示讀到了輸入流的末尾,。off指定在數(shù)組b中存放數(shù)據(jù)的起始偏移位置;len指定讀取的最大字節(jié)數(shù) 其他方法 long skip(long n):在輸入流中跳過(guò)n個(gè)字節(jié),,并返回實(shí)際跳過(guò)的字節(jié)數(shù) int available():返回在不發(fā)生阻塞的情況下,,可讀取的字節(jié)數(shù) void close():關(guān)閉輸入流,釋放和這個(gè)流相關(guān)的系統(tǒng)資源 void mark(int readlimit):在輸入流的當(dāng)前位置放置一個(gè)標(biāo)記,,如果讀取的字節(jié)數(shù)多于readlimit設(shè)置的值,則流忽略這個(gè)標(biāo)記 抽象基類OutputStream
三個(gè)基本的寫方法 abstract void write(int b):往輸出流中寫入一個(gè)字節(jié)(寫入的是整型b的第一個(gè)字節(jié)) void write(byte[] b):往輸出流中寫入數(shù)組b中的所有字節(jié) void write(byte[] b,int off,int len):往輸出流中寫入數(shù)組b中從偏移量off開始的len個(gè)字節(jié)的數(shù)據(jù) 其他方法 void flush():刷新輸出流,,強(qiáng)制緩沖區(qū)中的輸出字節(jié)被寫出 void close():關(guān)閉輸出流,釋放和這個(gè)流相關(guān)的系統(tǒng)資源 基本的流類:
FileInputStream和FileOutputStream:節(jié)點(diǎn)流,,用于從文件中讀取或往文件中寫入字節(jié)流。如果在構(gòu)造FileOutputStream時(shí),,文件已經(jīng)存在,則覆蓋這個(gè)文件 BufferedInputStream和BufferedOutputStream:過(guò)濾流,,需要使用已經(jīng)存在的節(jié)點(diǎn)流來(lái)構(gòu)造,提供帶緩沖的讀寫,,提高了讀寫的效率(用它們來(lái)構(gòu)造緩沖輸入流和緩沖輸出流) DataInputStream和DataOutputStream:過(guò)濾流,,需要使用已經(jīng)存在的節(jié)點(diǎn)流來(lái)構(gòu)造,,提供了讀寫Java中的基本數(shù)據(jù)類型的功能 PipedInputStream和PipedOutputStream:管道流,用于線程間的通信,。一個(gè)線程的PipedInputStream對(duì)象從另一個(gè)線程的PipedOutputStream對(duì)象讀取輸入。要使管道流有用,,必須同時(shí)構(gòu)造管道輸入流和管道輸出流 import java.io.*;
class StreamTest { public static void main(String[] args) throws Exception { /*從屏幕輸入,輸入什么回車后會(huì)直接在屏幕上輸出,,ctrl+C退出 int data; while((data=System.in.read())!=-1) { System.out.write(data); } */ /*往文件中寫入 FileOutputStream fos=new FileOutputStream("1.txt");//FilterOutputStream(OutputStream out):Creates an output stream filter built on top of the specified underlying output stream fos.write("http://lilac0610.spaces.".getBytes());//FileOutputStream的write方法只接受byte和int型 void write(byte[] b):Writes b.length bytes to this output stream;byte[] getBytes():Encodes this String into a sequence of bytes using the platform‘s default charset, storing the result into a new byte array. fos.close();//void close():Closes this output stream and releases any system resources associated with the stream. */ /*文件輸入流讀取數(shù)據(jù),輸出到屏幕上 FileInputStream fis=new FileInputStream("1.txt");//protected FilterInputStream(InputStream in):Creates a FilterInputStream by assigning the argument in to the field this.in so as to remember it for later use. byte[] buf=new byte[100]; int len=fis.read(buf);//int read(byte[] b):Reads up to byte.length bytes of data from this input stream into an array of bytes. System.out.println(new String(buf,0,len));//void println(String x):Print a String and then terminate the line;String(byte[] bytes, int offset, int length):Constructs a new String by decoding the specified subarray of bytes using the platform‘s default charset. fis.close();// void close():Closes this input stream and releases any system resources associated with the stream. */ /*BufferedOutputStream緩沖輸出流,,需要使用已經(jīng)存在的節(jié)點(diǎn)流來(lái)構(gòu)造(從 FilterOutputStream繼承) FileOutputStream fos=new FileOutputStream("1.txt"); BufferedOutputStream bos=new BufferedOutputStream(fos);//BufferedOutputStream(OutputStream out):Creates a new buffered output stream to write data to the specified underlying output stream with a default 512-byte buffer size. bos.write("http://lilac0610.spaces.".getBytes());//數(shù)據(jù)寫入緩沖區(qū) bos.flush();//void flush():Flushes this buffered output stream.將緩沖區(qū)中數(shù)據(jù)寫入文件 //bos.close();//也可將緩沖區(qū)中數(shù)據(jù)寫入文件,,但此時(shí)就不能再繼續(xù)寫入數(shù)據(jù)了 */ /*BufferedInputStream緩沖輸入流 FileInputStream fis=new FileInputStream("1.txt"); BufferedInputStream bis=new BufferedInputStream(fis); byte[] buf=new byte[100]; int len=bis.read(buf); System.out.println(new String(buf,0,len));//void println(String x):Print a String and then terminate the line;String(byte[] bytes, int offset, int length):Constructs a new String by decoding the specified subarray of bytes using the platform‘s default charset. bis.close(); */ /*DataOutputStream提供了讀寫Java中的基本數(shù)據(jù)類型的功能 FileOutputStream fos=new FileOutputStream("1.txt"); BufferedOutputStream bos=new BufferedOutputStream(fos); DataOutputStream dos=new DataOutputStream(bos);//此時(shí)相當(dāng)于把三個(gè)流鏈接了起來(lái),,把bos鏈接到了fos,,又把dos鏈接到了bos,,此時(shí)帶緩沖并可寫入基本數(shù)據(jù)類型 byte b=3; int i=78; char ch=‘a(chǎn)‘; float f=4.5f; dos.writeByte(b); dos.writeInt(i); dos.writeChar(ch); dos.writeFloat(f); dos.close(); */ /*DataInputStream FileInputStream fis=new FileInputStream("1.txt"); BufferedInputStream bis=new BufferedInputStream(fis); DataInputStream dis=new DataInputStream(bis); System.out.println(dis.readByte());//讀取的順序要與寫入的一致 System.out.println(dis.readInt()); System.out.println(dis.readChar()); System.out.println(dis.readFloat()); dis.close(); */ } }
---------------------------------------------------------------------------------------
import java.io.*; class PipedStreamTest { public static void main(String[] args) { PipedOutputStream pos=new PipedOutputStream(); PipedInputStream pis=new PipedInputStream(); try { pos.connect(pis); new Producer(pos).start(); new Consumer(pis).start(); } catch(Exception e) { e.printStackTrace(); } } } class Producer extends Thread
{ private PipedOutputStream pos; public Producer(PipedOutputStream pos) { this.pos=pos; } public void run() { try { pos.write("Hello".getBytes()); pos.close(); } catch(Exception e) { e.printStackTrace(); } } } class Consumer extends Thread
{ private PipedInputStream pis; public Consumer(PipedInputStream pis) { this.pis=pis; } public void run() { try { byte[] buf=new byte[100]; int len=pis.read(buf); System.out.println(new String(buf,0,len)); pis.close(); } catch(Exception e) { e.printStackTrace(); } } } Java I/O庫(kù)的設(shè)計(jì)原則
Java的I/O庫(kù)提供了一個(gè)稱作鏈接的機(jī)制,可以將一個(gè)流與另一個(gè)流首尾相接,,形成一個(gè)流管道的鏈接。這種機(jī)制實(shí)際上是一種被稱為Decorator(裝飾)設(shè)計(jì)模式的應(yīng)用 通過(guò)流的鏈接,,可以動(dòng)態(tài)的增加流的功能,,而這種功能的增加是通過(guò)組合一些流的基本功能而動(dòng)態(tài)獲取的 我們要獲取一個(gè)I/O對(duì)象,,往往需要產(chǎn)生多個(gè)I/O對(duì)象(例如InputStream鏈:FileInputStream從文件中獲取輸入字節(jié)—BufferedInputStream增加了緩沖的功能—DataInputStream增加了讀取Java基本數(shù)據(jù)類型的功能;OutputStream鏈:DataOutputStream可以往輸出流中寫入Java基本數(shù)據(jù)類型—BufferedInputStream提供數(shù)據(jù)寫入到緩沖區(qū)的功能—FileInputStream將數(shù)據(jù)寫入到文件中),,這也是Java I/O庫(kù)不太容易掌握的原因,,但在I/O庫(kù)中Decorator模式的運(yùn)用,,給我們提供了實(shí)現(xiàn)上的靈活性 InputStream、OutputStream是對(duì)字節(jié)流的操作,,Reader,、Writer是對(duì)字符流的操作
Java程序語(yǔ)言使用Unicode來(lái)表示字符串和字符 Reader和Writer這兩個(gè)抽象類主要用來(lái)讀寫字符流 import java.io.*;
class StreamTest { public static void main(String[] args) throws Exception { /* FileOutputStream fos=new FileOutputStream("1.txt"); OutputStreamWriter osw=new OutputStreamWriter(fos); BufferedWriter bw=new BufferedWriter(osw); bw.write("http://lilac.spaces."); bw.close(); FileInputStream fis=new FileInputStream("1.txt"); InputStreamReader isr= new InputStreamReader(fis); BufferedReader br=new BufferedReader(isr); System.out.println(br.readLine()); br.close(); */ InputStreamReader isr= new InputStreamReader(System.in); BufferedReader br=new BufferedReader(isr); String strLine; while((strLine=br.readLine())!=null)//從輸入設(shè)備上讀入一行數(shù)據(jù),,沒(méi)有輸入數(shù)據(jù)則為null { System.out.println(strLine); } br.close(); } } 字符集的編碼: ASCII(American Standard Code for Information Interchange,,美國(guó)信息互換標(biāo)準(zhǔn)代碼),是基于常用的英文字符的一套電腦編碼系統(tǒng),。我們知道英文中經(jīng)常使用的字符,、數(shù)字符號(hào)被計(jì)算機(jī)處理時(shí)都是以二進(jìn)制碼的形式出現(xiàn)的,。這種二進(jìn)制碼的集合就是所謂的ASCII碼。每一個(gè)ASCII碼與一個(gè)8位(bit)二進(jìn)制數(shù)對(duì)應(yīng)。其最高位是0,,相應(yīng)的十進(jìn)制數(shù)是0-127。如,,數(shù)字“0”的編碼用十進(jìn)制數(shù)表示就是48,。另有128個(gè)擴(kuò)展的ASCII,最高位都是1,,由一些指標(biāo)符和其他符號(hào)組成。ASCII是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng),。 GB2312:GB2312碼是中華人民共和國(guó)國(guó)家漢字信息交換用編碼,,全稱《信息交換用漢字編碼字符集—基本集》,。主要用于給每一個(gè)中文字符制定相應(yīng)的數(shù)字,也就是進(jìn)行編碼,。一個(gè)中文字符用兩個(gè)字節(jié)的數(shù)字來(lái)表示,,為了和ASCII碼有所區(qū)別,,將中文字符每一個(gè)字節(jié)的最高位置都用1來(lái)表示 GBK:為了對(duì)更多的字符進(jìn)行編碼,國(guó)家又發(fā)布了新的編碼系統(tǒng)GBK(GBK的K是“擴(kuò)展”的漢語(yǔ)拼音第一個(gè)字母),。在新的編碼系統(tǒng)中,,除了完全兼容GB2312外,,還對(duì)繁體中文、一些不常用的漢字和許多符號(hào)進(jìn)行了編碼 ISO-8859-1:是西方國(guó)家所使用的字符編碼集,,是一種單字節(jié)的字符集,,而英文實(shí)際上只用了其中數(shù)字小于128的部分 Unicode:這是一種通用的字符集,,對(duì)所有語(yǔ)言的文字進(jìn)行了統(tǒng)一編碼,對(duì)每一個(gè)字符都用2個(gè)字節(jié)來(lái)表示,,對(duì)于英文字符采取前面加"0"字節(jié)的策略實(shí)現(xiàn)等長(zhǎng)兼容,。如"a"的ASCII碼為0x61,,UNICODE就為0x00,0x61 UTF-8:Eight-bit UCS Transformation Format,,(UCS,,Universal Character Set,通用字符集,,UCS是所有其他字符集標(biāo)準(zhǔn)的一個(gè)超集),。一個(gè)7位的ASCII碼值,對(duì)應(yīng)的UTF碼是一個(gè)字節(jié),。如果字符是0x0000,,或在0x0080與0x007f之間,,對(duì)應(yīng)的UTF碼是兩個(gè)字節(jié),如果字符在0x0800與0xffff之間,,對(duì)應(yīng)的UTF碼是三個(gè)字節(jié) 在Java中字符都是用Unicode表示的,。我們獲取一段Unicode,,是解碼;將字符或字符串轉(zhuǎn)換為字節(jié)就是編碼過(guò)程 ------------------------------------------------------------------------------------------
import java.util.*; import java.nio.charset.*; class CharsetTest//解決亂碼顯示問(wèn)題 { public static void main(String[] args) throws Exception { /*輸出JVM所支持的字符集 Map m=Charset.availableCharsets(); Set names=m.keySet(); Iterator it=names.iterator();//迭代器 while(it.hasNext()) { System.out.println(it.next()); } */ Properties pps=System.getProperties();//static Properties getProperties():Determines the current system properties. pps.list(System.out); pps.put("file.encodeing","ISO-8859-1"); int data; byte[] buf=new byte[100]; int i=0; while((data=System.in.read())!=‘q‘) { buf[i]=(byte)data; i++; } String str=new String(buf,0,i);//Java會(huì)按ISO-8859-1把得到的字符解碼成Unicode,,但輸入的時(shí)候是按中文操作系統(tǒng)的字符集GBK碼讀入的 String(byte[] bytes, int offset, int length):Constructs a new String by decoding the specified subarray of bytes using the platform‘s default charset. System.out.println(str); String strGBK=new String(str.getBytes("ISO-8859-1"),"GBK");//把內(nèi)容按ISO-8859-1編碼回去,再按GBK解碼回來(lái) System.out.println(strGBK); } }
-----------------------------------------------------------------------------------------------
RandomAccessFile類
RandomAccessFile類同時(shí)實(shí)現(xiàn)了DataInput和DataOutput接口(所以可以讀取和寫入),,提供了對(duì)文件隨機(jī)存取的功能,利用這個(gè)類可以在文件的任何位置讀取或?qū)懭霐?shù)據(jù) RandomAccessFile類提供了一個(gè)文件指針,,用來(lái)標(biāo)志要進(jìn)行讀寫操作的下一數(shù)據(jù)的位置 import java.io.*;
class RandomFileTest { public static void main(String[] args) throws Exception { Student s1=new Student(1,"zs",98.5); Student s2=new Student(2,"ls",99.5); Student s3=new Student(3,"ww",95.5); RandomAccessFile raf=new RandomAccessFile("student.txt","rw"); s1.writeStudent(raf); s2.writeStudent(raf); s3.writeStudent(raf); Student s=new Student(); raf.seek(0);//寫入第三個(gè)Student信息的時(shí)候,,指針已經(jīng)指向末尾下面還要進(jìn)行讀取,,所以要設(shè)置一下文件指針 for(long i=0;i<raf.length();i=raf.getFilePointer())//long length():Returns the length of this file;long getFilePointer():Returns the current offset in this file. { s.readStudent(raf); System.out.println(s.num+":"+s.name+":"+s.score); } raf.close(); } } class Student
{ int num; String name; double score; public Student() {} public Student(int num,String name,double score) { this.num=num; this.name=name; this.score=score; } public void writeStudent(RandomAccessFile raf) throws IOException { raf.writeInt(num); raf.writeUTF(name);//writeBytes(String str):……by discarding its high eight bits不建議使用,中文字符只寫入第一個(gè)字節(jié)無(wú)法識(shí)別;writeChars(String str)和writeUTF(String str)都可以,,但是writeUTF會(huì)在一開始記錄寫入數(shù)據(jù)長(zhǎng)度,所以RandomAccessFile還提供了readUTF() raf.writeDouble(score); } public void readStudent(RandomAccessFile raf) throws IOException { num=raf.readInt(); name=raf.readUTF(); score=raf.readDouble(); } } --------------------------------------------------------------------------------------
對(duì)象序列化 將對(duì)象轉(zhuǎn)換為字節(jié)流保存起來(lái),,并在日后還原這個(gè)對(duì)象,,這種機(jī)制叫做對(duì)象序列化(可用于在網(wǎng)絡(luò)上發(fā)送對(duì)象) 將一個(gè)對(duì)象保存到永久存儲(chǔ)設(shè)備上稱為持續(xù)性 一個(gè)對(duì)象要想能夠?qū)崿F(xiàn)序列化,,必須實(shí)現(xiàn)Serializable接口(標(biāo)識(shí)接口)或Externalizable接口 當(dāng)一個(gè)對(duì)象被序列化時(shí),,只保存對(duì)象的非靜態(tài)成員變量,不能保存任何的成員方法和靜態(tài)的成員變量 如果一個(gè)對(duì)象的成員變量是一個(gè)對(duì)象,,那么這個(gè)對(duì)象的數(shù)據(jù)成員也會(huì)被保存 如果一個(gè)可序列化的對(duì)象包含對(duì)某個(gè)不可序列化的對(duì)象的引用,那么整個(gè)序列化操作將會(huì)失敗,,并且會(huì)拋出一個(gè)NotSerializableException,。我們可以將這個(gè)引用標(biāo)記為transient,,那么對(duì)象仍然可以序列化 import java.io.*;
class ObjectSerialTest { public static void main(String[] args) throws Exception { Employee e1=new Employee("zs",25,3000.50); Employee e2=new Employee("ls",24,3200.40); Employee e3=new Employee("ww",27,3800.55); FileOutputStream fos=new FileOutputStream("employee.txt"); ObjectOutputStream oos=new ObjectOutputStream(fos);//ObjectOutputStream實(shí)現(xiàn)了DataOutput,所以它提供了往輸出流當(dāng)中寫入Java基本數(shù)據(jù)類型的功能 oos.writeObject(e1);//writeObject()完成對(duì)象序列化 oos.writeObject(e2); oos.writeObject(e3); oos.close(); FileInputStream fis=new FileInputStream("employee.txt"); ObjectInputStream ois=new ObjectInputStream(fis); Employee e; for(int i=0;i<3;i++) { e=(Employee)ois.readObject();//Object readObject()返回的是Object,,所以要做類型轉(zhuǎn)換,否則報(bào)錯(cuò);當(dāng)反序列化的時(shí)候,,并不會(huì)調(diào)用該對(duì)象任何的構(gòu)造函數(shù),,只是根據(jù)先前所保存的信息在內(nèi)存中重新還原對(duì)象 System.out.println(e.name+":"+e.age+":"+e.salary); } ois.close(); } } class Employee implements Serializable
{ String name; int age; double salary;//若不像讓某個(gè)變量被序列化保存起來(lái),就可以也將其聲明為transient transient Thread t=new Thread();//Thread本身不可序列化,,標(biāo)記為transient后就不會(huì)再參與到序列化中 public Employee(String name,int age,double salary) { this.age=age; this.name=name; this.salary=salary; } //寫如下兩個(gè)方法,可以在序列化的時(shí)候調(diào)用自己寫的方法,,這里兩個(gè)方法雖聲明為private,,但是可以在類外調(diào)用,,是個(gè)特例 private void writeObject(java.io.ObjectOutputStream oos) throws IOException { oos.writeInt(age); oos.writeUTF(name); System.out.println("Write Object"); } private void readObject(java.io.ObjectInputStream ois) throws IOException, ClassNotFoundException { age=ois.readInt(); name=ois.readUTF(); System.out.println("Read Object"); } } 總結(jié): InputStream和OutputStream:字節(jié)流的輸入和輸出。從這兩個(gè)類派生出了一些類:FileInputStream,、BufferedInputStream,、DataInputStream,、PipedInputStream,、ObjectInputStream;FileOutputStream,、BufferedOutputStream,、DataOutputStream、PipedOutputStream,、ObjectOutputStream Reader和Writer:字符流的輸入和輸出。從這兩個(gè)類派生出了一些類:BufferedReader,、InputStreamReader,;BufferedWriter,、OutputStreamWriter 流的鏈接(Java I/O庫(kù)的設(shè)計(jì)原則)
|
|
來(lái)自: 依笑乘風(fēng)涼 > 《JAVA學(xué)習(xí)》