首先我們得知道:我們儲存在硬碟上的檔案是byte byte byte...儲存的,是資料的集合。
java 中的 io 流主要分為:
- 位元組流
- 字元流
一、位元組流
位元組流又分為
- 輸入流 InputStream
- 輸出流 OutputStream
輸入流負責從 源(可以是檔案) 讀取資料到 Java程式 中。
輸出流負責把 Java程式 中資料寫入到 源(可以是檔案) 中。
1.1 輸入流 InputStream
InputStream 是一個抽象類,抽象了應用程式讀取資料的方式。
輸入流基本方法:
- int b = in.read();讀取一個位元組無符號填充到int低八位.-1是 EOF
- in.read(byte[] buf)
- in.read(byte[] buf,int start,int size)
常用的實現類有以下三個
1.1.1 FileInputStream
FileInputStream 用於從檔案讀取資料,可以通過 new 關鍵字構造,比如:
File file = new File(檔案路徑);
FileInputStream inputStream = new FileInputStream(file);
複製程式碼
也可以:
FileInputStream inputStream = new FileInputStream(檔案路徑);
複製程式碼
使用示例: 本示例從專案根目錄的 test.txt 讀取內容並列印,
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream("test.txt");
int len;
byte[] bytes = new byte[8 * 1024];
while ((len=inputStream.read(bytes,0,bytes.length))!=-1){
String s = new String(bytes,0,len,"utf-8");
System.out.println(s);
}
inputStream.close();
}
}
複製程式碼
1.1.1 DataInputStream
DataInputStream 對"流"功能的擴充套件,可以更加方便的讀取 int, long,字元等型別資料。
使用 Demo 如下:
public class DataInputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream("test.txt");
DataInputStream dataInputStream = new DataInputStream(inputStream);
int len;
byte[] buffer = new byte[8 * 1024];
while ((len = dataInputStream.read(buffer, 0, buffer.length)) != -1) {
System.out.println(new String(buffer,0,len));
}
inputStream.close();
dataInputStream.close();
}
}
複製程式碼
1.1.3 BufferedInputStream
BufferedInputStream 為 IO 提供了帶緩衝區的操作,一般開啟檔案進行寫入 或讀取操作時,都會加上緩衝,這種流模式提高了IO的效能。
使用如下:
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("test.txt"));
int len;
byte[] buffer = new byte[8*1024];
while ((len=bufferedInputStream.read(buffer,0,buffer.length))!=-1){
System.out.println(new String(buffer,0,len));
}
bufferedInputStream.close();
}
}
複製程式碼
1.2 輸出流 OutputStream
OutputStream 也是一個抽象類,抽象了應用程式寫資料的方式。
輸出流基本方法:
- out.write(int b) 寫出一個byte到流,b的低8位
- out.write(byte[] buf)將buf位元組陣列都寫入到流
- out.write(byte[] buf,int start,int size)
同樣,常用的輸出流實現類有下面三個:
1.2.1 FileOutputStream
FileOutputStream 用於寫入資料到檔案中,可以通過 new 關鍵字很輕鬆的建立
File file = new File(檔案路徑);
FileOutputStream outputStream = new FileOutputStream(file);
複製程式碼
或者
FileOutputStream outputStream = new FileOutputStream(檔案路徑);
複製程式碼
使用示例: 本示例是寫文字到專案根目錄的檔案 test.txt。
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream outputStream = new FileOutputStream("test.txt");
String s = "測試FileOutputStreamDemo";
outputStream.write(s.getBytes("utf-8"));
outputStream.close();
}
}
複製程式碼
1.2.2 DataOutputStream
DataOutputStream 對"流"功能的擴充套件,可以更加方便的寫入 int, long,字元等型別資料。
使用 demo 如下:
public class DataOutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream outputStream = new FileOutputStream("test.txt");
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeInt(123321);
dataOutputStream.writeBoolean(true);
dataOutputStream.writeUTF("DataOutputStreamDemo測試");
outputStream.close();
dataOutputStream.close();
}
}
複製程式碼
如果按照上面執行是會發現,只能在 test.txt 檔案中看到
DataOutputStreamDemo測試
複製程式碼
前面寫入的 123321 和 true 都是亂碼,比如我這邊看到的是
那是因為 DataOutputStream 是一種格式化的資料輸出方式,而並非都是字元流,如果寫到檔案中他的資料格式就和在記憶體中一樣,這樣他讀出來是會很方便,我們開啟檔案看到的內容是字元編碼的,int、boolean 不是字元編碼的,所以會亂碼。
然後使用 dataOutputStream.writeUTF 可以正確顯示 是因為 UTF-8的字元編碼是對的。
注意: 用 DataOutputStream 輸出的資料並不是為了用記事本開啟看的而是為了儲存資料的 一般來儲存為.dat檔案區別開文字本件。
1.2.3 BufferedOutputStream
BufferedOutputStream 為 IO 寫操作提供了帶緩衝區的操作,提高了IO的效能。
使用如下:
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws IOException {
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("test.txt"));
bufferedOutputStream.write("BufferedOutputStreamDemo測試".getBytes("utf-8"));
bufferedOutputStream.close();
}
複製程式碼
位元組輸入流先寫這麼多,還有很多 InputStream 和 OutputStream 的實現類,有興趣的可以去看下。
接下來我們通過一個例項,看看使用哪種方式操作更快。
public class IoUtil {
/**
* 檔案拷貝,單位元組、不帶緩衝進行檔案拷貝
*
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByByte(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("srcFile is not exists!");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException("srcFile is not files");
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
int len;
while ((len = in.read()) != -1) {
out.write(len);
out.flush();
}
in.close();
out.close();
}
/**
* 檔案拷貝,位元組批量讀取
*
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFile(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("srcFile is not exists!");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException("srcFile is not files");
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
byte[] buf = new byte[8 * 1024];
int len;
while ((len = in.read(buf, 0, buf.length)) != -1) {
out.write(buf, 0, len);
out.flush();//最好加上
}
in.close();
out.close();
}
/**
* 檔案拷貝,使用帶緩衝的位元組流進行
*
* @param srcFile
* @param destFile
*/
public static void copyFileByBuffer(File srcFile, File destFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException("srcFile is not exists!");
}
if (!destFile.isFile()) {
throw new IllegalArgumentException("srcFile is not files");
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFile));
int len;
while ((len = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(len);
bufferedOutputStream.flush();
}
bufferedOutputStream.close();
bufferedOutputStream.close();
}
}
複製程式碼
接下來我們分別使用三種方式拷貝一份檔案,看看用時分別多少
測試程式碼:
public class Main {
public static void main(String[] args) throws IOException {
long start1 = System.currentTimeMillis();
IoUtil.copyFileByByte(new File("alfred.dmg"), new File("alfred1.dmg"));
long end1 = System.currentTimeMillis();
System.out.println("使用單位元組、不帶緩衝拷貝檔案用時:" + (end1 - start1));
long start2 = System.currentTimeMillis();
IoUtil.copyFile(new File("alfred.dmg"), new File("alfred2.dmg"));
long end2 = System.currentTimeMillis();
System.out.println("使用位元組批量讀取拷貝檔案用時:" + (end2 - start2));
long start3 = System.currentTimeMillis();
IoUtil.copyFileByBuffer(new File("alfred.dmg"), new File("alfred3.dmg"));
long end3 = System.currentTimeMillis();
System.out.println("使用使用帶緩衝的位元組流拷貝檔案用時:" + (end3 - start3));
}
}
複製程式碼
執行看看:
使用單位元組、不帶緩衝拷貝檔案用時:28138
使用位元組批量讀取拷貝檔案用時:8
使用使用帶緩衝的位元組流拷貝檔案用時:22406
複製程式碼
是不是很恐怖,使用位元組批量讀取的速度快的不可思議,所以拷貝檔案時使用哪種方式,心裡應該有數了。
總結下: 可以看到,位元組流的實現類一般都是成對出現的,上面講了三對:
- FileInputStream 和 FileOutputStream
- DataInputStream 和 DataOutputStream
- BufferedInputStream 和 BufferedOutputStream
二、字元流
字元流又分為
輸入流 Writer 輸出流 Reader
輸入流負責從 源(可以是檔案) 讀取資料到 Java程式 中。
輸出流負責把 Java程式 中資料寫入到 源(可以是檔案) 中。
位元組流和字元流很類似,Writer 和 Reader的實現類一般也是成對出現的。
2.1 OutputStreamWriter 和 InputStreamReader
使用如下:
public class IsrAndOswDemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("test1.txt"));
outputStreamWriter.write("IsrAndOswDemo測試");
outputStreamWriter.close();
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("test1.txt"));
while (inputStreamReader.ready()) {
System.out.print((char) inputStreamReader.read());
}
int len;
char[] bytes = new char[8 * 1024];
//批量讀取,放入bytes這個字元陣列,從第0個位置開始放置,最多放bytes.length個
//返回的是讀到的字元的個數
while ((len = inputStreamReader.read(bytes, 0, bytes.length)) != -1) {
String s = new String(bytes, 0, len);
System.out.println(s);
}
inputStreamReader.close();
}
}
複製程式碼
輸出:
IsrAndOswDemo測試
複製程式碼
2.2 BufferedReader 、BufferedWriter、PrintWriter
下面的例子是通過 BufferedReader 讀取 test1.txt 中的內容,然後分別寫入到 test4.txt 和 test5.txt 中。
public class BrAndBwAndPwDemo {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("test1.txt")));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test4.txt")));
PrintWriter printWriter = new PrintWriter("test5.txt");
String line;
//一次讀一行,不識別換行
while ((line=bufferedReader.readLine())!=null){
System.out.println(line);
// 這裡是BufferedWriter的寫操作
bufferedWriter.write(line);
bufferedWriter.flush();
bufferedWriter.newLine();//單獨寫出換行操作
// 這裡是PrintWriter的寫操作
printWriter.print(line);//不換行
printWriter.println(line);//換行
}
bufferedReader.close();
bufferedWriter.close();
printWriter.close();
}
}
複製程式碼
你可以通過以下方式關注我: