File類
File類可以用來新建、刪除、重命名文件和目錄,但它不能訪問文件內容本身,訪問文件內容需要使用輸入輸出流
訪問文件名相關的方法
- String getName():返回File對象所表示的文件名或路徑名
- String getPath():返回File對象所對應的路徑名
- String getAbsolutePath():返回次Fille對象所對應的絕對路徑
- boolean renameTo(File newName):重命名此File對象所對應的文件或目錄,重命名成功返回true
文件檢測相關的方法
- boolean exists():判斷File對象對應的文件或目錄是否存在
- boolean canWrite(): 判斷File對象對應的文件或目錄是否可寫
- boolean canRead():判斷File對象對應的文件或目錄是否可讀
- boolean isFile():判斷File對象對應的是否爲文件
- boolean isDirectory():判斷File對象對應的是否爲目錄
文件操作相關方法
- long length():返回文件內容長度
- boolean createNewFile():當此File對象所對應的文件不存在時,該方法將新建一個該File對象所指定的新文件,創建成功返回true
- boolean delete():刪除File對應的文件
目錄操作相關的方法
- boolean mkdir():創建一個File對象所對應的目錄
- String[] list():列出File對象的所以子文件名和路徑名
- File[] listFiles():列出File對象的所有子文件
- getParentFile():得到文件的父級目錄
文件過濾器
File類的list方法了一返回File對象的所有子文件名,該方法中可以接收一個FilenameFilter參數,通過該參數可以只列出符合條件的文件
public static void main(String[] args) {
--------以當前路徑來創建一個file對象
File file = new File(".");
--------如果文件名以.java結尾或文件對應一個路徑,則返回true
file.list((dir,name)-> name.endsWith(".java") || new File(name).isDirectory());
System.out.println(file);
}
字節流和字符流
InputStream和Reader是所有輸入流的抽象基類,本身不能創建實例來執行輸入,但可以使用FileInputStream和FileReader來讀取文件
public static void main(String[] args) {
try {
//準備文件lol.txt其中的內容是AB,對應的ASCII分別是65 66
File f =new File("d:/lol.txt");
//創建基於文件的輸入流
FileInputStream fis =new FileInputStream(f);
//創建字節數組,其長度就是文件的長度
byte[] all =new byte[(int) f.length()];
//以字節流的形式讀取文件所有內容
fis.read(all);
for (byte b : all) {
//打印出來是65 66
System.out.println(b);
}
//每次使用完流,都應該進行關閉
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
OutputStream和Writer是所有輸出流的抽象基類,本身不能創建實例來執行輸出,但可以使用FileOutputStream和FileWriter來讀取文件,如果用來輸出字符串內容使用FileWriter會更好些
處理流的用法
使用處理流的優勢:輸入輸出更簡單;執行效率更高
使用PrintStream來包裝OutputStream
FileOutputStream fileOutputStream = new FileOutputStream("F://tcp.txt");
PrintStream printStream = new PrintStream(fileOutputStream);
字符流
FileReader:用來讀取訪問文件
FileWriter:用來寫入文件
StringReader:用字符流來讀取字符串,該對象傳入的是字符串節點
StringWriter:用字符流來寫入字符串,該對象實際上是以一個StringBuffer作爲輸出節點,字符串的長度是可變的
StringWriter stringWriter = new StringWriter();
stringWriter.write("你好");
轉換流
InputStreamReader:將字節輸入流轉換成字符輸入流
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
OutputStringWriter:將字節輸出流轉換成字符輸出流
BufferedReader: 用來將Reader再次包裝變成BufferedReader ,可以利用 bufferedReader.readLine()來讀取一行,BufferedReader 具有緩衝功能,它一次讀取一行文本,以換行符爲標誌,如果沒有讀取到換行符,則程序阻塞,等待讀取到換行符爲止,這也是在控制檯只有按下回車纔會打印出內容的原因
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
bufferedReader.readLine();
關閉流的方法
所有的流,無論是輸入流還是輸出流,使用完畢之後,都應該關閉。 如果不關閉,會產生對資源佔用的浪費。 當量比較大的時候,會影響到業務的正常開展。
在try的作用域裏關閉文件流
在try的作用域裏關閉文件輸入流,在前面的示例中都是使用這種方式,這樣做有一個弊端;
如果文件不存在,或者讀取的時候出現問題而拋出異常,那麼就不會執行這一行關閉流的代碼,存在巨大的資源佔用隱患。 不推薦使用
在finally中關閉
這是標準的關閉流的方式
1. 首先把流的引用聲明在try的外面,如果聲明在try裏面,其作用域無法抵達finally.
2. 在finally關閉之前,要先判斷該引用是否爲空
3. 關閉的時候,需要再一次進行try catch處理
這是標準的嚴謹的關閉流的方式,但是看上去很繁瑣,所以寫不重要的或者測試代碼的時候,都會採用上面的有隱患try的方式,因爲不麻煩~
public static void main(String[] args) {
File f = new File("d:/lol.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally 裏關閉流
if (null != fis)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
字符編碼問題
FileReader得到的是字符,所以一定是已經把字節根據某種編碼識別成了字符了
而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統,就是GBK
FileReader是不能手動設置編碼方式的,爲了使用其他的編碼方式,只能使用InputStreamReader來代替,像這樣:
new InputStreamReader(new FileInputStream(f),Charset.forName(“UTF-8”));
public class TestStream {
-----爲什麼中字前面有一個?
如果是使用記事本另存爲UTF-8的格式,那麼在第一個字節有一個標示符,
叫做BOM用來標誌這個文件是用UTF-8來編碼的
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
File f = new File("E:\\project\\j2se\\src\\test.txt");
System.out.println("默認編碼方式:"+Charset.defaultCharset());
//FileReader得到的是字符,所以一定是已經把字節根據某種編碼識別成了字符了
//而FileReader使用的編碼方式是Charset.defaultCharset()的返回值,如果是中文的操作系統,就是GBK
try (FileReader fr = new FileReader(f)) {
char[] cs = new char[(int) f.length()];
fr.read(cs);
System.out.printf("FileReader會使用默認的編碼方式%s,識別出來的字符是:%n",Charset.defaultCharset());
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//FileReader是不能手動設置編碼方式的,爲了使用其他的編碼方式,只能使用InputStreamReader來代替
//並且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 這樣的形式
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
char[] cs = new char[(int) f.length()];
isr.read(cs);
System.out.printf("InputStreamReader 指定編碼方式UTF-8,識別出來的字符是:%n");
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
序列化
序列化機制允許將實現序列化的java對象轉換成字節序列,也可使用反序列化將從二進制流中恢復Java對象;一個對象以流的形式進行傳輸,叫做序列化。 該對象所對應的類,必須是實現Serializable接口;web應用中需要保存到HttpSession或ServletContext屬性的java對象都應該實現序列化
使用對象流實現序列化
ObjectOutputStream,是一個處理流,必須建立在其它節點流之上,使用ObjectOutputStream對象的writeObject可以將一個對象寫入輸出流```
public class ScannerSerizable implements Serializable {
String name;
int age;
public ScannerSerizable(String name,int age)
{
this.name=name;
this.age=age;
}
}
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(new File("F://java.txt"));
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
ScannerSerizable person = new ScannerSerizable("張三",20);
objectOutputStream.writeObject(person);
}
使用 ObjectInputStream進行反序列化
FileInputStream fileInputStream = new FileInputStream("F://java.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream );
ScannerSerizable person2 =(ScannerSerizable) objectInputStream.readObject();
使用引用的序列化
如果某個類的成員變量的類型不是基本類型而是引用類型,那麼這個引用類型必須也是可序列化的,否則擁有該引用類型的類也不可序列化,如下面代碼,如果student對象的類沒有可序列化,不管ScannerSerizable 有沒有實現Serializable接口,ScannerSerizable 都是不可序列化的
public class ScannerSerizable implements Serializable
{
String name;
int age;
private ScannerSerizable student;
}
練習:準備一個長度是10,類型是Hero的數組,使用10個Hero對象初始化該數組
然後把該數組序列化到一個文件heros.lol
接着使用ObjectInputStream 讀取該文件,並轉換爲Hero數組,驗證該數組中的內容,是否和序列化之前一樣
public static void main(String[] args) throws IOException, ClassNotFoundException
{
ScannerSerizable scannerSerizable1 = new ScannerSerizable("張1",20);
ScannerSerizable scannerSerizable2 = new ScannerSerizable("張2",20);
ScannerSerizable scannerSerizable3 = new ScannerSerizable("張3",20);
ScannerSerizable scannerSerizable4 = new ScannerSerizable("張4",20);
ScannerSerizable scannerSerizable5 = new ScannerSerizable("張5",20);
ScannerSerizable scannerSerizable6 = new ScannerSerizable("張6",20);
ScannerSerizable scannerSerizable7 = new ScannerSerizable("張7",20);
ScannerSerizable scannerSerizable8 = new ScannerSerizable("張8",20);
ScannerSerizable scannerSerizable9 = new ScannerSerizable("張9",20);
ScannerSerizable scannerSerizable10 = new ScannerSerizable("張10",20);
ScannerSerizable[] scannerSerizables = new ScannerSerizable[10];
scannerSerizables[0] = scannerSerizable1;
scannerSerizables[1] = scannerSerizable2;
scannerSerizables[2] = scannerSerizable3;
scannerSerizables[3] = scannerSerizable4;
scannerSerizables[4] = scannerSerizable5;
scannerSerizables[5] = scannerSerizable6;
scannerSerizables[6] = scannerSerizable7;
scannerSerizables[7] = scannerSerizable8;
scannerSerizables[8] = scannerSerizable9;
scannerSerizables[9] = scannerSerizable10;
FileOutputStream fileOutputStream = new FileOutputStream("F://heros.lol");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
for(int i =0;i<10;i++)
{
objectOutputStream.writeObject(scannerSerizables[i]);
}
FileInputStream fileInputStream = new FileInputStream("F://heros.lol");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
for(int i =0;i<10;i++)
{
ScannerSerizable scannerSerizable = (ScannerSerizable) objectInputStream.readObject();
System.out.println("姓名:"+scannerSerizable.getName()+";age:"+scannerSerizable.getAge());
}
}