Java-Java I/O流解读之基于字节的I / O和字节流
- 概述
- File and Directory
- Class javaioFile Pre-JDK 7
- Verifying Properties of a FileDirectory
- List Directory
- List Directory with Filter
- Class javaniofilePath JDK 7
- Class javaioFile Pre-JDK 7
- Stream IO in Standard IO javaio Package 標準I O中的流I Ojavaio包
- Byte-Based IO Byte Streams 基于字節的I O和字節流
- Reading from an InputStream
- Writing to an OutputStream
- Opening Closing IO Streams
- Flushing the OutputStream
- Implementations of abstract InputStreamOutputStream
- Layered or Chained IO Streams 分層或鏈接I O流
- File IO Byte-Streams - FileInputStream FileOutputStream
- Buffered IO Byte-Streams - BufferedInputStream BufferedOutputStream
- 示例
- Example 1 Copying a file byte-by-byte without Buffering
- Example 2 Copying a file with a Programmer-Managed Buffer 使用自定義的Buf
- Example 3 Copying a file with Buffered Streams
- Formatted Data-Streams DataInputStream DataOutputStream
- 代碼
概述
編寫簡單的 I / O操作很簡單,僅僅涉及到很少的類和方法。 但是編寫高效,便攜式I / O非常困難,特別是如果我們必須處理不同的字符集。 這就解釋了為什么有這么多的I / O包(在JDK 1.7中有9個)!
JDK有兩套 I / O 包:
- 自JDK 1.0引入的基于流的I / O的標準I / O(在包java.io中)
- 在JDK 1.4中引入的新的I / O(在java.nio包中)用于更有效的基于緩沖區的I / O
JDK 1.5通過新類java.util.Scanner和Formatter引用格式化的文本I / O,并使用格式說明符格式化輸出的C-like printf()和format()方法.
JDK 1.7通過新的包java.nio.file及其輔助包中的所謂的NIO.2(非阻塞I / O)來增強對文件I / O的支持。 它還引入了一種新的try-with-resources語法來簡化close()方法的編碼。
File and Directory
Class java.io.File (Pre-JDK 7)
java.io.File 可以表述一個文件 或者一個目錄 (JDK1.7中 引入了一個更加強大的接類 java.nio,file.Path,克服了java.io.File中的很多限制。)
路徑字符串用于定位文件或目錄。 不幸的是,路徑字符串是系統相關的
例如:
Windows中的“c:\myproject\java\Hello.java”
Unix / Mac中的“/myproject/java/Hello.java”
- 目錄分隔符: Windows使用反斜杠’\’作為目錄分隔符; 而Unixes / Mac使用前斜杠’/’。
- 路徑分隔符:Windows使用分號’;’ 作為路徑分隔符來分隔路徑列表; 而Unixes / Mac使用冒號’:’
- 行分隔符:Windows中使用“ \r\n”作為行分隔符的文本文件; 而Unix系統使用“ \n”和Mac使用“ \r”
- 根目錄:在“ c:\”或“ \”被稱為根。Windows支持多根,每一個映射到一個驅動器(例如,“ c:\”,“ d:\“)。而Unix / Mac有一個根(” \“)
文件路徑可以是絕對的(從根開始)或相對(相對于引用目錄)。 特殊符號 . 和..分別表示當前目錄和父目錄。
java.io.File類維護這些依賴于系統的屬性,我們可以編寫可移植的程序
目錄分隔符: 靜態字符串字段 File.separator 和 File.separatorChar [他們沒有遵循從JDK 1.2采用的常規Java命名約定。]如上所述,Windows使用反斜杠’\’; 而Unixes / Mac使用正斜杠’/’。
路徑分隔符:靜態字符串字段 File.pathSeparator和 File.pathSeparatorChar。 如前所述,Windows使用分號’;’ 分隔路徑列表; 而Unixes / Mac使用冒號’:’。
windows 環境下輸出:
; ; \ \我們可以使用路徑字符串或URI構造一個File實例,如下所示。
請注意,物理文件/目錄可能存在或可能不存在。
文件URL采用file:// …的形式,例如file:/// d:/docs/programming/java/test.html。
舉例:
// A file relative to the current working directory File file1 = new File("xgj.txt");// A file with absolute path D:\workspace\ws-java-base\JavaMaster File file2 = new File("D:\\xgj.txt");// A file with parent and child File parent = new File("D:\\temp"); File child = new File(parent, "xgj.txt");// A directory File dir = new File("D:\\temp");如果你打算將應用封裝成jar包,應該使用URL類來引用資源,因為它可以引用磁盤文件以及JAR文件,例如,
java.net.URL url = this.getClass().getResource("icon.png");Verifying Properties of a File/Directory
public boolean exists() // Tests if this file/directory exists. public long length() // Returns the length of this file. public boolean isDirectory() // Tests if this instance is a directory. public boolean isFile() // Tests if this instance is a file. public boolean canRead() // Tests if this file is readable. public boolean canWrite() // Tests if this file is writable. public boolean delete() // Deletes this file/directory. public void deleteOnExit() // Deletes this file/directory when the program terminates. public boolean renameTo(File dest) // Renames this file. public boolean mkdir() // Makes (Creates) this directory.List Directory
如果是目錄的話,我們可以通過下面的方法列出內容
public String[] list() // List the contents of this directory in a String-array public File[] listFiles() // List the contents of this directory in a File-array示例:
package com.xgj.master.java.io.fileDemo;import java.io.File;/*** * * @ClassName: ListDirectoryRecusive* * @Description: Recursively list the contents of a directory* * @author: Mr.Yang* * @date: 2017年9月6日 下午6:27:01*/ public class ListDirectoryRecusive {public static void main(String[] args) {File dir = new File("D:\\OneDrive");listDirectoryRecusive(dir);}/*** * * @Title: listDirectoryRecusive* * @Description: 遍歷目錄下的內容(包括子孫目錄)* * @param dir* * @return: void*/public static void listDirectoryRecusive(File dir) {if (dir.isDirectory()) {File[] items = dir.listFiles();for (File item : items) {System.out.println(item.getAbsolutePath());// Recursive call 如果目錄下還有目錄if (item.isDirectory()) {listDirectoryRecusive(item);}}}} }輸出結果:
D:\OneDrive\desktop.ini D:\OneDrive\公開 D:\OneDrive\公開\2.txt D:\OneDrive\圖片 D:\OneDrive\圖片\1.txt D:\OneDrive\文檔 D:\OneDrive\文檔\MasterJava.pptx D:\OneDrive\文檔\新建 D:\OneDrive\文檔\新建\23讓34.mppList Directory with Filter
當然了我們也可以將過濾器應用于list()和listFiles(),以僅列出滿足特定條件的文件。
public String[] list(FilenameFilter filter) public File[] listFiles(FilenameFilter filter) public File[] listFiles(FileFilter filter)java.io.FilenameFilter接口定義了一個抽象方法
public boolean accept(File dirName, String fileName)list()和listFiles()方法對所生成的每個文件/子目錄執行回調accept()。 我們可以在accept()中編寫過濾條件。 不符合的文件/子目錄將被排除。
示例:
package com.xgj.master.java.io.fileDemo;import java.io.File; import java.io.FilenameFilter;import org.junit.Test;/*** * * @ClassName: ListDirectoryWithFilter* * @Description: List files that end with "pptx"* * @author: Mr.Yang* * @date: 2017年9月6日 下午7:50:13*/ public class ListDirectoryWithFilter {/*** * * @Title: listDirectoryWithFilter* * @Description: 遍歷某個目錄下所有以pptx結尾的文件或者目錄* * @param dir* * @return: void*/public void listDirectoryWithFilter(File dir) {if (dir.isDirectory()) {// List only files that meet the filtering criteria// programmed in accept() method of FilenameFilter.String[] files = dir.list(new FilenameFilter() {@Overridepublic boolean accept(File dir, String file) {return file.endsWith("pptx");}});// an anonymous inner class as FilenameFilterfor (String file : files) {System.out.println(file);}}}@Testpublic void test() {listDirectoryWithFilter(new File("D:\\OneDrive\\文檔"));}}輸出:
MasterJava.pptx pptxClass java.nio.file.Path (JDK 7)
另外開篇闡述
Stream I/O in Standard I/O (java.io Package) 標準I / O中的流I / O(java.io包)
程序從數據源(例如鍵盤,文件,網絡,存儲器緩沖器或另一程序)讀取輸入,并向數據宿(例如,顯示控制臺,文件,網絡,存儲器緩沖器或另一程序)寫入輸出。
在Java標準I / O中,輸入和輸出由所謂的流(Stream)處理。
流是連續的單向數據流(就像水或油流過管道)。重要的是要提到Java不區分流I / O中的各種類型的數據源或匯(例如文件或網絡)。它們都被視為一個順序的數據流。輸入和輸出流可以從任何數據源/匯點(如文件,網絡,鍵盤/控制臺或其他程序)建立。
Java程序通過打開輸入流從源接收數據,并通過打開輸出流將數據發送到宿。
所有Java I / O流都是單向的(除了RandomAccessFile,稍后將討論)。
如果你的程序需要執行輸入和輸出,則必須打開兩個流 - 輸入流和輸出流。
操作I / O流,分為3步:
Java的I / O操作比C / C ++更復雜以支持國際化(i18n)。 Java內部將字符(字符類型)存儲在16位UCS-2字符集中。 但外部數據源/接收器可以將字符存儲在其他字符集(例如US-ASCII,ISO-8859-x,UTF-8,UTF-16等等)中,固定長度為8位或16位, 位或以1到4字節的可變長度。 [讀取“字符集和編碼方案”]。
因此,Java需要區分用于處理原始字節或二進制數據的基于字節的I / O以及用于處理由字符組成的文本的基于字符的I / O。
Byte-Based I/O & Byte Streams 基于字節的I / O和字節流
字節流用于從外部設備串行讀取/寫入原始字節。 所有字節流都是從抽象超類InputStream和OutputStream派生的,如類圖所示。
Reading from an InputStream
抽象類 InputStream中聲明了一個抽象方法read() 從輸入源讀取一個數據字節
public abstract int read() throws IOException;read()方法:
返回輸入字節讀取為int,范圍為0到255,或
如果檢測到“流結束”條件,則返回-1
如果遇到I / O錯誤,則拋出IOException。
read()方法返回一個int而不是一個字節,因為它使用-1表示流末尾。
read()方法將會block,直到一個字節可用或者發生I / O錯誤或檢測到“end-of-stream”。
術語“block”表示方法(和程序)將被暫停。 只有當方法返回時,程序才會恢復。
在InputStream中實現了兩種read()方法,用于將字節塊讀入字節數組。
它返回讀取的字節數. 如果“end-of-stream”遇到,則返回-1。
Writing to an OutputStream
與輸入對應類似,抽象超類OutputStream聲明一個抽象方法write()來將數據字節寫入輸出接收器。 write()入參為一個int。 int參數的最低有效字節被寫出; 高于3字節被丟棄。 如果發生I / O錯誤(例如,輸出流已關閉),則會拋出IOException。
public void abstract void write(int unsignedByte) throws IOException和 InputStream中的read()相似,OutputStream中實現了兩種write()方法從字節數組中寫入一個字節塊
// Write "length" number of bytes, from the bytes array starting from offset of index. public void write(byte[] bytes, int offset, int length) throws IOException // Same as write(bytes, 0, bytes.length) public void write(byte[] bytes) throws IOExceptionOpening & Closing I/O Streams
我們通過構建流的實例來打開I / O流。 InputStream和OutputStream都提供了一個close()方法來關閉流,該流執行必要的清理操作以釋放系統資源。
public void close() throws IOException // close this Stream通過在try-catch-finally的finally子句中運行close()來明確地關閉I / O流是一個很好的做法,以便在不再需要流時立即釋放系統資源。 這可以防止嚴重的資源泄漏。
不幸的是,close()方法也拋出一個IOException,并且需要包含在一個嵌套的try-catch語句中,如下所示。 這使得代碼變得很丑陋。
InputStream in = null;try {in = new FileInputStream(...);........} catch (FileNotFoundException e) {e.printStackTrace();} finally {try {in.close();} catch (IOException e) {e.printStackTrace();}}JDK 1.7引入了一種新的try-with-resources語法,它會在try或catch之后自動關閉所有打開的資源,如下所示。 這樣的代碼看起來更加的優雅。
// Automatically closes all opened resource in try (...). try (FileInputStream in = new FileInputStream(...)) {....... } catch (Exception e) {e.printStackTrace(); }Flushing the OutputStream
OutputStream提供了一個flush()方法來從輸出緩沖區中刷新剩余的字節。
public void flush() throws IOException // Flush the outputImplementations of abstract InputStream/OutputStream
InputStream和OutputStream是不能被實例化的抽象類。 我們需要選擇一個適當的具體子類來建立與物理設備的連接。 例如,可以實例化FileInputStream或FileOutputStream以建立到物理磁盤文件的流。
Layered (or Chained) I/O Streams 分層(或鏈接)I / O流
I / O流通常與其他I / O流分層或鏈接,用于緩沖,過濾或數據格式轉換(原始字節和原始類型之間)的目的。 例如,我們可以將BufferedInputStream分層到一個FileInputStream進行緩沖輸入,并在前面堆疊一個DataInputStream進行格式化數據輸入(使用諸如int,double等原語),如下圖所示。
File I/O Byte-Streams - FileInputStream & FileOutputStream
FileInputStream和FileOutputStream是抽象類InputStream和OutputStream的具體實現,用于從磁盤文件支持I / O。
Buffered I/O Byte-Streams - BufferedInputStream & BufferedOutputStream
InputStream / OutputStream中的read()/ write()方法旨在讀/寫每個調用的單字節數據。 這是非常低效的,因為每個調用由底層操作系統處理(可能會觸發磁盤訪問或其他昂貴的操作)。 在單個I / O操作中,從外部設備讀取/寫入內存緩沖區的緩沖區通常用于加速I / O。
FileInputStream / FileOutputStream沒有緩沖。 它通常鏈接到BufferedInputStream或BufferedOutputStream,它提供緩沖。 要將流鏈接在一起,只需將一個流的實例傳遞到另一個流的構造函數中。
例如,以下代碼將FileInputStream鏈接到BufferedInputStream,最后是一個DataInputStream
FileInputStream in = new FileInputStream(new File("D:\\xgj.txt"));BufferedInputStream bis = new BufferedInputStream(in);DataInputStream dis = new DataInputStream(bis); // or DataInputStream dis2 = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("D:\\xgj.txt"))));示例:
Example 1: Copying a file byte-by-byte without Buffering.
maven工程
package com.xgj.master.java.io.fileDemo;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;import org.junit.Test; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;/*** * * @ClassName: FileCopyNoBuffer* * @Description: FileCopyNoBuffer* * @author: Mr.Yang* * @date: 2017年9月6日 下午10:53:17*/ public class FileCopyNoBufferPreJDK7 { // Pre-JDK 7@Testpublic void test() {// 利用Spring提供的Resource/ResourceLoader接口操作資源文件ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();Resource resource = resourcePatternResolver.getResource("classpath:com/xgj/master/java/io/fileDemo/SQL.Cookbook.pdf");FileInputStream in = null;FileOutputStream out = null;long startTime, elapsedTime; // for speed benchmarkingtry {// Print file lengthFile fileIn = resource.getFile();System.out.println("File size is " + fileIn.length() / 1024 / 1024 + " MB");in = new FileInputStream(fileIn);out = new FileOutputStream(new File("D:\\NoBufferPreJDK7.pdf"));startTime = System.nanoTime();int byteRead;// Read a raw byte, returns an int of 0 to 255.while ((byteRead = in.read()) != -1) {// Write the least-significant byte of int, drop the upper 3// bytesout.write(byteRead);}// cost timeelapsedTime = System.nanoTime() - startTime;System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");} catch (IOException e) {e.printStackTrace();} finally {// JDK7之前的寫法,在finally中關閉流try {if (in != null)in.close();if (out != null)out.close();} catch (IOException e) {e.printStackTrace();}}}}此示例通過從輸入文件讀取一個字節并將其寫入輸出文件來復制文件。 它直接使用FileInputStream和FileOutputStream進行緩沖。
請注意,大多數I / O方法“拋出”IOException,它必須被捕獲或聲明為拋出。
close()方法在finally子句中,確保try 或者catch后能夠關閉流。 然而,close()方法也會拋出一個IOException,因此必須封裝在一個嵌套的try-catch塊中,這樣使代碼有點難看。
在這里使用了 JDK 1.5中引入的System.nanoTime()來更準確地測量經過的時間,而不是傳統的不精確的System.currentTimeMillis()。
如前所述,JDK 1.7引入了一種新的try-with-resources語法,它會在try或catch之后自動關閉所有打開的資源。 例如,上述示例可以按照如下方式重新編寫:
package com.xgj.master.java.io.fileDemo;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;import org.junit.Test; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;/*** * * @ClassName: FileCopyNoBufferJDK7* * @Description: FileCopyNoBufferJDK7* * @author: Mr.Yang* * @date: 2017年9月6日 下午11:02:50*/ public class FileCopyNoBufferJDK7 {@Testpublic void test() {// 利用Spring提供的ResourcePatternResolver操作資源文件 同時支持Ant風格的資源路徑表達式ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();Resource resource = resourcePatternResolver.getResource("classpath:com/xgj/master/java/io/fileDemo/281015.jpg");long startTime, elapsedTime; // for speed benchmarking// DK 1.7引入了一種新的try-with-resources語法,// 它會在try或catch之后自動關閉所有打開的資源,如下所示。// 這樣的代碼看起來更加的優雅。try (FileInputStream in = new FileInputStream(resource.getFile());FileOutputStream out = new FileOutputStream(new File("D:\\test.jpg"))) {// Print file lengthFile fileIn = resource.getFile();System.out.println("File size is " + fileIn.length() / 1024 / 1024 + " MB");startTime = System.nanoTime();int byteRead;// Read a raw byte, returns an int of 0 to 255.while ((byteRead = in.read()) != -1) {// Write the least-significant byte of int, drop the upper 3// bytesout.write(byteRead);}// cost timeelapsedTime = System.nanoTime() - startTime;System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");} catch (IOException e) {e.printStackTrace();}} }運行結果:
File size is 26 MB Elapsed Time is 333595.85495 msec耗費 333595.85495 毫秒 大約是 333S ,也就是5分半鐘……
Example 2: Copying a file with a Programmer-Managed Buffer. 使用自定義的Buf
package com.xgj.master.java.io.fileDemo;import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;import org.junit.Test; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;public class FileCopyUserBufferPreJDK7 {@Testpublic void test() {// 利用Spring提供的ResourcePatternResolver操作資源文件 同時支持Ant風格的資源路徑表達式ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();Resource resource = resolver.getResource("com/xgj/master/java/io/fileDemo/SQL.Cookbook.pdf");FileInputStream in = null;FileOutputStream out = null;long startTime, elapsedTime; // for speed benchmarkingtry {// Print file lengthFile fileIn = resource.getFile();System.out.println("File size is " + fileIn.length() / 1024 / 1024 + " MB");in = new FileInputStream(fileIn);out = new FileOutputStream(new File("D:\\FileCopyUserBufferPreJDK7.pdf"));startTime = System.nanoTime();// 4K byte-buffer 每次讀取4Kbyte[] byteBuf = new byte[4096];int numByteRead;while ((numByteRead = in.read(byteBuf)) != -1) {out.write(byteBuf, 0, numByteRead);}// cost timeelapsedTime = System.nanoTime() - startTime;System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 關閉流 切記try {if (in != null)in.close();if (out != null)out.close();} catch (IOException e) {e.printStackTrace();}}} }運行結果
File size is 26 MB Elapsed Time is 198.8157 msec此示例再次直接使用FileInputStream和FileOutputStream。 但是,它不是一次讀取/寫入一個字節,而是讀/寫一個4KB塊。 這個程序只花了198毫秒 , 和第一個不使用緩沖 ,速度相比提高了1600多倍,效率不言而喻。
較大的緩沖區大小,達到一定限度,通常會提高I / O性能。 然而,在加速和內存使用之間存在權衡。 對于文件復制,肯定建議使用大型緩沖區。 但是,從文件讀取幾個字節,大型緩沖區只會浪費內存。
我使用JDK 1.7重新編寫程序,并嘗試在26MB的更大的文件上的各種緩沖區大小,如下
輸出結果:
1KB: 560.22msec2KB: 265.76msec4KB: 130.43msec8KB: 77.81msec16KB: 52.49msec32KB: 38.99msec64KB: 30.66msec256KB: 31.00msec 1024KB: 73.45msec從結果中可以看出一些端倪,并不是緩沖區越大效率要高,存在某個平衡。
Example 3: Copying a file with Buffered Streams.
package com.xgj.master.java.io.fileDemo;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;import org.junit.Test; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;public class FileCopyBufferedStreamPreJDK7 {@Testpublic void test() {ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();Resource resource = resolver.getResource("com/xgj/master/java/io/fileDemo/SQL.Cookbook.pdf");BufferedInputStream bis = null;BufferedOutputStream bos = null;long startTime = 0, elapsedTime; // for speed benchmarkingtry {bis = new BufferedInputStream(new FileInputStream(resource.getFile()));bos = new BufferedOutputStream(new FileOutputStream("D:\\artisan.pdf"));startTime = System.nanoTime();int byteRead;// Read byte-by-byte from bufferwhile ((byteRead = bis.read()) != -1) {bos.write(byteRead);}elapsedTime = System.nanoTime() - startTime;System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally { // always close the streamstry {if (bis != null) {bis.close();}if (bos != null) {bis.close();}} catch (IOException e) {e.printStackTrace();}}} }輸出結果:
Elapsed Time is 1432.864941 msec在這個例子中,我用BufferedInputStream連接FileInputStream,使用BufferedOutputStream連接FileOutputStream,并逐個字節讀/寫。 JRE決定緩沖區大小。 該程序花費了1432.864941 毫秒,比例1高出,但慢于我們自定義管理的緩沖區。
JDK 1.7版本的例子如下:
package com.xgj.master.java.io.fileDemo;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream;import org.junit.Test; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;public class FileCopyBufferedStreamJDK7 {@Testpublic void test() {ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();Resource resource = resolver.getResource("com/xgj/master/java/io/fileDemo/SQL.Cookbook.pdf");long startTime = 0, elapsedTime; // for speed benchmarkingtry (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resource.getFile()));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\xgj_2.pdf")))) {// Check file lengthFile fileIn = resource.getFile();System.out.println("File size is " + fileIn.length() + " bytes");startTime = System.nanoTime();int byteRead;while ((byteRead = bis.read()) != -1) {bos.write(byteRead);}elapsedTime = System.nanoTime() - startTime;System.out.println("Elapsed Time is " + (elapsedTime / 1000000.0) + " msec");} catch (Exception e) {e.printStackTrace();}} }Formatted Data-Streams: DataInputStream & DataOutputStream
DataInputStream和DataOutputStream可以堆疊在任何InputStream和OutputStream之上,以解析原始字節,以便以所需的數據格式(如int和double)執行I / O操作。
DataInputStream 是數據輸入流。它繼承于FilterInputStream。
DataInputStream 是用來裝飾其它輸入流,它“允許應用程序以與機器無關方式從底層輸入流中讀取基本 Java 數據類型”。
應用程序可以使用DataOutputStream(數據輸出流)寫入由DataInputStream(數據輸入流)讀取的數據。
要使用DataInputStream進行格式化輸入,可以按如下方式鏈接輸入流:
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("in.dat")));DataInputStream實現了DataInput接口,它提供了讀取格式化的原始數據和字符串的方法,如:
// 8 Primitives public final int readInt() throws IOExcpetion; // Read 4 bytes and convert into int public final double readDoube() throws IOExcpetion; // Read 8 bytes and convert into double public final byte readByte() throws IOExcpetion; public final char readChar() throws IOExcpetion; public final short readShort() throws IOExcpetion; public final long readLong() throws IOExcpetion; public final boolean readBoolean() throws IOExcpetion; // Read 1 byte. Convert to false if zero public final float readFloat() throws IOExcpetion;public final int readUnsignedByte() throws IOExcpetion; // Read 1 byte in [0, 255] upcast to int public final int readUnsignedShort() throws IOExcpetion; // Read 2 bytes in [0, 65535], same as char, upcast to int public final void readFully(byte[] b, int off, int len) throws IOException; public final void readFully(byte[] b) throws IOException;// Strings public final String readLine() throws IOException;// Read a line (until newline), convert each byte into a char - no unicode support. public final String readUTF() throws IOException;// read a UTF-encoded string with first two bytes indicating its UTF bytes lengthpublic final int skipBytes(int n) // Skip a number of bytes同樣,你可以按如下方式堆疊DataOutputStream:
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("out.dat")));DataOutputStream實現DataOutput接口,它提供寫入格式化的原始數據和String的方法。 例如,
// 8 primitive types public final void writeInt(int i) throws IOExcpetion; // Write the int as 4 bytes public final void writeFloat(float f) throws IOExcpetion; public final void writeDoube(double d) throws IOExcpetion; // Write the double as 8 bytes public final void writeByte(int b) throws IOExcpetion; // least-significant byte public final void writeShort(int s) throws IOExcpetion; // two lower bytes public final void writeLong(long l) throws IOExcpetion; public final void writeBoolean(boolean b) throws IOExcpetion; public final void writeChar(int i) throws IOExcpetion;// String public final void writeBytes(String str) throws IOExcpetion; // least-significant byte of each char public final void writeChars(String str) throws IOExcpetion;// Write String as UCS-2 16-bit char, Big-endian (big byte first) public final void writeUTF(String str) throws IOException; // Write String as UTF, with first two bytes indicating UTF bytes lengthpublic final void write(byte[] b, int off, int len) throws IOException public final void write(byte[] b) throws IOException public final void write(int b) throws IOException // Write the least-significant byte舉例: 以下程序將一些原始語寫入磁盤文件。 然后,它讀取原始字節以檢查原始語的存儲方式。 最后,它讀取數據作為原始語。
package com.xgj.master.java.io.fileDemo;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;public class DataIOStream {public static void main(String[] args) {ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();Resource resource = resolver.getResource("com/xgj/master/java/io/fileDemo/data-out.txt");String message = "Hi,您好!";// Write primitives to an output filetry (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(resource.getFile())))) {out.writeByte(127);out.writeShort(0xFFFF); // -1out.writeInt(0xABCD);out.writeLong(0x1234_5678); // JDK 7 syntaxout.writeFloat(11.22f);out.writeDouble(55.66);out.writeBoolean(true);out.writeBoolean(false);for (int i = 0; i < message.length(); ++i) {out.writeChar(message.charAt(i));}out.writeChars(message);out.writeBytes(message);out.flush();} catch (IOException ex) {ex.printStackTrace();}// Read raw bytes and print in Hextry (BufferedInputStream in = new BufferedInputStream(new FileInputStream(resource.getFile()))) {int inByte;while ((inByte = in.read()) != -1) {System.out.printf("%02X ", inByte); // Print Hex codes}System.out.printf("%n%n");} catch (IOException ex) {ex.printStackTrace();}// Read primitivestry (DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(resource.getFile())))) {System.out.println("byte: " + in.readByte());System.out.println("short: " + in.readShort());System.out.println("int: " + in.readInt());System.out.println("long: " + in.readLong());System.out.println("float: " + in.readFloat());System.out.println("double: " + in.readDouble());System.out.println("boolean: " + in.readBoolean());System.out.println("boolean: " + in.readBoolean());System.out.print("char: ");for (int i = 0; i < message.length(); ++i) {System.out.print(in.readChar());}System.out.println();System.out.print("chars: ");for (int i = 0; i < message.length(); ++i) {System.out.print(in.readChar());}System.out.println();System.out.print("bytes: ");for (int i = 0; i < message.length(); ++i) {System.out.print((char) in.readByte());}System.out.println();} catch (IOException ex) {ex.printStackTrace();}} }輸出結果分析:
存儲在磁盤中的數據與內部Java程序的格式完全相同(例如,用于字符的UCS-2)。 字節順序是big-endian(大字節優先,最低地址中最高有效字節)。
代碼
代碼已托管到Github—> https://github.com/yangshangwei/JavaMaster
總結
以上是生活随笔為你收集整理的Java-Java I/O流解读之基于字节的I / O和字节流的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-AOP @AspectJ切
- 下一篇: Java-Java I/O流解读之基于字