Java基礎14-java進階(5)【IO流】
Java進階06 IO流
1 File類
1.1 簡介
-
java.io.File類:檔案和檔案目錄路徑的抽象表示形式,與平臺無關
-
File 能新建、刪除、重新命名檔案和目錄,但 File 不能訪問檔案內容本身。如果需要訪問檔案內容本身,則需要使用輸入/輸出流。
-
想要在Java程式中表示一個真實存在的檔案或目錄,那麼必須有一個File對 象,但是Java程式中的一個File物件,可能沒有一個真實存在的檔案或目錄。
-
File物件可以作為引數傳遞給流的構造器
1.2 常用構造器
-
public File(String pathname)
- 以pathname為路徑建立File物件,可以是絕對路徑或者相對路徑,如果 pathname是相對路徑,則預設的當前路徑在系統屬性user.dir中儲存。
- 絕對路徑:是一個固定的路徑,從碟符開始
- 相對路徑:是相對於某個位置開始
- “/”:表示根路徑(或windows碟符)
- “./”表示當前路徑(idea中表示專案的路徑),在使用“./”獲取當前路徑的檔案時“./”可以省略
- “…/”表示當前路徑的上一級(idea中表示專案的路徑)
- 以pathname為路徑建立File物件,可以是絕對路徑或者相對路徑,如果 pathname是相對路徑,則預設的當前路徑在系統屬性user.dir中儲存。
-
public File(String parent,String child)
- 以parent為父路徑,child為子路徑建立File物件。
-
public File(File parent,String child)
- 根據一個父File物件和子檔案路徑建立File物件
-
路徑中的每級目錄之間用一個路徑分隔符隔開。
-
路徑分隔符和系統有關:
- windows和DOS系統預設使用“\”來表示
- UNIX和URL使用“/”來表示
-
Java程式支援跨平臺執行,因此路徑分隔符要慎用。
1.3 常用方法
-
File類的獲取功能
- public String getAbsolutePath():獲取絕對路徑 (檔案)
- public String getPath() :獲取路徑 (檔案)
- public String getName() :獲取名稱 (檔案)
- public String getParent():獲取上層檔案目錄路徑。若無,返回null (檔案)
- public long length() :獲取檔案長度(即:位元組數)。不能獲取目錄的長度。 (檔案)
- public long lastModified() :獲取最後一次的修改時間,毫秒值 (檔案)
- public String[] list() :獲取指定目錄下的所有檔案或者檔案目錄的名稱陣列 (目錄)
- public File[] listFiles() :獲取指定目錄下的所有檔案或者檔案目錄的File陣列 (目錄)
-
File類的重新命名功能
- public boolean renameTo(File dest):把檔案重新命名為指定的檔案路徑 (檔案)
-
File類的判斷功能
- public boolean isDirectory():判斷是否是檔案目錄 (目錄)
- public boolean isFile() :判斷是否是檔案 (檔案)
- public boolean exists() :判斷是否存在 (檔案)
- public boolean canRead() :判斷是否可讀 (檔案)
- public boolean canWrite() :判斷是否可寫 (檔案)
- public boolean isHidden() :判斷是否隱藏 (檔案)
-
File類的建立功能
- public boolean createNewFile() :建立檔案。若檔案存在,則不建立,返回false (檔案)
- public boolean mkdir() :建立檔案目錄。如果此檔案目錄存在,就不建立了。 如果此檔案目錄的上層目錄不存在,也不建立。 (目錄)
- public boolean mkdirs() :建立檔案目錄。如果上層檔案目錄不存在,一併建立 (目錄)
-
File類的刪除功能
- public boolean delete():刪除檔案或者資料夾 (檔案/目錄)
- 刪除注意事項: Java中的刪除不走回收站。 要刪除一個檔案目錄,請注意該檔案目錄內不能包含檔案或者檔案目錄
示例程式碼
File dir1 = new File("D:/IOTest/dir1");
if (!dir1.exists()) { // 如果D:/IOTest/dir1不存在,就建立為目錄
dir1.mkdir();
}
// 建立以dir1為父目錄,名為"dir2"的File物件
File dir2 = new File(dir1, "dir2");
if (!dir2.exists()) { // 如果還不存在,就建立為目錄
dir2.mkdirs();
}
File dir4 = new File(dir1, "dir3/dir4");
if (!dir4.exists()) {
dir4.mkdirs();
}
// 建立以dir2為父目錄,名為"test.txt"的File物件
File file = new File(dir2, "test.txt");
if (!file.exists()) { // 如果還不存在,就建立為檔案
file.createNewFile();
}
課堂練習-class01
1. 利用File構造器,new 一個檔案目錄file
1)在其中建立多個檔案和目錄
2)編寫方法,實現刪除file中指定檔案的操作
2. 判斷指定目錄下是否有字尾名為.jpg的檔案,如果有,就輸出該檔名稱
3. 遍歷指定目錄所有檔名稱,包括子檔案目錄中的檔案。
擴充1:並計算指定目錄佔用空間的大小
擴充2:刪除指定檔案目錄及其下的所有檔案
1.4 常見應用
遍歷檔案
public static void listAll(File dir) {
System.out.println(dir.getName());
//獲取指定目錄下當前的所有資料夾或者檔案物件
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++){
if(files[x].isDirectory()){
listAll(files[x]);
}
else
System.out.println(files[x].getName());
}
}
刪除檔案
public static void main(String[] args) {
File dir = new File("e:\\demodir");
// dir.delete();
removeDir(dir);
}
public static void removeDir(File dir) {
File[] files = dir.listFiles();
for(File file : files){
if(file.isDirectory()){
removeDir(file);
}else{
System.out.println(file+":"+file.delete());
}
}
System.out.println(dir+":"+dir.delete());
}
2 IO流及其分類
2.1 Java IO原理
-
I/O是Input/Output的縮寫, I/O技術是非常實用的技術,用於處理裝置之間的資料傳輸。如讀/寫檔案,網路通訊等。
-
Java程式中,對於資料的輸入/輸出操作以“流(stream)”的方式進行。
-
java.io包下提供了各種“流”類和介面,用以獲取不同種類的資料,並通過標準的方法輸入或輸出資料。
-
輸入input:讀取外部資料(磁 盤、光碟等儲存裝置的資料)到程式(記憶體)中。
-
輸出output:將程式(記憶體) 資料輸出到磁碟、光碟等儲存裝置中。
2.2 流的分類 #重點#
-
按操作資料單位不同分為:位元組流(8 bit)–>處理非文字檔案,字元流(16 bit)–>處理文字檔案
-
按資料流的流向不同分為:輸入流,輸出流
-
按流的角色的不同分為:節點流-->最基本的流,處理流
位元組流 | 字元流 | |
---|---|---|
輸入流 | InputStream | Reader |
輸出流 | OutputStream | Writer |
-
Java的IO流共涉及40多個類,實際上非常規則,都是從如下4個抽象基類派生的。
-
由這四個類派生出來的子類名稱都是以其父類名作為子類名字尾。
3 節點流–#重點#
3.1 FileReader
//使用異常
FileReader fr = null;
try {
//1.例項化File類的物件,指明要操作的檔案
File file = new File("hello.txt");
//2.提供具體的流
fr = new FileReader(file);
//3.資料的讀入
int data;
while((data = fr.read()) != -1){
System.out.print((char)data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的關閉操作
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//使用陣列的方式--》提高使用的效率
FileReader fr = null;
try {
//1.File類的例項化
File file = new File("hello.txt");
//2.FileReader流的例項化
fr = new FileReader(file);
//3.讀入的操作
//read(char[] cbuf):返回每次讀入cbuf陣列中的字元的個數。如果達到檔案末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){
//方式一:
//正確的寫法
for(int i = 0;i < len;i++){
System.out.print(cbuf[i]);
}
//方式二:
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null){
//4.資源的關閉
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 FileWriter
//未使用異常
public class FileWriterText {
public static void main(String[] args) throws IOException {
//FileWriter
// 1.建立File物件,讓該物件關聯a.txt
File file=new File("C:\\Users\\小管同學\\Desktop\\readerA.txt");
FileWriter fileWriter=new FileWriter(file);
fileWriter.write("fileWriter使用");
fileWriter.close();
}
}
//使用異常
public class FileWriterText {
public static void main(String[] args) {
//FileWriter
// 1.建立File物件,讓該物件關聯a.txt
File file=new File("C:\\Users\\小管同學\\Desktop\\readerA.txt");
FileWriter fileWriter= null;
try {
fileWriter = new FileWriter(file);
fileWriter.write("fileWriter使用");
} catch (IOException e) {
e.printStackTrace();
}
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileWriter fw = null;
try {
//1.提供File類的物件,指明寫出到的檔案
File file = new File("hello1.txt");
//2.提供FileWriter的物件,用於資料的寫出
fw = new FileWriter(file,false);
//3.寫出的操作
fw.write("I have a dream!\n");
fw.write("you need to have a dream!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流資源的關閉
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文字檔案的複製
FileReader fr = null;
FileWriter fw = null;
try {
//1.建立File類的物件,指明讀入和寫出的檔案
File srcFile = new File("hello.txt");
File destFile = new File("hello2.txt");
//2.建立輸入流和輸出流的物件
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.資料的讀入和寫出操作
char[] cbuf = new char[5];
int len;//記錄每次讀入到cbuf陣列中的字元的個數
while((len = fr.read(cbuf)) != -1){
//每次寫出len個字元
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.關閉流資源
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//未使用異常
public class CopyCharFile {
public static void main(String[] args) throws IOException {
// 1.建立原始檔以及目標檔案
File sourceFile=new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計.md");
File destFile=new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計(賦值).md");
// 2.建立FileReader和FileWriter
FileReader reader = new FileReader( sourceFile);
FileWriter writer = new FileWriter(destFile);
// 3使用迴圈一遍讀一邊寫(讀一個字元,寫一個字元)
int read = 0;
while ((read = reader.read()) != -1){
writer.write(read);
}
// 4關閉流(後建立或者使用的流先關閉)
writer.close();
reader.close();
}
}
//使用異常
public class CopyCharFile {
public static void main(String[] args) {
// 1.建立原始檔以及目標檔案
File sourceFile=new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計.md");
File destFile=new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計(賦值).md");
FileReader reader = null;
FileWriter writer = null;
try {
// 2.建立FileReader和FileWriter
reader = new FileReader( sourceFile);
writer = new FileWriter(destFile);
// 3使用迴圈一遍讀一邊寫(讀一個字元,寫一個字元)
// int read = 0;
// while ((read = reader.read()) != -1){
// writer.write(read);
// }
// 3使用快取進行讀寫優化,調成2的倍數(1024)
// 使用迴圈一遍讀一邊寫2(讀1024個字元,寫1024個字元)優化提高效率
char[] cbuf=new char[1024];
int len;
while ((len=reader.read(cbuf))!=-1){
writer.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
// 4關閉流(後建立或者使用的流先關閉)
writer.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3 FileInputStream和FileOutputStream
FileInputStream fis = null;
try {
//1. 造檔案
File file = new File("hello.txt");
//2.造流
fis = new FileInputStream(file);
//3.讀資料
byte[] buffer = new byte[5];
int len;//記錄每次讀取的位元組的個數
while((len = fis.read(buffer)) != -1){
String str = new String(buffer,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
//4.關閉資源
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
實現對圖片的複製
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//
File srcFile = new File("愛情與友情.jpg");
File destFile = new File("愛情與友情2.jpg");
//
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//複製的過程
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null){
//
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
指定路徑下檔案的複製
//指定路徑下檔案的複製
public void copyFile(String srcPath,String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//複製的過程
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null){
//
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//未使用異常
public class ImageCopy {
public static void main(String[] args) throws Exception {
File source=new File("C:\\Users\\小管同學\\Desktop\\text\\數小信.png");
File dest=new File("C:\\Users\\小管同學\\Desktop\\text\\數小信(賦值).png");
//位元組輸入流和位元組輸出流
FileInputStream inputStream = new FileInputStream( source) ;
FileOutputStream outputStream = new FileOutputStream( dest) ;
//緩衝流
BufferedInputStream BufferedInputStream=new BufferedInputStream(inputStream);
BufferedOutputStream bufferedInputStream=new BufferedOutputStream(outputStream);
long start=System.currentTimeMillis();
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0,len); ;
}
long end=System.currentTimeMillis();
outputStream.close();
inputStream.close();
System.out.println("此次複製公用"+(end-start)+"毫秒");
}
}
4 緩衝流-提高效率–#重點#
-
為了提高資料讀寫的速度,Java API提供了帶緩衝功能的流類,在使用這些流類時,會建立一個內部緩衝區陣列,預設使用8192個位元組(8Kb)的緩衝區。
-
緩衝流要“套接”在相應的節點流之上,根據資料操作單位可以把緩衝流分為:
- BufferedInputStream 和 BufferedOutputStream
- BufferedReader 和 BufferedWriter
-
當讀取資料時,資料按塊讀入緩衝區,其後的讀操作則直接訪問緩衝區
-
當使用BufferedInputStream讀取位元組檔案時,BufferedInputStream會一次性從檔案中讀取8192個(8Kb),存在緩衝區中,直到緩衝區裝滿了,才重新從檔案中讀取下一個8192個位元組陣列。
-
向流中寫入位元組時,不會直接寫到檔案,先寫到緩衝區中直到緩衝區寫滿, BufferedOutputStream才會把緩衝區中的資料一次性寫到檔案裡。使用方法 flush()可以強制將緩衝區的內容全部寫入輸出流
-
關閉流的順序和開啟流的順序相反。只要關閉最外層流即可,關閉最外層流也會相應關閉內層節點流
-
flush()方法的使用:手動將buffer中內容寫入檔案
-
如果是帶緩衝區的流物件的close()方法,不但會關閉流,還會在關閉流之前重新整理緩衝區,關閉後不能再寫出
示例程式碼
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 建立緩衝流物件:它是處理流,是對節點流的包裝
br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt"));
bw = new BufferedWriter(new FileWriter("d:\\IOTest\\dest.txt"));
String str;
while ((str = br.readLine()) != null) { // 一次讀取字元文字檔案的一行字元
bw.write(str); // 一次寫入一行字串
bw.newLine(); // 寫入行分隔符
}
bw.flush(); // 重新整理緩衝區
} catch (IOException e) {
e.printStackTrace();
} finally {
// 關閉IO流物件
try {
if (bw != null) {
bw.close(); // 關閉過濾流時,會自動關閉它所包裝的底層節點流
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
} }
public class BufferedCopyFile {
public static void main(String[] args) throws IOException {
// 1.建立原始檔以及目標檔案
File sourceFile=new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計.md");
File destFile=new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計(賦值).md");
// 2.節點流
FileReader reader = new FileReader( sourceFile);
FileWriter writer = new FileWriter (destFile) ;
//3帶緩衝功能的字元處理流
BufferedReader bufferedReader = new BufferedReader(reader);
BufferedWriter bufferedWriter = new BufferedWriter(writer);
//readLine()每次讀入一行資料,如果沒有資料,返回null
String str;
while ((str=bufferedReader.readLine())!=null){
bufferedWriter.write(str);
bufferedWriter.newLine();//增加換行符
}
//4關閉流
bufferedWriter.close();
bufferedReader. close();
}
}
public class BufferedCopyFile {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader( new FileReader( new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計.md")));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter (new File("C:\\Users\\小管同學\\Desktop\\text\\06 網路程式設計(賦值).md")) );
//readLine()每次讀入一行資料,如果沒有資料,返回null
String str;
while ((str=bufferedReader.readLine())!=null){
bufferedWriter.write(str);
bufferedWriter.newLine();//增加換行符
}
//4關閉流
bufferedWriter.close();
bufferedReader. close();
}
}
課堂練習
1. 分別使用節點流:FileInputStream、FileOutputStream和緩衝流:BufferedInputStream、BufferedOutputStream實現文字檔案/圖片/視訊檔案的複製。並比較二者在資料複製方面的效率
2. 實現圖片加密操作。
int b = 0;
while((b = fis.read()) != -1){
fos.write(b ^ 5);
}
5 轉換流 #重點#
-
轉換流提供了在位元組流和字元流之間的轉換
-
Java API提供了兩個轉換流:
- InputStreamReader:將InputStream轉換為Reader
- OutputStreamWriter:將Writer轉換為OutputStream
-
位元組流中的資料都是字元時,轉成字元流操作更高效。
-
很多時候我們使用轉換流來處理檔案亂碼問題。實現編碼和解碼的功能。
5.1 InputStreamReader
-
實現將位元組的輸入流按指定字符集轉換為字元的輸入流。
-
需要和InputStream“套接”。
-
構造器
- public InputStreamReader(InputStream in)
- public InputSreamReader(InputStream in,String charsetName)
Reader isr = new InputStreamReader(System.in,”gbk”);
public class TransterTest {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\小管同學\\Desktop\\text\\reader.txt"));
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"utf-8");//位元組到字元的轉換
int read=0;
while ((read=inputStreamReader.read())!=-1){
System.out.print((char)read);
}
fileInputStream.close();
}
}
5.2 OutputStreamWriter
-
實現將字元的輸出流按指定字符集轉換為位元組的輸出流。
-
需要和OutputStream“套接”。
-
構造器
- public OutputStreamWriter(OutputStream out)
- public OutputSreamWriter(OutputStream out,String charsetName)
示例程式碼
public void testMyInput() throws Exception {
FileInputStream fis = new FileInputStream("dbcp.txt");
FileOutputStream fos = new FileOutputStream("dbcp5.txt");
InputStreamReader isr = new InputStreamReader(fis, "GBK");
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
BufferedReader br = new BufferedReader(isr);
BufferedWriter bw = new BufferedWriter(osw);
String str = null;
while ((str = br.readLine()) != null) {
bw.write(str);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
public class TransterTest {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\小管同學\\Desktop\\text\\reader.txt"));
FileOutputStream fileOutputStream = new FileOutputStream(new File("C:\\Users\\小管同學\\Desktop\\text\\reader.txt"));
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"utf-8");//位元組到字元的轉換
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");
int read=0;
while ((read=inputStreamReader.read())!=-1){
// System.out.print((char)read);
outputStreamWriter.write(read);
}
// fileInputStream.close();
outputStreamWriter.close();
inputStreamReader.close();
}
}
6 標準輸入、輸出流
-
System.in和System.out分別代表了系統標準的輸入和輸出裝置
-
預設輸入裝置是:鍵盤,輸出裝置是:顯示器
-
System.in的型別是InputStream
-
System.out的型別是PrintStream,其是OutputStream的子類 FilterOutputStream 的子類
-
重定向:通過System類的setIn,setOut方法對預設裝置進行改變。
- public static void setIn(InputStream in)
- public static void setOut(PrintStream out)
示例程式碼
從鍵盤輸入字串,要求將讀取到的整行字串轉成大寫輸出。然後繼續進行輸入操作,直至當輸入“e”或者“exit”時,退出程式。
System.out.println("請輸入資訊(退出輸入e或exit):");
// 把"標準"輸入流(鍵盤輸入)這個位元組流包裝成字元流,再包裝成緩衝流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
while ((s = br.readLine()) != null) { // 讀取使用者輸入的一行資料 --> 阻塞程式
if ("e".equalsIgnoreCase(s) || "exit".equalsIgnoreCase(s)) {
System.out.println("安全退出!!");
break;
}
// 將讀取到的整行字串轉成大寫輸出
System.out.println("-->:" + s.toUpperCase());
System.out.println("繼續輸入資訊");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close(); // 關閉過濾流時,會自動關閉它包裝的底層節點流
}
} catch (IOException e) {
e.printStackTrace();
}
}
7 物件流
-
ObjectInputStream和OjbectOutputSteam
- 用於儲存和讀取基本資料型別資料或物件的處理流。它的強大之處就是可以把Java中的物件寫入到資料來源中,也能把物件從資料來源中還原回來。
-
序列化:用ObjectOutputStream類儲存基本型別資料或物件的機制
-
反序列化:用ObjectInputStream類讀取基本型別資料或物件的機制
-
ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變數
物件的序列化–掌握
-
物件序列化機制允許把記憶體中的Java物件轉換成平臺無關的二進位制流,從而允許把這種二進位制流持久地儲存在磁碟上,或通過網路將這種二進位制流傳輸到另一個網路節點。當其它程式獲取了這種二進位制流,就可以恢復成原來的Java物件
-
序列化的好處在於可將任何實現了Serializable介面的物件轉化為位元組資料, 使其在儲存和傳輸時可被還原
-
序列化是 RMI(Remote Method Invoke – 遠端方法呼叫)過程的引數和返 回值都必須實現的機制,而 RMI 是 JavaEE 的基礎。因此序列化機制是JavaEE 平臺的基礎
-
如果需要讓某個物件支援序列化機制,則必須讓物件所屬的類及其屬性是可序列化的,為了讓某個類是可序列化的,該類必須實現如下兩個介面之一。 否則,會丟擲NotSerializableException異常
- Serializable
- Externalizable
-
凡是實現Serializable介面的類都有一個表示序列化版本識別符號的靜態變數:
private static final long serialVersionUID;
- serialVersionUID用來表明類的不同版本間的相容性。簡言之,其目的是以序列化物件進行版本控制,有關各版本反序列化時是否相容。
- 如果類沒有顯示定義這個靜態常量,它的值是Java執行時環境根據類的內部細節自動生成的。若類的例項變數做了修改,serialVersionUID 可能發生變化。故建議, 顯式宣告。
-
簡單來說,Java的序列化機制是通過在執行時判斷類的serialVersionUID來驗 證版本一致性的。在進行反序列化時,JVM會把傳來的位元組流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異 常。(InvalidCastException)
使用物件流序列化物件
-
若某個類實現了 Serializable 介面,該類的物件就是可序列化的:
- 建立一個ObjectOutputStream
- 呼叫ObjectOutputStream物件的writeObject(物件)方法輸出可序列化物件
- 注意寫出一次,操作flush()一次
-
反序列化
- 建立一個ObjectInputStream
- 呼叫readObject()方法讀取流中的物件
強調:如果某個類的屬性不是基本資料型別或 String 型別,而是另一個引用型別,那麼這個引用型別必須是可序列化的,否則擁有該型別的Field的類也不能序列化
示例程式碼
//序列化:將物件寫入到磁碟或者進行網路傳輸。
//要求物件必須實現序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person("韓梅梅", 18, "中華大街", new Pet());
oos.writeObject(p);
oos.flush();
oos.close();
//反序列化:將磁碟中的物件資料來源讀出。
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();
8 隨機存取檔案流
-
RandomAccessFile
宣告在java.io包下,但直接繼承於java.lang.Object類。並且它實現了DataInput、DataOutput這兩個介面,也就意味著這個類既可以讀也可以寫。 -
RandomAccessFile 類支援 “隨機訪問”的方式,程式可以直接跳到檔案的任意地方來讀、寫檔案
- 支援只訪問檔案的部分內容
- 可以向已存在的檔案後追加內容
-
RandomAccessFile 物件包含一個記錄指標,用以標示當前讀寫處的位置。RandomAccessFile 類物件可以自由移動記錄指標:
- long getFilePointer():獲取檔案記錄指標的當前位置
- void seek(long pos):將檔案記錄指標定位到 pos 位置
-
構造器
- public RandomAccessFile(File file, String mode)
- public RandomAccessFile(String name, String mode)
-
建立 RandomAccessFile 類例項需要指定一個 mode 引數,該引數指定 RandomAccessFile 的訪問模式:
- r:以只讀方式開啟
- rw:開啟以便讀取和寫入
- rwd:開啟以便讀取和寫入;同步檔案內容的更新
- rws:開啟以便讀取和寫入;同步檔案內容和後設資料的更新
-
如果模式為只讀r。則不會建立檔案,而是會去讀取一個已經存在的檔案,如果讀取的檔案不存在則會出現異常。 如果模式為rw讀寫。如果檔案不存在則會去建立檔案,如果存在則不會建立。
示例程式碼
//讀取檔案內容
RandomAccessFile raf = new RandomAccessFile(“test.txt”, “rw”);
raf.seek(5);
byte [] b = new byte[1024];
int off = 0;
int len = 5;
raf.read(b, off, len);
String str = new String(b, 0, len);
System.out.println(str);
raf.close();
//寫入檔案內容
RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
raf.seek(5);
//先讀出來
String temp = raf.readLine();
raf.seek(5);
raf.write("xyz".getBytes());
raf.write(temp.getBytes());
raf.close();
9 流的基本應用小節
-
流是用來處理資料的。
-
處理資料時,一定要先明確資料來源,與資料目的地
- 資料來源可以是檔案,可以是鍵盤。
- 資料目的地可以是檔案、顯示器或者其他裝置。
-
處理流是在幫助資料進行傳輸,並對傳輸的資料進行處理,比如過濾處理、轉換處理等。。
相關文章
- java進階(33)--IO流Java
- JAVA_基礎IO流物件流(三)Java物件
- Java基礎 Java-IO流 深入淺出Java
- java基礎學習_io流之FileInputStreamJava
- Java基礎(八)——IO流1_位元組流、字元流Java字元
- java基礎(四):談談java中的IO流Java
- Java基礎之IO轉換流學習Java
- Java基礎(八)——IO流2_緩衝流、轉換流Java
- Java基礎知識回顧之六 —– IO流Java
- Java程式設計基礎23——IO(其他流)&PropertiesJava程式設計
- Java基礎知識回顧之六 ----- IO流Java
- IO流上:概述、字元流、緩衝區(java基礎)字元Java
- [Java基礎]IOJava
- 長沙Java培訓:Java基礎通往高階進階篇Java
- java -IO流Java
- Java IO流Java
- Java IO: 流Java
- Java IO流Java
- java - IO流Java
- JAVA進階之IO模型深入解析Java模型
- 12Java進階-IO與XMLJavaXML
- [java IO流]之 IO概述Java
- Java零基礎學java之IO流--05InputStream位元組輸入流Java
- [Java基礎]Stream流Java
- 13Java進階——IO、執行緒Java執行緒
- Java的IO流Java
- Python的基礎進階Python
- Java筆記-IO流Java筆記
- JAVA IO流-小白版Java
- 【重學Java】IO流Java
- Java IO流(詳細)Java
- Io流階段大總結
- Java面試真題之中級進階(執行緒,程序,序列化,IO流,NIO)Java面試執行緒
- [Java SE] 基礎工具庫 : Apache Commons IOJavaApache
- Python基礎之IO流和序列化講解Python
- 前端基礎之jQuery進階前端jQuery
- 【Go進階—基礎特性】反射Go反射
- 【Go進階—基礎特性】deferGo