Input 輸入
Output 輸出
文件
java.io.File 它是對應者實際的文件或是文件夾(目錄)
new File(String 文件路徑)
new File("d:/1.txt"); // 可以使用 / 作爲分隔符
new File("D:\\MySQL"); // 可以使用 \ 作爲分隔符
或者可以使用 File.separator
獲取不同操作系統的分隔符
1. 文件對象的api
.isFile() ; 返回一個布爾值代表是否是文件
.isDirectory(); 返回一個布爾值代表是否是目錄
File 可以用來代表不存在的目錄或文件:
.mkdir() 來創建一個目錄
.mkdirs() 可以用來創建多級目錄
File file = new File("D:\\a\\b\\c");
file.mkdirs();
.exists() 用來判斷一個文件或目錄是否存在
.listFiles() 得到一個目錄下的所有子目錄和文件
File file = new File("D:\\6.23實訓班共享");
File[] files = file.listFiles();
for(File f: files) {
System.out.println(f);
}
可以使用FilenameFilter接口來過濾需要的文件或文件夾
File[] files2 = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.startsWith("筆")) {
return true;
} else {
return false;
}
}
});
for(File f :files2) {
System.out.println(f);
}
刪除文件(立刻)
new File("D:\\6.23實訓班共享\\測試.txt").delete();
刪除文件(當程序運行結束)
new File("D:\\6.23實訓班共享\\測試.txt").deleteOnExit();
重命名和移動
new File("D:\\6.23實訓班共享\\測試.txt").renameTo(new File("c:\\測試2.txt"));
相對路徑
File file = new File("D:\\6.23實訓班共享\\代碼\\Day16-IO\\1.txt");// 絕對路徑
System.out.println(file.exists());
System.out.println(System.getProperty("user.dir")); // 當前目錄
File file2 = new File("1.txt"); // 相對路徑
System.out.println(file2.exists());
System.out.println(file2.getAbsoluteFile());
2.IO流
Input 輸入流: 從文件讀取內容,文件對我就是輸入流
Output 輸出流: 向文件寫入內容,文件對我就是輸出流
2.1 字節流(以字節爲單位操作數據)
InputStream 抽象類 -> FileInputStream 文件輸入流
OutputStream 抽象類 -> FileOutputStream 文件輸出流
讀取內容:
-
一次讀取一個字節
// 1. 創建輸入流對象 FileInputStream fis = new FileInputStream(new File("1.txt")); // FileInputStream fis = new FileInputStream("1.txt") // 2. 讀取內容 /*int read = fis.read();// 一次讀取一個字節, 返回int中只用了一個字節 System.out.println((char)read); read = fis.read(); System.out.println((char)read); read = fis.read(); System.out.println((char)read); read = fis.read(); System.out.println(read);*/ while(true) { int read = fis.read(); if(read == -1) { break; } System.out.println(read); }
- 一次讀取多個字節
// 1. 創建輸入流對象 FileInputStream fis = new FileInputStream(new File("1.txt"));
// 2. 一次讀取多個字節
byte[] buf = new byte[2];
/*int len = fis.read(buf);// 將讀到的內容填充到byte數組中,返回的是讀到的字節總數, 返回-1還是表示讀取完畢了
System.out.println(len);
System.out.println(Arrays.toString(buf));
len = fis.read(buf);
System.out.println(len);
System.out.println(Arrays.toString(buf));
len = fis.read(buf);
System.out.println(len);*/
while(true) {
int n = fis.read(buf);
if(n == -1) {
break;
}
System.out.println(Arrays.toString(buf));
}
> 特點: 流是單向的
3. 輸出流例子:
```java
// 1.創建了輸出流
FileOutputStream fos = new FileOutputStream("2.txt");
// 2. 向輸出流寫入內容
fos.write(97);
fos.write(98);
fos.write(99);
// 3. 關閉輸出流
fos.close();
-
文件的複製
FileInputStream fis = new FileInputStream("1.txt"); FileOutputStream fos = new FileOutputStream("3.txt"); while(true) { byte[] buf = new byte[1024]; int len = fis.read(buf); if(len == -1) { break; } fos.write(buf, 0, len); // 實際讀到len個字節,就寫入len個字節 } fis.close(); fos.close();
2.2 字符流
以字符爲單位處理流的內容
Reader 字符輸入流 InputStreamReader 將字節流轉爲字符流
Writer 字符輸出流 OutputStreamWriter 將字節流轉爲字符流
public static void main(String[] args) throws IOException {
// 1. 將字節流轉換爲字符流
FileInputStream fis = new FileInputStream("1.txt");
// 注意:實際文件編碼要與讀取時的文件編碼一致
InputStreamReader reader = new InputStreamReader(fis, "utf-8");
// 2. 讀取
/*while(true) {
int c = reader.read();
if(c == - 1) {
break;
}
System.out.println((char)c);
}*/
while(true) {
char[] buf = new char[1024];
int len = reader.read(buf);
if(len == -1) {
break;
}
System.out.println(Arrays.toString(buf));
}
// 3. 關閉, 只需要關閉外層的流, 內部會幫我們關掉內層的流
reader.close();
}
BufferedReader 在InputStreamReader的基礎上以行爲單位處理字符流
與 InputStreamReader是平級關係, 父類都是Reader
FileInputStream fis = new FileInputStream("1.txt");
InputStreamReader reader = new InputStreamReader(fis, "utf-8");
BufferedReader reader2 = new BufferedReader(reader);
/*System.out.println(reader2.readLine()); // 以行爲單位讀取數據
System.out.println(reader2.readLine()); // 以行爲單位讀取數據
System.out.println(reader2.readLine()); // 以行爲單位讀取數據*/
while(true) {
String line = reader2.readLine();
if(line == null) {
break;
}
System.out.println(line);
}
reader2.close();
BufferedReader與InputStreamReader體現的是裝飾者模式
裝飾者模式
裝飾者與被裝飾者需要有一個共同的父類
裝飾者和被裝飾者之間體現的是組合的關係,而不是繼承的關係(目的是爲了更加靈活)
裝飾者會對被裝飾者做功能上的增強
Effective(高效的) JAVA
組合優於繼承
字節流
InputStream
(*) FileInputStream 從文件讀取字節
(*) BufferedInputStream 加入緩衝功能,提高文件的讀取效率
ByteArrayInputStream 從字節數組變成輸入流
OutputStream
(*) FileOutputStream 向文件寫入字節
(*) BufferedOutputStream 加入緩衝功能, 提高文件的寫入效率
ByteArrayOutputStream 把流的內容寫入字節數組
PrintStream 實際上就是 System.out
字符流
Reader
() InputStreamReader 轉換字節流爲字符流
() BufferedReader 功能增強,以行爲單位讀取數據 (裝飾器模式)
FileReader 是InputStreamReader子類,將字符編碼固定爲操作系統的默認編碼,不能手工改動
Writer
() OutputStreamWriter 轉換字節流爲字符流
() PrintWriter 以行爲單位寫入數據
write 當成字符寫入
print print就是將參數轉爲字符串後寫入
FileWriter 是OutputStreamWriter的子類,也是固定了字符編碼
java中的序列化
問題:如何將對象中的信息永久保存
1.將來將對象信息存入數據庫
2.java 中提供的序列化方式來永久保存數據
首先要讓類實現Serializable序列化接口
第二使用ObjectOutputStream 寫入要序列化的對象
public class Student implements Serializable{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```java
Student student = new Student();
student.setId(1);
student.setName("張三");
// 序列化就是將對象變爲輸出字節流
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:\\student.obj"));
os.writeObject(student);
os.close();
如果沒有實現Serializable接口,會出現NotSerializableException
注意:
1)要求對象中的所有屬性也都是可以序列化
2)如果某個屬性不想序列化,可以在屬性上加transient
關鍵字
反序列化
把字節內容讀取進來,還原爲java對象
ObjectInputStream用來讀取字節內容,還原(反序列化)爲java對象
ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:\\student.obj"));
Student s = (Student)is.readObject();
System.out.println(s.getId());
System.out.println(s.getName());
System.out.println(s.getAddress());
除了可以寫入和讀取對象以外,還可以寫入和讀取基本類型(int,long,boolean...) ,讀取和寫入的順序要保持一致
如果不一致,出現EOFException
如果沒有更多內容,也會出現EOFException
建議在寫入時最後一個對象使用null,這樣讀取時就可以根據null來判斷是否讀取完畢
序列化和反序列化其實也是java中的一種數據傳輸的機制
創建對象的幾種方式:
- 反序列化
- clone 是一種
- new 是一種
克隆需要實現Cloneable接口,並覆蓋clone方法,克隆舉例:
public class Teacher implements Cloneable{ // 可克隆的
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 必須調用Object父類的克隆方法
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Teacher t = new Teacher();
t.setId(1);
t.setName("滿老師");
Teacher t2 = (Teacher)t.clone();
System.out.println(t2.getId());
System.out.println(t2.getName());
System.out.println(t2 == t);
}
}
克隆對應的設計模式:原型(prototype)模式 ,不走構造方法,根據一個已有對象創建新的對象。
使用Cloneable接口和clone克隆的對象,僅僅是淺拷貝
,如果屬性爲引用類型,複製的僅是地址。沒有爲這個屬性創建新的對象
深拷貝
利用序列化和反序列化生成新的對象,也會爲屬性創建新的對象
例:
public class Teacher2 implements Serializable{
private int id;
private String name;
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher2 clone() {
try {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(this); // 寫入當前對象
byte[] bytes = bos.toByteArray(); // 字節結果
// 反序列化
ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bytes));
Teacher2 t = (Teacher2)is.readObject();
return t;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
Teacher2 t = new Teacher2();
t.setId(1);
t.setName("李老師");
t.setBirthday(new Date());
Teacher2 t2 = t.clone();
System.out.println(t == t2);
System.out.println(t.getBirthday() == t2.getBirthday());
}
}