文章目錄
- IO流簡介
- 資料源
- 流(stream)
- java中的四大 IO 抽象類
- inputstream :位元組輸入流
- outputstream :位元組輸出流
- Reader :字符輸入流
- Writer :字符輸出流
- 應用場景
- 流分類
- 常見的 IO 流類
- IO流的案例
- 讀取本地磁盤中的一個檔案 FileInputStream
- 讀取檔案代碼改造
- File 類
- File類的作用
- File 類操作檔案的常用方法
- File 類操作目錄的常用方法
- 常見流物件
- 檔案位元組流
- 通過檔案位元組流實作一個圖片復制的功能
- 使用文本位元組輸入流讀取圖片
- 使用文本位元組輸出流寫入圖片
- 使用緩沖區提升讀寫效率
- 方式一 (較為常用)陣列長度是固定的
- 方式二 :陣列的長度不是固定的
- 通過位元組緩沖流提高讀寫效率
- 定義檔案拷貝工具方法
- 檔案字符流
- 檔案字符輸入流
- 檔案字符輸出流
- 使用字符流完成檔案拷貝
- 創建緩沖區提升讀寫效率
- 通過字符緩沖流提高讀寫效率
- 字符輸入緩沖流
- 字符輸出緩沖流
- 通過字符緩沖流實作檔案拷貝
- 在拷貝檔案的同時為文本添加行號
- 轉換流
- 通過位元組流為copy的文本添加行號
- 字符輸出流 PrintWriter
- 位元組陣列流
- 位元組陣列輸入流
- 位元組陣列輸出流
- 物件流
- Java物件的序列化和反序列化
- 序列化和反序列化是什么
- 序列化涉及的類和介面
- 操作基本資料型別
- 寫出基本資料型別資料
- 讀取基本資料型別資料
- 操作物件
- 將物件序列化到檔案
- 創建物件
- 序列化物件
- 將物件反序列化到記憶體中
- 隨機訪問流
- 第三方 IO 包 -- Apache IO 包
- 添加 jar 包依賴
- FileUtils
- 常用的方法
- 使用
- IOUtils
- 常用的方法
- 使用
IO流簡介
對于任何程式設計語言而言,輸入輸出系統都是非常核心的功能,程式運行需要的資料,資料的獲取往往需要跟外部進行通信,外部系統可能是檔案、資料庫、其他程式、io設備等等,
輸入(input)指的是 :可以讓程式從外部獲得資料 (核心含義是“讀”)
輸出(output)指的是 :程式輸出資料給外部系統,從而可以操作外部系統(核心含義是 “寫”)
資料源
資料源(data Source) 提供資料的原始媒介,常見的資料源有 :資料庫、檔案、其他程式等

流(stream)
對于輸入流而言,資料源就像是水箱,流(stream)就像水管中流動的水流,程式就是我們最終的用戶,我們通過流(stream)將資料源(Data Source)中的資料輸送到程式中,
對于輸出流而言,目標資料源就是目的地(dest),我們通過流(stream)將程式中的資料輸送到目的資料源中

java中的四大 IO 抽象類
位元組輸出輸入流 :inputstream、outputstream 資料單位為位元組
字符輸入輸出流 :reader、writer 資料單位為字符
這四個類是所有 IO 流類的抽象父類
inputstream :位元組輸入流
常用的方法 :
read() : 讀取一個位元組的資料,并將位元組的值作為int 資料型別回傳(0-255之間的一個值),如果為讀出位元組則回傳 -1(回傳值為-1時,表示讀取結束)
close() :該方法無回傳值 void ,關閉輸入流,釋放系統資源
outputstream :位元組輸出流
常用的方法 :
write(int n) :向目的地中寫入一個位元組,無回傳值 void
close() : 該方法無回傳值 void ,關閉輸出流,釋放系統資源
注意 :輸入輸出流相當耗費資源,用完要及時關閉
Reader :字符輸入流
read() : 讀取一個字符的資料,并將字符的值作為int 資料型別回傳(0-65535之間的一個值,即Unicode值),如果為讀出位元組則回傳 -1(回傳值為-1時,表示讀取結束)
close() :該方法無回傳值 void ,關閉輸入流,釋放系統資源
Writer :字符輸出流
write(int n) :向輸出流中寫入一個字符,無回傳值 void
close() : 該方法無回傳值 void ,關閉輸出流,釋放系統資源
區別 :
- 以stream結尾的流為位元組流,例如 :FileInputStream、FileOutputStream
- 以Reader/Writer 結尾的流為字符流,例如 :FileReader、FileWriter
應用場景
如果我們要讀的檔案是一個二進制的檔案,如 :圖片、音頻之類的,用位元組流stream
如果我們要讀的檔案是是一個文本,可以使用字符流 reader 、writer
流分類
節點流 :直接接觸資料源的流
處理流 :不直接接觸資料源的流
節點流處于 IO 操作的第一線,所有的操作必須通過他們進行,處理流可以對節點流進行包裝,提高性能或提高程式的靈活性

