java-檔案輸入輸出處理
---------------------------------------------------
1、File類
File類是IO包中唯一代表磁碟檔案本身的物件,File類定義了一些與平臺無關的方法來操作檔案。通過呼叫File類提供的各種方法,能夠完成建立、刪除檔案、重新命名檔案、判斷檔案的讀寫許可權許可權是否存在、設定和查詢檔案的最近修改時間等操作。
File類沒有無參構造方法,最常用的是使用下面的構造方法來生成File物件(注意分隔符可以使用"/"和"",但是使用""必須寫"\",因為涉及轉義的問題):
File(String pathName) pathName指的是檔案的路徑名;
File.separator
在Windows下的路徑分隔符(\)和在Linux下的路徑分隔符(/)是不一樣的,當直接使用絕對路徑時,跨平臺會報No Such file or diretory異常。
File中還有幾個與separator類似的靜態常量,與系統有關,在程式設計中應儘量使用。
//File.separator 表示不同系統下的路徑分割符
File file = new File("D:"+File.separator+"test"+File.separator+"test1");
//File file = new File("D:/test/test1.txt");
2、建立檔案
建立檔案物件 File(String pathname)
//pathname 檔案路徑
File file = new File("D:/test/test1.txt");
建立檔案 createNewFile()
File file = new File("D:/test");
//判斷檔案是否存在,不存在,建立
if(!file.exists()){
try {
//判斷檔案是否建立成功
//createNewFile方法,會返回是否建立成功的結果,true成功,false失敗
if(file.createNewFile()){
System.out.println("建立檔案"+file.getName()+"成功");
}else{
System.out.println("建立檔案"+file.getName()+"失敗");
}
} catch (IOException e) {
e.printStackTrace();
}
3、建立目錄(單級,多級)
mkdir() | 建立單級目錄 |
---|---|
mkdirs() | 建立多級目錄 |
建立單級目錄 mkdir()
File dir = new File("D:/test/test1");//目前只有text資料夾
//判斷目錄是否存在,如果不存在則建立
if(!dir.exists()){
//mkdir方法,建立目錄,返回是否建立成功的結果
//mkdirs方法,建立多級目錄
if(dir.mkdir()){
System.out.println("建立目錄成功"); //生成test1資料夾
}else{
System.out.println("刪建立目錄失敗");
}
}else{
System.out.println("目錄存在,不需要建立");
}
建立多級目錄 mkdirs()
File dirs = new File("D:/test/test1/text1_1"); //目前只有text資料夾
//改變引數和方法即可
if(dirs.mkdirs()){
System.out.println("建立目錄成功"); //生成test1資料夾及子資料夾text1_1
}else{
System.out.println("刪建立目錄失敗");
}
4、刪除檔案或目錄(只能刪除單級空目錄)
delete()
//存在則刪除,不存在,提示
File file = new File("目錄或檔案路徑");
if(file.exists()){
// delete方法,刪除檔案或者目錄,並會返回是否刪除成功的結果,true-成功,false-失敗
//注意:刪除目錄,只能刪除當前以及的目錄,並且只能是空目錄
if(file.delete()){
System.out.println("刪除檔案或目錄成功");
}else{
System.out.println("刪除檔案或目錄失敗");
}
}else{
System.out.println("檔案或目錄不存在");
}
5、File類中常見方法
file.getName() | 檔名稱 |
---|---|
file.length() | 檔案大小 |
file.getPath() | 檔案路徑 |
file.getAbsolutePath() | 檔案絕對路徑 |
還有其他方法可以直接檢視;
--------------------------------------------------
1、FileInputStream
1.1 初始化
FileInputStream(String name) |
---|
FileInputStream(File file) |
//直接通過檔案地址初始化
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//通過File物件初始化
File file = new File("D:/test/test1.txt");
FileInputStream fis = new FileInputStream(file)
1.2 獲取檔案大小
available()
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
fis.available(); //檔案大小
1.3 讀取檔案內容
read() | 讀取一個位元組(返回對應位元組的ascii碼值) |
---|---|
read(byte b[]) | 根據位元組緩衝陣列的長度,進行讀取(返回讀取的位元組數) |
read()
//檔案 D:/test/test1.txt
內容
KH96abcdefghijk
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
while (true){
//read() 方法:從輸入流物件中,一次讀取一個位元組(返回的是對應位元組的ascii碼值,int型別)
int hasRead = fis.read();
//當讀取到末尾,返回-1,代表檔案讀取結束
if(hasRead == -1){
break;
}
System.out.print((char) hasRead);
//列印檔案中字元的ascii值
//轉化為字元:KH96abcdefghijk
}
//最後一定要關閉資源
fis.close();
執行結果:
原始檔的大小:15
KH96abcdefghijk
read(byte b[])
帶緩衝位元組數,讀取檔案內容,一次讀取就不是一個位元組,而是根據位元組緩衝陣列的長度,進行讀取
錯誤案例
讀取時通過read()來判斷是否繼續迴圈,讀取到錯誤值
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//帶緩衝位元組數,根據位元組緩衝陣列的長度,進行讀取
byte[] bytes = new byte[5];
//容易出錯的判斷方式:read()方式執行一次,就讀取一個位元組(沒有儲存,讀完就扔,位元組丟失),不可以作為判斷條件
while(fis.read() != -1){
//迴圈讀取內容
//帶緩衝陣列的讀取,方法返回的是讀取的位元組數,不是讀取的內容
//每次讀取的資料,是由緩衝位元組陣列長度決定,每次都是從上一次讀取的位置後開始繼續讀取,每次都是將讀取的內容依次放入快取陣列
int hasRead = fis.read(bytes);
System.out.println("讀取的位元組數:"+hasRead);
System.out.println(new String(bytes));
System.out.println("讀取檔案成功");
}
fis.close();
執行結果:
原始檔的大小:15
讀取的位元組數:5
H96ab //K丟失
讀取檔案成功
讀取的位元組數:5
defgh //c丟失
讀取檔案成功
讀取的位元組數:2
jkfgh //i丟失,並且還多出了上一次留下 dgh,這是因為沒有讀滿緩衝位元組陣列,而造成的讀取上一次的值
讀取檔案成功
正確案例
因為帶位元組緩衝陣列返回的時讀取到的長度,所以,用讀取到的長度來判斷是否要繼續讀取,和要寫入多少個位元組;
FileInputStream fis = new ileInputStream("D:/test/test1.txt");
//帶緩衝位元組數,根據位元組緩衝陣列的長度,進行讀取
byte[] bytes = new byte[5];
//正確寫法
int hasRead = 0;
while((hasRead = fis.read(bytes)) > 0){
//每次讀取的內容
System.out.println(new String(bytes,0,hasRead));
}
fis.close();
執行結果:
原始檔的大小:15
KH96a
bcdef
ghijk
// 沒有丟失位元組
1.4 資源關閉
close();
在使用流資源的時候一定要關閉資源,否則會造成資源浪費;
放在try( ) 裡面
JDK1.7以後,只需將資源初始化放在try()裡面就可以不用手動關閉流資源;
2、FileOutputStream
2.1初始化
FileOutputStream(File file) |
---|
FileOutputStream(File file, boolean append) |
FileOutputStream(String name) |
FileOutputStream(String name, boolean append) |
與FileInputStream類似,不過寫入的檔案不一定要存在,如果檔案不存在,會自動建立一個空的檔案;
2.2 寫入方式 boolean append
boolean append 使用否以追加方式方式寫入;
false(預設值,覆蓋)
true(追加)
2.3 寫入檔案內容
write(byte b[]) |
---|
write(byte b[], int off, int len) |
String string = "KH96班,正在學習檔案輸出流,輸出檔案2";
//File file = new File("D:/test/test2.txt");
//JDK1.7以後,只需將資源初始化放在try()裡面就可以不用手動關閉流資源,推薦使用;
try(FileOutputStream fos = new FileOutputStream("D:/test/test2.txt",true)){
//將字串轉成位元組陣列,寫入目標檔案
fos.write(string.getBytes());
//手動重新整理緩衝區
fos.flush();
}catch (IOException e){
e.printStackTrace();
}
---------------------------------------------------
FileReader字元流讀取檔案,更適合用於讀取檔案,可以讀取中文;
常用字元流類關係圖
1、FileReader
1.1 初始化
FileReader(File file) |
---|
FileReader(String fileName) |
1.2 讀取檔案內容
read() | 按單個字元讀取 |
---|---|
read(char cbuf[]) | 按字元陣列長度讀取 |
案例:按字元陣列讀取
//test1.txt檔案內容:FileWriter測試內容
try(
//初始化字元讀取流
FileReader frd = new FileReader("D:/test/test1.txt");
){
//定義一個可變字串物件
StringBuilder sbd = new StringBuilder();
//定義緩衝字元陣列
char[] chars = new char[5];
int hasRead = 0; //讀取到的字元長度
while((hasRead = frd.read(chars))>0){
sbd.append(new String(chars,0,hasRead));
System.out.println("每次讀取:"+sbd.toString());
}
//輸出檔案內容
System.out.println("檔案全部內容:"+sbd.toString());
System.out.println("檔案讀取成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
執行結果
每次讀取:FileW
每次讀取:FileWriter
每次讀取:FileWriter測試內容
檔案全部內容:FileWriter測試內容
檔案讀取成功!
2、FileWriter
2.1 初始化
FileReader(String fileName) |
---|
FileReader(File file) |
2.2 寫入檔案內容
write(String str) |
---|
write(String str, int off, int len) |
write(char cbuf[]) |
write(char cbuf[], int off, int len) |
案例:字元流直接寫入字串
//FileWriter 字元流寫檔案基本用法,可以直接寫字元
try( FileWriter fwr= new FileWriter("D:/test/test2.txt")){
//定義寫入檔案
String string = "KH96,正在學習字元流寫入檔案";
//直接寫入目標檔案
fwr.write(string);
//重新整理緩衝區
fwr.flush(); //一定要重新整理緩衝區
System.out.println("字元流寫入成功!!!");
}catch (Exception e){
e.printStackTrace();
}
執行結果
字元流寫入成功!!!
-----------------------------------------------------
1、BufferedReader
BufferedReader高效字元流讀取檔案基本用法,自帶緩衝區,讀取檔案效率高,支援逐行讀取;
1.1 初始化
BufferedReader(Reader in) | 預設緩衝字元陣列(大小8192) |
---|---|
BufferedReader(Reader in, int sz) | 自定義緩衝字元陣列大小 |
1.2 讀取檔案內容
buffer1.txt檔案內容
張三,23
李四,34
王五,34
逐行讀取案例
try(BufferedReader bfrd = new BufferedReader(new FileReader("D:/test/buffer1.txt"))){
//使用逐行讀取方式,讀取檔案
String readLinestr = bfrd.readLine();
//當讀取內容為null的時候跳出迴圈
while(readLinestr != null){
System.out.println(readLinestr);
//繼續讀取下一行
readLinestr = bfrd.readLine();
}
System.out.println("逐行讀取成功");
}catch (Exception e){
e.printStackTrace();
}
執行結果
張三,23
李四,34
王五,34
逐行讀取成功
1.3 預設緩衝區
//預設緩衝區的大小為:8192個字元
原始碼
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize); //使用預設字元陣列容量
}
private static int defaultCharBufferSize = 8192; //預設最大值為8192
2、BufferedWriter
BufferedWriter高效字元流寫入檔案基本用法,可以直接寫整行,還可以換行(newLine());
2.1 初始化
BufferedWriter(Writer out) | 預設緩衝字元陣列(大小8192) |
---|---|
BufferedWriter(Writer out, int sz) | 自定義緩衝字元陣列大小 |
2.2寫入檔案內容
try(BufferedWriter bfwt = new BufferedWriter(new FileWriter("D:/test/buffer2.txt"))){
//寫入內容
String string = "KH96,正在學習高效字元流寫入";
//寫入
bfwt.write(string);
//換行
bfwt.newLine();
bfwt.write(string+",新的一行");
//重新整理緩衝區
bfwt.flush();
System.out.println("高效字元寫入完成");
}catch (Exception e){
e.printStackTrace();
}
3、InputStreamReader
InputStreamReader(InputStream in) | 預設本地字符集 |
---|---|
InputStreamReader(InputStream in, String charsetName) | 自定義字符集 |
BufferedReader 通過InputStreamReader可以指定字符集讀取檔案的內容;
try(
//InputStreamReader提供了一個指定字符集的構造方法,建立輸入字元物件,必須指定字符集跟檔案字符集一致
BufferedReader bfrd = new BufferedReader(new InputStreamReader(new FileInputStream("D:/test/end1.txt"),"gbk"))
){
//使用逐行讀取方式,讀取檔案
String readLinestr = bfrd.readLine();
//迴圈讀取,讀取到檔案末尾,返回null
while(readLinestr != null){
System.out.println(readLinestr);
//繼續讀取下一行
readLinestr = bfrd.readLine();
}
System.out.println("逐行讀取成功");
}catch (Exception e) {
e.printStackTrace();
}
4、 OutputStreamWriter
OutputStreamWriter(OutputStream out) | 預設本地字符集 |
---|---|
OutputStreamWriter(OutputStream out, String charsetName) | 自定義字符集 |
BufferedWriter 通過OutputStreamWriter可以指定字符集寫入檔案的內容;
try(
BufferedWriter bfrwt = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:/test/end1.txt"),"gbk"))
){
String str = "測試指定檔案字符集為gbk寫入";
bfrwt.write(str);
System.out.println("檔案寫入完成!!!");
}catch (Exception e) {
e.printStackTrace();
}
----------------------------------------------------
1、例項化
DataInputStream(InputStream in) | 引數是一個位元組輸入流 |
---|---|
DataOutputStream(OutputStream out) | 引數是一個位元組輸出流 |
演示
DataInputStream dis = new DataInputStream(new FileInputStream("D:/test/girl.jpg"));
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/test/girl2.jpg"));
2、舉例
複製圖片
try(
DataInputStream dis = new DataInputStream(new FileInputStream("D:/test/girl.jpg"));
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/test/girl2.jpg"));
){
//字元緩衝區
byte[] bytes = new byte[10];
//讀取長度
int hasread = 0;
while((hasread = dis.read(bytes))>0){
dos.write(bytes,0,hasread);
}
//重新整理緩衝區
dos.flush();
System.out.println("圖片複製成功");
}catch (Exception e){
e.printStackTrace();
}
----------------------------------------------------
序列號
- 序列號是序列化和反序列化的唯一標識,是一個長整型數值;
- 如果類中不自己定義序列號,系統會自動生成一個序列號;
- 當一方實體類發生改變,而呼叫方的序列號是不會跟著改變的,不知道物件已修改,會導致兩邊序列號不一致,反序列化失敗;
- 所以要求必須手動生成一個序列號;
- 手動生成序列號後,可以解決目標類發生改變,不影響介面呼叫,物件可以正確序列化,不過物件修改的屬性返序列化後沒有值;
序列化物件類
//如果要支援序列化操作必須實現序列化介面
//賬戶類
public class Account implements Serializable {
//手動生成序列號
private static final long serialVersionUID = 2116137267832764072L;
//賬戶名
private String aname;
//賬戶密碼
private String apwd;
//set,get方法省略
@Override
public String toString() {
return "Account{" +
"aname='" + aname + '\'' +
", apwd='" + apwd + '\'' +
'}';
}
}
序列化
使用ObjectOutputStream 類的 writeObject(Object obj)方法
//序列化物件,寫入檔案
public static void xlhAccount() throws IOException {
Account account = new Account("KH96","12345");
//使用物件輸出流,將記憶體中的物件寫入到檔案
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/test/account.txt"));
//直接寫入物件
oos.writeObject(account);
oos.close();
System.out.println("序列化物件寫入成功");
}
序列化結果
反序列化
使用 ObjectInputStream 類的 readObject()方法
//反序列化目標物件讀取寫入序列化的檔案,進行反序列化,變為寫入的那個目標物件
public static void fxlhAccount() throws IOException, ClassNotFoundException {
//使用物件輸入流,讀入寫入了序列化物件的檔案
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/test/account.txt"));
Account account = (Account) ois.readObject();
ois.close();
//輸出目標物件
System.out.println(account.toString());
System.out.println("讀取序列化物件,反序列化成功");
}
反序列化結果
Account{aname='KH96', apwd='12345'}
讀取序列化物件,反序列化成功
當類發生改變
改變後的序列化物件
//賬戶類
public class Account implements Serializable {
//手動生成序列號
private static final long serialVersionUID = 2116137267832764072L;
//賬戶名
private String aname;
//賬戶密碼
private String apwd;
//新增手機
private String atel;
//set,get方法省略
@Override
public String toString() {
return "Account{" +
"aname='" + aname + '\'' +
", apwd='" + apwd + '\'' +
", atel='" + atel + '\'' +
'}';
}
}
反序列化結果
Account{aname='KH96', apwd='12345', atel='null'}
讀取序列化物件,反序列化成功