11、java中的I/O流(1)
?????? 我對于流的理解是這樣的,計算機的本質本來就是對輸入的數據進行操作,然后將結果輸出的一種工具,數據在各個數據源節點之間進行流動,感覺流就是對這種狀態的一種抽象,一個數據流表示的就是一系列數據序列,java存在現成的類庫可以實現數據的主動獲取和處理,這些操作數據的類庫構成了java的I/O體系。
?????? 流根據不同的方面可以分成不同的類型,根據流向可分為輸入流和輸出流;根據操作的數據單元不同可分為字節流(8bit)和字符流(16bit,Unicode編碼)。
?????? 在這里將流分成字節流和字符流來對java中相應的處理類做一下分類,I/O一般用于對在文件和網絡之間流動的數據做處理,以處理以文件為載體的數據作為實例。
????????????????????????????????? ?
?????? 介紹一下常用到的流,先說一下字節流,處理字節流的兩個頂級抽象父類是處理輸入流的InputStream和處理輸出流的OutputStream。當處理文件時,可以使用他們的子類 FileInputStream 和 FileOutputStream,代碼如下:
public class StreamTest {public static void main(String[] args) {StreamTest test = new StreamTest(); // test.testFileInputStream(); // test.testFileOutputStream();test.testCopyFile();}/*** 使用輸入流讀取文件中的信息,然后打印* @author chaizepeng**/public void testFileInputStream() {InputStream inputStream = null;File file = new File("E:\\test\\input.txt");try {inputStream = new FileInputStream(file);//將文件中的數據讀入到輸入流中byte[] b = new byte[1024];inputStream.read(b);//從輸入流中讀取1024個字節String s = new String(b, "utf-8");System.out.println(s);} catch (Exception e) {e.printStackTrace();}finally {//使用流操作非常耗資源,所以在使用完之后要及時關閉if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 使用輸出流寫出數據到文件中* @author chaizepeng**/public void testFileOutputStream() {File file = new File("E:\\test\\output.txt");OutputStream outputStream = null;try {outputStream = new FileOutputStream(file);//將數據流指向指定的文件String s = "hello world";byte[] bytes = s.getBytes("utf-8");outputStream.write(bytes);//將字節數組中的數據寫入到輸出流指向的文件中outputStream.flush();//刷新輸出流,保證數據寫入成功} catch (Exception e) {e.printStackTrace();}finally {//使用流操作非常耗資源,所以在使用完之后要及時關閉if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 將 E:\\test\\input.txt 復制到 E:\\test\\copy.txt* @author chaizepeng**/public void testCopyFile() {InputStream inputStream = null;OutputStream outputStream = null;File file = new File("E:\\test\\copy.txt");if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}try {inputStream = new FileInputStream("E:\\test\\input.txt");//將文件中的數據讀入到輸入流中//想往文件中追加信息時,使用另一個構造器即可:new FileOutputStream(file,true)outputStream = new FileOutputStream(file);//將輸出流對準一個文件byte[] b = new byte[1024];int len = 0;while ((len = inputStream.read(b,0,b.length)) != -1) {//每次讀取1024個字節outputStream.write(b,0,len);//將讀取到的字節序列寫入到輸出流對應的文件中,知道輸入流在文件中獲取到的數據列長度為0}outputStream.flush();} catch (Exception e) {e.printStackTrace();}finally {//使用流操作非常耗資源,所以在使用完之后要及時關閉try {if (outputStream != null) {outputStream.close();}if (inputStream != null) {inputStream.close();} }catch (IOException e) {e.printStackTrace();}}} }想將數據從內存中讀出并寫入到另一塊內存中時可以使用子類 ByteArrayInputStream 和 ByteArrayOutputStream ,代碼如下:
public class ByteArrayStreamTest {public static void main(String[] args) {ByteArrayStreamTest test = new ByteArrayStreamTest();test.testByteArrayStream();}/*** 用于在內存中輸入和輸出,不必依賴磁盤,也就是不用創建File類* 因為處理的是內存中的數據,所以也不是非要關閉資源不可*/public void testByteArrayStream() {//ByteArrayInputStream 用于從內存中(不是在磁盤上)讀入數據并創建一個輸入流對象byte []b = "hello world".getBytes();ByteArrayInputStream inputStream = new ByteArrayInputStream(b);ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);byte []temp = new byte[4];//創建一個臨時的數組,用于轉移數據int len = 0;while ((len = inputStream.read(temp,0,temp.length) ) != -1) {outputStream.write(temp,0,len);//將內存中}System.out.println(outputStream.toString());//在輸出流中獲取寫入到指定內存的數據} }??????? 說一下字符流,例如:當處理一些中文文件時,使用字節流如果遇到突發事件可能會因為編碼問題導致文件損壞,處理一些中文文件時可以選擇字符流(處理文本文件時都可使用,為了不必要的麻煩,最好使用字節流),處理一些非文本文件時必須使用字節流。字符流的兩個頂級接口是Reader和Writer,如果處理文件時可以使用FileReader和FileWriter,代碼如下:
public class CharStreamTest {public static void main(String[] args) {CharStreamTest test = new CharStreamTest();test.testReaderTest();}/*** 將E:\\test\\reader.txt 復制到 E:\\test\\writer.txt **/public void testReaderTest() {FileWriter writer = null;FileReader reader = null;File file = new File("E:\\test\\writer.txt");if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}try {reader = new FileReader("E:\\test\\reader.txt");writer = new FileWriter(file);char []b = new char[1024];int len = 0;while((len = reader.read(b, 0, b.length)) != -1) {writer.write(b, 0, len);}writer.flush();} catch (IOException e) {e.printStackTrace();}finally {//使用流操作非常耗資源,所以在使用完之后要及時關閉try {if (writer != null) {writer.close();}if (reader != null) {reader.close();} }catch (IOException e) {e.printStackTrace();}}}}????????為了提高讀入和寫出的效率,java提供了緩沖流,使用緩沖流就相當于在內存中直接獲取數據,而不需要頻繁的去調用外部方法操作磁盤,大大提高了效率,緩沖流中維護了一個內存數組,每次讀取數據時都在數組中獲取,通過一定的機制當數組中沒有數據或者數據已經讀取完時就會調用一次應用的c或c++的方法操作一次磁盤,提高了效率。源碼分析如下:
//通過源碼來解釋為什么緩沖流效率高//首先看一下不使用緩沖流//FileInputStream中的read方法,全都是最后調用native修飾的c或者c++的方法//也就是說當使用FileInputStream去讀取數據時,每讀取一次,都會去磁盤中獲取一次數據//每次都去訪問磁盤導致效率底public int read() throws IOException {return read0();}private native int read0() throws IOException;private native int readBytes(byte b[], int off, int len) throws IOException;public int read(byte b[]) throws IOException {return readBytes(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {return readBytes(b, off, len);}//BufferedInputStream中的read方法,//創建緩沖流對象時,維護了一個數組,public BufferedInputStream(InputStream in, int size) {buf = new byte[size];}//調用的read方法public synchronized int read(byte b[], int off, int len){//刪減一些代碼,read中會調用read1方法int nread = read1(b, off + n, len - n);//在內存數組中獲取數據,而不是去磁盤中獲取,這也就是網上一直所說的不再是讀一次獲取一次,而是一次性讀取多個放到內存中,大大節省了效率System.arraycopy(getBufIfOpen(), pos, b, off, cnt);}//調用的read1方法private int read1(byte[] b, int off, int len) throws IOException {//刪減一些代碼,read1中會調用InputStream中的read方法getInIfOpen().read(b, off, len);}//調用的read1方法getInIfOpenprivate InputStream getInIfOpen() throws IOException {//而返回的正好是構造緩沖流時傳入的字節流in,所以說到底,最后直接去磁盤獲取數據的還是應用的c/c++的代碼,只不過一次獲取固定大小長度的字節數據放到緩沖流類中維護的內存數組中InputStream input = in;if (input == null)throw new IOException("Stream closed");return input;}針對字節流提供了BufferedInputStream 和 BufferedOutputStream 兩個緩沖流,用法如下:
public class BufferStreamTest {public static void main(String[] args) {BufferStreamTest test = new BufferStreamTest();test.testInputBufferedStream();}public void testInputBufferedStream() {BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream = null;File file = new File("E:\\test\\bufferedoutput.ppt");try {bufferedInputStream = new BufferedInputStream(new FileInputStream("E:\\czp\\Learning Materials\\筆記\\io.ppt"));bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));byte[] b = new byte[1024];int len;while((len = bufferedInputStream.read(b ,0 ,b.length)) != -1) {bufferedOutputStream.write(b, 0, len);}bufferedOutputStream.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if (bufferedOutputStream!=null) {bufferedOutputStream.close();}if (bufferedInputStream!=null) {bufferedInputStream.close();}} catch (Exception e2) {e2.printStackTrace();}}} }針對字符流提供了BufferedReader 和 BufferedWriter ,用法如下:
public class BufferStreamTest {public static void main(String[] args) {BufferStreamTest test = new BufferStreamTest();test.testBufferCharStream();}public void testBufferCharStream() {BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;File file = new File("E:\\test\\bufferedreader.txt");try {FileReader reader = new FileReader("E:\\czp\\Learning Materials\\ceshi.txt");//BufferedReader 的數據源是一個字符輸入流bufferedReader = new BufferedReader(reader);bufferedWriter = new BufferedWriter(new FileWriter(file));String s = "";while( (s = bufferedReader.readLine()) != null) {//每次讀取一行數據System.out.println(s);bufferedWriter.write(s);bufferedWriter.newLine();//換行bufferedWriter.flush();//刷新緩沖區} } catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//關閉資源try {if (bufferedWriter!=null) {bufferedWriter.close();}if (bufferedReader!=null) {bufferedReader.close();}} catch (Exception e2) {e2.printStackTrace();}}} }有的時候想用字符流進行數據的讀寫,但是呢,提供的只有數據的字節流,這時便可使用轉換流,代碼如下:
public class ConvertStreamTest {public static void main(String[] args) throws IOException {ConvertStreamTest test = new ConvertStreamTest();test.testInputStreamReader();test.testOutputStreamWriter();}/*** 字節輸入流轉換成字符輸入流 */public void testInputStreamReader() throws IOException {FileInputStream fileInputStream = null;//字節輸入流Reader inputStreamReader = null;//字符輸入流try {//獲取一個字節輸入流fileInputStream = new FileInputStream("E:\\czp\\Learning Materials\\ceshi.txt");//通過轉換輸入流 InputStreamReader 的構造方法構造一個字符輸入流inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");char []ch = new char[2048];inputStreamReader.read(ch);//正常的在流中讀取數據System.out.println(new String(ch));} catch (Exception e) {}finally {if (inputStreamReader!=null) {inputStreamReader.close();}if (fileInputStream!= null) {fileInputStream.close();}}}/*** 字節輸出流轉換成字符輸出流 */public void testOutputStreamWriter() throws IOException {FileOutputStream fileOutputStream = null;Writer writer = null;try {fileOutputStream = new FileOutputStream("E:\\test\\bufferedreader.txt");writer = new OutputStreamWriter(fileOutputStream, "gbk");writer.write("測試轉換流");} catch (Exception e) {}finally {if (writer != null) {writer.close();}if (fileOutputStream!=null) {fileOutputStream.close();}}} }?
使用java也可實現文件的壓縮和解壓縮,使用到的兩個類是:GZIPInputStream、GZIPOutputStream,他們是util包下的類,不是io包下。代碼如下:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream;public class GZIPStreamTest {public static void main(String[] args) throws IOException {GZIPStreamTest test = new GZIPStreamTest();test.testZipStream();test.testUnZipStream();}/*** 壓縮操作* 將E:\\czp\\Learning Materials\\ceshi.txt 壓縮到 E:\\test\\a.zip*/public void testZipStream() throws IOException {FileInputStream fileInputStream = null;FileOutputStream fileOutputStream = null;GZIPOutputStream gzipOutputStream = null;File file = new File("E:\\test\\a.zip");try {fileInputStream = new FileInputStream("E:\\czp\\Learning Materials\\ceshi.txt");fileOutputStream = new FileOutputStream(file);gzipOutputStream = new GZIPOutputStream(fileOutputStream);byte []by = new byte[1024];int len = 0;while((len = fileInputStream.read(by, 0, by.length)) != -1) {gzipOutputStream.write(by, 0, len);gzipOutputStream.flush();}} catch (Exception e) {}finally {if (gzipOutputStream != null) {gzipOutputStream.close();}if (fileOutputStream != null) {fileOutputStream.close();}if (fileInputStream != null) {fileInputStream.close();}}}/*** 解壓操作*/public void testUnZipStream() throws IOException {FileInputStream fileInputStream = null;FileOutputStream fileOutputStream = null;GZIPInputStream gzipInputStream = null;File file = new File("E:\\test\\b.txt");try {fileInputStream = new FileInputStream("E:\\test\\a.zip");gzipInputStream = new GZIPInputStream(fileInputStream);fileOutputStream = new FileOutputStream(file);byte []by = new byte[1024];int len = 0;while((len = gzipInputStream.read(by, 0, by.length)) != -1) {fileOutputStream.write(by, 0, len);fileOutputStream.flush();}} catch (Exception e) {}finally {if (fileOutputStream != null) {fileOutputStream.close();}if (gzipInputStream != null) {gzipInputStream.close();}if (fileInputStream != null) {fileInputStream.close();}}} }以上只是對java中I/O體系中常用的幾個類做了簡單的介紹,真正用的時候可以參考API。
總結
以上是生活随笔為你收集整理的11、java中的I/O流(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10、java中文件的抽象表示
- 下一篇: 12、java中的I/O流(2)