常見的 IO 流類

1、InputStream/OutputStream : 位元組流的抽象類
2、Reader/Writer :字符流的抽象類
3、FileInputStream/FileOutputStream :節點流,以位元組為單位直接操作檔案
4、ByteArrayInputStream / ByteArrayOutputStream :位元組流,以位元組為單位直接操作 位元組陣列物件
5、ObjectInputStream/ObjectOutputStream :處理流,以位元組為單位直接操作物件
6、DataInputStream/DataOutputStream :處理流,以位元組為單位直接操作基本資料型別與字串型別
7、FileReader/FileWriter :節點流,以字符為單位直接操作文本檔案(只能讀寫文本檔案)
8、BufferedReader/BufferedWriter :處理流,將 Reader 和 Writer 物件進行包裝,增加快取功能,提升讀寫效率
9、BufferedInputStream/BufferedOutputStream :處理流,將InputStream/OutputStream 物件進行包裝,增加快取功能,提升讀寫效率
10、InputStreamReader /OutputStreamWriter :處理流,將位元組流物件轉化成字符流物件
11、PrintStream :處理流,將OutputStream 進行包裝,可以方便的輸出字符,更加靈活
IO流的案例
讀取本地磁盤中的一個檔案 FileInputStream
當程式需要讀取一個資料源資料時,就會通過IO物件開通一個通往資料源的流,通過這個流的相關方法可以順序的讀到想要的資料
1、在電腦 F 盤中創建一個 test.txt 檔案,里面內容為 abc
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-x0lzcw9a-1631169066428)(8、IO流.assets/image-20210908212214444.png)]
2、撰寫代碼,去讀取這個檔案中的值
public static void main(String[] args) {
FileInputStream fis = null;
try {
//創建一個檔案位元組流輸入物件,引數為檔案的地址
fis = new FileInputStream("F:/test.txt");
//呼叫 fis 物件的 read() 方法來讀取資料
int read = fis.read();//列印輸入字符 a 對應的 ASCII 值97
System.out.println(read);
} catch (Exception e) {
e.printStackTrace();
}finally {
//關閉流
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
這段代碼的運行結果為 :97
為什么為 97 呢?
這里是因為,read() 方法讀取的是 test.txt 檔案的第一個字符,也就是 a ,那為什么回傳的是 97 而不是 a ,因為read方法回傳值是int ,所以這里回傳的是 a 對應的 ASCII 值中十進制的值,
我們用 位元組流讀取檔案時,回傳的是其對應 的ASCII 值
如果我們要列印完整的 abc ,需要 :
public static void main(String[] args) {
FileInputStream fis = null;
try {
//創建一個檔案位元組流輸入物件,引數為檔案的地址
fis = new FileInputStream("F:/test.txt");
//呼叫 fis 物件的 read() 方法來讀取資料
int s1 = fis.read();//列印輸入字符 a 對應的 ASCII 值97
int s2 = fis.read();//列印輸入字符 b 對應的 ASCII 值98
int s3 = fis.read();//列印輸入字符 c 對應的 ASCII 值99
int s4 = fis.read();//由于檔案內容已經讀取完畢,所以回傳-1
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
} catch (Exception e) {
e.printStackTrace();
}finally {
//關閉流
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
讀取檔案代碼改造
public static void main(String[] args) {
FileInputStream fis = null;
try {
//創建位元組輸入流物件,引數為檔案地址
fis = new FileInputStream("F:/test.txt");
int temp = 0;
while ((temp = fis.read())!=-1){
//如果將temp = fis.read()寫在while回圈里面,將會輸出 -1
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
運行結果為 :97 98 99
讓結果輸出為檔案中的 abc
public static void main(String[] args) {
FileInputStream fis = null;
try {
//創建位元組輸入流物件,引數為檔案地址
fis = new FileInputStream("F:/test.txt");
StringBuilder stringBuilder = new StringBuilder();
int temp = 0;
while ((temp = fis.read())!=-1){
System.out.println((char)temp);
stringBuilder.append((char)temp);
}
System.out.println(stringBuilder.toString());
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
File 類
File類的作用
File 類是java提供針對磁盤中的檔案或目錄轉換物件的包裝類,一個File物件可以代表一個檔案或目錄,File物件可以實作獲取檔案和目錄屬性等功能,可以實作對檔案和目錄的創建、洗掉等功能,
File 類操作檔案的常用方法
createNewFile() 創建新檔案
//創建一個 file 物件
File file = new File("f:/test/a.txt");//需要創建的新檔案名稱
try {
//創建一個新檔案
boolean newFile = file.createNewFile();
System.out.println(newFile);
} catch (Exception e) {
e.printStackTrace();
}
delete() 洗掉檔案(不僅可以洗掉檔案,也可以洗掉檔案夾,注意 :目錄下面有檔案的時候不能洗掉目錄)
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//洗掉檔案
boolean delete = file.delete();
System.out.println(delete);
} catch (Exception e) {
e.printStackTrace();
}
exists() 查看檔案是否存在(不僅可以查看檔案,也可以查看檔案夾)
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//判斷檔案是否存在
boolean exists = file.exists();
System.out.println(exists);
} catch (Exception e) {
e.printStackTrace();
}
getAbsolutePath() 獲取檔案的絕對路徑
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//獲取檔案的絕對路徑
String path = file.getAbsolutePath();
System.out.println(path);//f:\test\a.txt
} catch (Exception e) {
e.printStackTrace();
}
getPath() 獲取檔案的相對路徑
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//獲取檔案相對路徑
String path = file.getPath();
System.out.println(path);//f:\test\a.txt
} catch (Exception e) {
e.printStackTrace();
}
getName() 獲取檔案的名稱
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//獲取檔案的名稱
String name = file.getName();
System.out.println(name);//a.txt
} catch (Exception e) {
e.printStackTrace();
}
isFile() 判斷是否是檔案
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//判斷是否是檔案
boolean file1 = file.isFile();
System.out.println(file1);
} catch (Exception e) {
e.printStackTrace();
}
length() 查看檔案中的位元組數
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//查看檔案中的位元組數,內容abc ,回傳3
long length = file.length();
System.out.println(length);
} catch (Exception e) {
e.printStackTrace();
}
isHidden() 查看檔案是否是一個隱藏檔案
//創建一個 file 物件
File file = new File("f:/test/a.txt");
try {
//查看檔案是否是一個隱藏檔案
boolean hidden = file.isHidden();
System.out.println(hidden);
} catch (Exception e) {
e.printStackTrace();
}
File 類操作目錄的常用方法
isDirectory() 查看當前路徑是否是一個目錄
//創建一個 file 物件
File file = new File("f:/test");
try {
//查看當前路徑是否是一個目錄
boolean hidden = file.isDirectory();
System.out.println(hidden);
} catch (Exception e) {
e.printStackTrace();
}
getParentFile() 獲取當前目錄的父級目錄
//創建一個 file 物件
File file = new File("f:/test");
try {
//獲取當前目錄的父級目錄
File parentFile = file.getParentFile();
System.out.println(parentFile);//f:\
} catch (Exception e) {
e.printStackTrace();
}
mkdir() 創建目錄
//創建一個 file 物件
File file = new File("f:/test");
try {
//創建目錄
boolean mkdir = file.mkdir();
System.out.println(mkdir);
} catch (Exception e) {
e.printStackTrace();
}
list() 回傳一個字串陣列,包含目錄中的檔案名
//創建一個 file 物件
File file = new File("f:/test");
try {
//回傳一個字串陣列,包含目錄中的檔案名
String[] list = file.list();
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
//輸出結果
//新建文本檔案 (2).txt
//新建文本檔案.txt
} catch (Exception e) {
e.printStackTrace();
}
listFiles() 回傳一個 file 陣列,包含目錄中的檔案的路徑
//創建一個 file 物件
File file = new File("f:/test");
try {
//回傳一個 file 陣列,包含目錄中的檔案的路徑
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
//輸出結果
//f:\test\新建文本檔案 (2).txt
//f:\test\新建文本檔案.txt
} catch (Exception e) {
e.printStackTrace();
}
常見流物件
檔案位元組流
FileInputStream 通過位元組的方式讀取檔案,適合讀取所有型別的檔案,java也提供了 FileReader 專門讀取文本檔案
FileOutputStream通過位元組的方式寫資料到檔案中,適合所有型別的檔案,java也提供了 FileWriter 專門寫入文本檔案
通過檔案位元組流實作一個圖片復制的功能
使用文本位元組輸入流讀取圖片
public static void main(String[] args) {
FileInputStream fis = null;
try {
//創建位元組輸入流物件,引數為圖片地址
fis = new FileInputStream("f:/java.jpg");
int temp =0;
while ((temp=fis.read())!=-1){
System.out.println(temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//關閉流
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用文本位元組輸出流寫入圖片
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//創建位元組輸入流物件,引數為圖片地址
fis = new FileInputStream("f:/java.jpg");
//創建位元組輸出流物件,引數為圖片的新地址
fos = new FileOutputStream("f:/test/file.jpg");
int temp =0;
while ((temp=fis.read())!=-1){
fos.write(temp);
}
//從記憶體中寫入到磁盤中
fos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
//關閉流
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用緩沖區提升讀寫效率
方式一 (較為常用)陣列長度是固定的
通過創建一個指定的位元組陣列作為緩沖區,用來提升IO流的讀寫效率,
注意 :緩沖區的長度一定是 2 的整數冪,一般情況下 1024 長度較為合適
例如 :現在有20斤大米需要往家里運,有兩種方式,一種是一粒一粒的運,另一種是裝一個袋子里 ;第一種方式就相當于我們直接通過位元組流操作,而第二種方式就相當于我們創建一個緩沖區,緩沖區就像當于一個袋子,
package com.hkp.file;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileInputStreamDemo2 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//創建位元組輸入流物件,引數為圖片地址
fis = new FileInputStream("f:/java.jpg");
//創建位元組輸出流物件,引數為圖片的新地址
fos = new FileOutputStream("f:/file.jpg");
//創建緩沖區,提高讀寫效率
byte[] buffer = new byte[1024];
int temp =0;
while ((temp=fis.read(buffer))!=-1){
//引數說明,我們現在那資料是從緩沖區中拿的
//第一個引數是緩沖區,第二個引數是起始位置,第三個引數是陣列的長度
fos.write(buffer,0,temp);
}
//從記憶體中寫入到磁盤中
fos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
//關閉流
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
方式二 :陣列的長度不是固定的
通過創建一個位元組陣列作為緩沖區,陣列長度是通過輸入流物件的 available() 回傳當前檔案的預估長度來定義的,在讀寫檔案時,是在一次讀寫操作中完成檔案讀寫操作的,
注意 : 如果檔案過大,那么對記憶體的占用也是比較大的,所以大檔案不建議使用該方法,
package com.hkp.file;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileInputStreamDemo3 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//創建位元組輸入流物件,引數為圖片地址
fis = new FileInputStream("f:/java.jpg");
//創建位元組輸出流物件,引數為圖片的新地址
fos = new FileOutputStream("f:/file.jpg");
//創建緩沖區,提高讀寫效率
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fos.write(buffer);
//從記憶體中寫入到磁盤中
fos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
//關閉流
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
通過位元組緩沖流提高讀寫效率
java 緩沖流本身并不具有 IO 流的讀取與寫入功能,只是在節點流上加上緩沖功能提高效率;緩沖流是一種處理流(包裝流),當檔案或其他資料源頻繁的讀寫操作時,效率比較低,這時加上緩沖流就能夠更高效的讀寫資訊,緩沖流是先將資料快取起來,然后快取區存滿之后或者手動重繪時,在一次性的讀取到程式或寫入目的地,
BufferedInputStream 和 BufferedOutputStream 這兩個流是緩沖位元組流,通過內部的快取陣列來提高讀寫效率,
緩沖流中的byte陣列的默認長度為8192
package com.hkp.file;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class BufferStreamDemo1 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream("f:/java.jpg");
bis = new BufferedInputStream(fis);
fos = new FileOutputStream("f:/file.jpg");
bos = new BufferedOutputStream(fos);
int temp = 0;
while ((temp = bis.read())!=-1){
bos.write(temp);
}
bos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//關閉順序 :后開的先關閉
if(bis!=null){
bis.close();
}
if(fis!=null){
fis.close();
}
if(bos!=null){
bos.close();
}
if(fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
定義檔案拷貝工具方法
package com.hkp.file;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileCopyTool {
public static void main(String[] args) {
copyFile("f:/java.jpg","f:/file.jpg");
}
/**
* 檔案拷貝方法
* @param src 檔案舊地址
* @param des 檔案新地址
*/
public static void copyFile(String src,String des){
FileInputStream fis= null;
FileOutputStream fos = null;
try {
fis= new FileInputStream(src);
fos = new FileOutputStream(des);
//定義位元組緩沖區
byte[] buffer =new byte[1024];
int temp =0;
while((temp = fis.read(buffer))!=-1){
fos.write(buffer,0,temp);
}
fos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(fis != null){
fis.close();
}
if(fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
檔案字符流
檔案字符輸入流
package com.hkp.file;
import java.io.FileReader;
public class FileDemo {
public static void main(String[] args) {
FileReader fd =null;
try {
//創建檔案字符輸入流物件
fd = new FileReader("F:/test.txt");
int temp = 0;
while ((temp = fd.read())!=-1){
System.out.println((char)temp);
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fd!=null){
try {
fd.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
檔案字符輸出流
寫入檔案時,會直接替換檔案里原本的內容,這是我們可以在創建 FileWriter 物件時來定義是否在原本內容上追加
FileWriter fw = new FileWriter("f:/test.txt",true);//true表示追加,false表示不追加
package com.hkp.file;
import java.io.FileWriter;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
try {
//創建字符檔案輸出流,如果沒有這個檔案,默認會創建
fw = new FileWriter("f:/test.txt");
//向檔案中寫入文本\r\n表示回車換行
fw.write("Hello IO!!!\r\n");
fw.write("Hello IO!!!");
//重繪
fw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用字符流完成檔案拷貝
public static void main(String[] args) {
FileReader frd = null;
FileWriter fw = null;
try {
//創建檔案字符輸入流
frd = new FileReader("f:/test.txt");
//創建檔案字符輸出流
fw = new FileWriter("f:/copy.txt");
int temp = 0;
while ((temp = frd.read())!=-1){
fw.write(temp);
}
fw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(frd!=null){
frd.close();
}
if(fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
創建緩沖區提升讀寫效率
字符輸入輸出流,定義的是 char 型別的陣列緩沖區
public static void main(String[] args) {
FileReader frd = null;
FileWriter fw = null;
try {
//創建檔案字符輸入流
frd = new FileReader("f:/test.txt");
//創建檔案字符輸出流
fw = new FileWriter("f:/copy.txt");
//創建緩沖區
char[] buffer = new char[1024];
int temp = 0;
while ((temp = frd.read(buffer))!=-1){
fw.write(buffer,0,temp);
}
fw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(frd!=null){
frd.close();
}
if(fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
通過字符緩沖流提高讀寫效率
BufferedReader 、BufferedWriter
字符輸入緩沖流
BufferedReader 是針對字符輸入流的緩沖流物件,提供了更方便的按行讀取的方法 :readLine() ;在使用字符流讀取文本檔案時,我們可以使用該方法以行為單位進行讀取
public static void main(String[] args) {
FileReader frd = null;
BufferedReader bfrd = null;
try {
frd = new FileReader("f:/test.txt");
bfrd = new BufferedReader(frd);
String temp = "";
while ((temp = bfrd.readLine())!=null){
System.out.println(temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfrd!=null){
bfrd.close();
}
if(frd!=null){
frd.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
字符輸出緩沖流
BufferedWriter 是針對字符輸出流的緩沖流物件,可以使用 readLine() ;方法實作換行處理
public static void main(String[] args) {
FileWriter fw =null;
BufferedWriter bfw = null;
try {
//會自動創建文本檔案
fw = new FileWriter("f:/writer.txt");
bfw = new BufferedWriter(fw);
bfw.write("Hello IO!!!");
bfw.newLine();
bfw.write("Hello IO!!!");
bfw.newLine();
bfw.write("Hello IO!!!");
bfw.newLine();
bfw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfw!=null){
bfw.close();
}
if(fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
通過字符緩沖流實作檔案拷貝
public static void main(String[] args) {
copyFile("f:/test.txt","f:/copy.txt");
}
/**
* 通過字符流實作拷貝
* @param src 檔案舊地址
* @param des 檔案新地址
*/
public static void copyFile(String src,String des){
FileReader fd = null;
FileWriter fw = null;
BufferedReader bfd = null;
BufferedWriter bfw = null;
try {
fd = new FileReader(src);
bfd = new BufferedReader(fd);
fw = new FileWriter(des);
bfw = new BufferedWriter(fw);
String temp = "";
while((temp = bfd.readLine())!=null){
bfw.write(temp);
bfw.newLine();
}
bfw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfd !=null){
bfd.close();
}
if(fd!=null){
fd.close();
}
if(bfw!=null){
bfw.close();
}
if(fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
在拷貝檔案的同時為文本添加行號
public static void main(String[] args) {
copyFile("f:/test.txt","f:/copy.txt");
}
/**
* 通過字符流實作拷貝
* @param src 檔案舊地址
* @param des 檔案新地址
*/
public static void copyFile(String src,String des){
FileReader fd = null;
FileWriter fw = null;
BufferedReader bfd = null;
BufferedWriter bfw = null;
try {
fd = new FileReader(src);
bfd = new BufferedReader(fd);
fw = new FileWriter(des);
bfw = new BufferedWriter(fw);
String temp = "";
int num = 1;
while((temp = bfd.readLine())!=null){
bfw.write(num+"、"+temp);
bfw.newLine();
num++;
}
bfw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfd !=null){
bfd.close();
}
if(fd!=null){
fd.close();
}
if(bfw!=null){
bfw.close();
}
if(fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
轉換流
InputStreamReader/OutputStreamWriter用來實作將位元組流轉化成字符流,
比如,如下場景:
System.in是位元組流物件,代表鍵盤的輸入,如果我們想按行接收用戶的輸入時,就必須用到緩沖字符流
BufferedReader特有的方法readLine(),但是經過觀察會發現在創建BufferedReader的構造方法的引數必須是一個
Reader物件,這時候我們的轉換流InputStreamReader 就派上用場了,
而System.out也是位元組流物件,代表輸出到顯示幕,按行讀取用戶的輸入后,并且要將讀取的一行字串直接顯示
到控制臺,就需要用到字符流的write(String str)方法,所以我們要使用OutputStreamWriter將位元組流轉化為字符
流,
public static void main(String[] args) {
InputStreamReader isr = null;
BufferedReader bfd = null;
OutputStreamWriter osw = null;
BufferedWriter bfw = null;
try {
//將位元組轉換為字符流
isr = new InputStreamReader(System.in);
osw = new OutputStreamWriter(System.out);
bfd = new BufferedReader(isr);
bfw = new BufferedWriter(osw);
while(true){
bfw.write("請輸入");
bfw.flush();
String input = bfd.readLine();
if(input.equals("exit")){
break;
}
bfw.write("你輸入的內容是 :"+input);//相當于 system.out.println()
bfw.newLine();
bfw.flush();
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfd!=null){
bfd.close();
}
if(isr!=null){
isr.close();
}
if(bfw!=null){
bfw.close();
}
if(osw!=null){
osw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
通過位元組流為copy的文本添加行號
位元組流不能處理讀取的資料,這里需要將位元組流轉換為字符流,通過字符流的緩沖流讀取一行,進行操作
public static void main(String[] args) {
copyFile("f:/test.txt","f:/copy.txt");
}
/**
* 通過字符流實作拷貝
* @param src 檔案舊地址
* @param des 檔案新地址
*/
public static void copyFile(String src,String des){
BufferedReader bfd = null;
BufferedWriter bfw = null;
try {
bfd = new BufferedReader(new InputStreamReader(new FileInputStream(src)));
bfw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(des)));
String temp = "";
int num = 1;
while((temp = bfd.readLine())!=null){
bfw.write(num+"、"+temp);
bfw.newLine();
num++;
}
bfw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfd !=null){
bfd.close();
}
if(bfw!=null){
bfw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
字符輸出流 PrintWriter
在Java的Io流中專門提供了用于字符輸出的流物件PrintWriter,該物件具有自動換行重繪緩沖字符輸出流功能(可
以不使用flush()和newLine()方法),特點是可以按行寫出字串,并可通過println();方法實作自動換行,
public static void main(String[] args) {
copyFile("f:/test.txt","f:/copy.txt");
}
/**
* 通過字符流實作拷貝
* @param src 檔案舊地址
* @param des 檔案新地址
*/
public static void copyFile(String src,String des){
BufferedReader bfd = null;
PrintWriter pw = null;
try {
bfd = new BufferedReader(new InputStreamReader(new FileInputStream(src)));
pw = new PrintWriter(des);
String temp = "";
int num = 1;
while((temp = bfd.readLine())!=null){
pw.println(num+"、"+temp);
num++;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(bfd !=null){
bfd.close();
}
if(pw!=null){
pw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
位元組陣列流
ByteArraylnputStream和 ByteArrayOutputStream經常用在需要流和陣列之間轉化的情況!
位元組陣列輸入流
說白了,FileInputStream是把檔案當做資料源,ByteArrayInputStream則是把記憶體中的”位元組陣列物件”當做資料源,
package com.hkp.file;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
public class ByteArraylnputStream {
public static void main(String[] args){
byte[] arr = "abcdefg".getBytes();//getBytes()可以將字串轉為一個byte陣列
//System.out.println(Arrays.toString(arr));//[97, 98, 99, 100, 101, 102, 103]
ByteArrayInputStream bis = null;
try {
//引數為一個位元組陣列
bis = new ByteArrayInputStream(arr);
int temp = 0;
while ((temp = bis.read())!=-1){
System.out.println((char)temp);
}
}finally {
try {
if(bis!=null){
bis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
位元組陣列輸出流
ByteArrayOutputStream流物件是將流中的資料寫入到位元組陣列中,
package com.hkp.file;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
public class ByteArrayOutputStreamDemo {
public static void main(String[] args) {
ByteArrayOutputStream bos = null;
try {
bos = new ByteArrayOutputStream();
bos.write('a');
bos.write('b');
bos.write('c');
//生成一個byte陣列
byte[] bytes = bos.toByteArray();
System.out.println(Arrays.toString(bytes));
}finally {
try {
if(bos!=null){
bos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
物件流
物件的本質是用來組織和存盤資料的,物件本身也是資料,那么,能不能將物件存盤到硬碟上的檔案中呢?能不能
將物件通過網路傳輸到另一個電腦呢?我們可以通過序列化和反序列化來實作這些需求,
Java物件的序列化和反序列化
序列化和反序列化是什么
當兩個行程遠程通信時,彼此可以發送各種型別的資料,無論是何種型別的資料,都會以二進制序列的形式在網路
上傳送,比如,我們可以通過http協議發送字串資訊;我們也可以在網路上直接發送Java物件,發送方需要把這個
Java物件轉換為位元組序列,才能在網路上傳送;接收方則需要把位元組序列再恢復為Java物件才能正常讀取把Java對
象轉換為位元組序列的程序稱為物件的序列化,把位元組序列恢復為Java物件的程序稱為物件的反序列化,
物件序列化的作用有如下兩種:
持久化 :把物件的位元組序列永久地保存到硬碟上,通常存放在一個檔案中,
網路通信 :在網路上傳送物件的位元組序列,比如:服務器之間的資料通信、物件傳遞,
序列化涉及的類和介面
ObjectOutputStream代表物件輸出流,它的writeObject(Object obj)方法可對引數指定的obj物件進行序列化,把得
到的位元組序列寫到一個目標輸出流中,
ObjectInputStream代表物件輸入流,它的readObject()方法從一個源輸入流中讀取位元組序列,再把它們反序列化為
一個物件,并將其回傳,
只有實作了Serializable介面的類的物件才能被序列化,Serializable介面是一個空介面,只起到標記作用,
操作基本資料型別
我們前邊學到的資料流只能實作對基本資料型別和字串型別的讀寫,并不能對Java物件進行讀寫操作(字串除
外),但是在物件流中除了能實作對基本資料型別進行讀寫操作以外,還可以對Java物件進行讀寫操作,
寫出基本資料型別資料
public static void main(String[] args) {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("f:/object.txt")));
oos.writeInt(10);
oos.writeChar('a');
oos.writeUTF("hello");//字串
oos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(oos!=null){
oos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
讀取基本資料型別資料
public static void main(String[] args) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("f:/object.txt")));
//必須按照寫入的順序讀取資料
System.out.println(ois.readInt());
System.out.println(ois.readChar());
System.out.println(ois.readUTF());
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(ois!=null){
ois.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
操作物件
將物件序列化到檔案
ObjectOutputStream可以將一個記憶體中的Java物件通過序列化的方式寫入到磁盤的檔案中,被序列化的物件必須要
實作Serializable 序列化介面,否則會拋出例外,
創建物件
package com.hkp.file;
import java.io.Serializable;
public class User implements Serializable {
private int id;
private String username;
private int age;
public User() {
}
public User(int id, String username, int age) {
this.id = id;
this.username = username;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", age=" + age +
'}';
}
}
序列化物件
public static void main(String[] args) {
ObjectOutputStream oos =null;
try {
oos = new ObjectOutputStream(new FileOutputStream("f:/user.txt"));
User user = new User(1,"test",20);
oos.writeObject(user);
oos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(oos!=null){
oos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
將物件反序列化到記憶體中
public static void main(String[] args) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("f:/user.txt"));
User user = (User) ois.readObject();
System.out.println(user.toString());
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(ois!=null){
ois.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
隨機訪問流
RandomAccessFile可以實作兩個作用 :
- 實作對一個檔案做讀和寫的操作,
- 可以訪問檔案的任意位置,不像其他流只能按照先后順序讀取,
在開發某些客戶端軟體時,經常用到這個功能強大的可以”任意操作檔案內容的類,比如,軟體的使用次數和使用
日期,可以通過本類訪問檔案中保存次數和日期的地方進行比對和修改,Java很少開發客戶端軟體,所以在Java
開發中這個類用的相對較少,
學習這個流我們需掌握三個核心方法 :
-
RandomAccessFile(String name, String mode) name用來確定檔案地址; mode取 r (讀)或 rw (可讀寫),通過
mode可以確定流對檔案的訪問權限,
-
seek(long a) 用來定位流物件讀寫檔案的位置,a確定讀寫位置距離檔案開頭的位元組個數,下標從0開始
-
getFilePointer() 獲得流的當前讀寫位置,
public static void main(String[] args) {
RandomAccessFile raf = null;
try {
//rw 表示對檔案可讀可寫
raf = new RandomAccessFile("f:/test.txt","rw");
//將若干資料寫入檔案中
int[] num = {10,20,30,40,50,60,70,80,90};
for (int i = 0; i < num.length; i++) {
raf.writeInt(num[i]);
}
//隨機訪問流可以不按順序訪問資料
//如我們要訪問 20,
//將位元組數定位到4,也就是從第5個位元組開始讀(一個數字代表兩個位元組)
raf.seek(4);
System.out.println(raf.readInt());//20
//隔一個讀一個
for (int i = 0; i < num.length; i+=2) {
raf.seek(i*4);
System.out.print(raf.readInt()+"\t");//10 30 50 70 90
}
System.out.println();
//在第八個位元組位置插入一個新的資料45,替換之前的資料30
raf.seek(8);
raf.writeInt(45);
for (int i = 0; i < num.length; i+=2) {
raf.seek(i*4);
System.out.print(raf.readInt()+"\t");//10 45 50 70 90
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(raf!=null){
raf.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
第三方 IO 包 – Apache IO 包
JDK中提供的檔案操作相關的類,但是功能都非常基礎,進行復雜操作時需要做大量編程作業,實際開發中,往往
需要你自己動手撰寫相關的代碼,尤其在遍歷目錄檔案時,經常用到遞回,非常繁瑣,Apache-commons工具包中
提供了IOUtils/FileUtils,可以讓我們非常方便的對檔案和目錄進行操作,
Apache lOUtils和FileUtils類別庫為我們提供了更加簡單、功能更加強大的檔案操作和 IO 流操作功能,
添加 jar 包依賴
Apache 官網 和 maven 倉庫都可以,推薦去maven倉庫,Apache 是國外的,網路上不太好
<!--Apache commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
FileUtils
常用的方法
cleanDirectory :清空目錄,但不洗掉目錄,
contentEquals :比較兩個檔案的內容是否相同,
copyDirectory :將一個目錄內容拷貝到另一個目錄,可以通過 FileFilter過濾需要拷貝的檔案,
copyFile :將一個檔案拷貝到一個新的地址,
copyFileToDirectory :將一個檔案拷貝到某個目錄下,
copylnputStreamToFile :將一個輸入流中的內容拷貝到某個檔案,
deleteDirectory :洗掉目錄,
deleteQuietly :洗掉檔案,
listFiles :列出指定目錄下的所有檔案,
openlnputSteam :打開指定檔案的輸入流,
readFileToString :將檔案內容作為字串回傳,
readLines :將檔案內容按行回傳到一個字串陣列中,
size :回傳檔案或目錄的大小,
write :將字串內容直接寫到檔案中,
writeByteArrayToFile :將位元組陣列內容寫到檔案中,
writeLines :將容器中的元素的toString 方法回傳的內容依次寫入檔案中,
writeStringToFile :將字串內容寫到檔案中,
使用
readFileToString :將檔案內容作為字串回傳,
package com.hkp.fileutils;
import org.apache.commons.io.FileUtils;
import java.io.File;
public class ReadToString {
public static void main(String[] args) {
try {
String content = FileUtils.readFileToString(new File("f:/test.txt"),"utf-8");
System.out.println(content);
//輸出結果
//你好,IO
//Hello IO
}catch (Exception e){
e.printStackTrace();
}
}
}
copyDirectory :將一個目錄內容拷貝到另一個目錄,可以通過 FileFilter過濾需要拷貝的檔案,
package com.hkp.fileutils;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.FileFilter;
public class copyDirectoryDemo {
public static void main(String[] args) throws Exception{
//引數說明
//第一個引數是需要拷貝檔案的檔案夾的路徑,第二個是目標檔案夾的路徑,第三個是過濾條件(是一個介面)注意不要導錯包
FileUtils.copyDirectory(new File("f:/"), new File("f:/test"), new FileFilter() {
//在檔案拷貝時候的過濾條件
//回傳 true 則需要拷貝,回傳false則不需要拷貝
public boolean accept(File pathname) {
//除了以 .txt 結尾的檔案需要拷貝,其他的都不需要拷貝
if(pathname.getName().endsWith(".txt")){
return true;
}
return false;
}
});
}
}
IOUtils
常用的方法
buffer方法 :將傳入的流進行包裝,變成緩沖流,并可以通過引數指定緩沖大小,
closeQueitly方法 :關閉流,
contentEquals方法 :比較兩個流中的內容是否一致,
copy方法 :將輸入流中的內容拷貝到輸出流中,并可以指定字符編碼,
copyLarge方法 :將輸入流中的內容拷貝到輸出流中,適合大于2G內容的拷貝,
linelterator方法 :回傳可以迭代每一行內容的迭代器,
read方法 :將輸入流中的部分內容讀入到位元組陣列中,
readFully方法 :將輸入流中的所有內容讀入到位元組陣列中,
readLine方法 :讀入輸入流內容中的一行,
toBufferedInputStream,toBufferedReader :將輸入轉為帶快取的輸入流,
toByteArray,toCharArray :將輸入流的內容轉為位元組陣列、字符陣列,
toString :將輸入流或陣列中的內容轉化為字串,
write方法 :向流里面寫入內容,
writeLine方法 :向流里面寫入一行內容,
使用
toString :將輸入流或陣列中的內容轉化為字串,
package com.hkp.fileutils;
import org.apache.commons.io.IOUtils;
import java.io.FileInputStream;
public class IOUtilsDemo {
public static void main(String[] args) throws Exception{
String content = IOUtils.toString(new FileInputStream("f:/test.txt"),"utf-8");
System.out.println(content);
//輸出結果
//你好,IO
//Hello IO
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299531.html
標籤:其他
