java.io.file.sync_Java(25)IO流和File類

IO流+File類

File類

講IO流之前先來講以下File類。Java的標準庫Java.io提供了File類來操作文件和目錄。操作可以有:新建、刪除、重命名等,但是不能訪問文件本身的內容,如果想要訪問,需要使用IO流。

新建File對象:

package day01;

import java.io.File;

class Battery{

public static void main(String[] args) {

File a=new File("C:\\Users\\97464\\Desktop\\test\\File1.txt");

File b=new File("C:\\Users\\97464\\Desktop","test\\File1.txt");

/*

1.上面兩種方式創建的FIle對象是一個意思,File類的不同構造方法導致可以有不同的參數。

2.構造File對象的時候,既可以傳入絕對路徑,也可以傳入相對路徑。

3.注意Windows平臺使用\作為路徑分隔符,在Java字符串中需要用\\表示一個\。Linux平臺使用/作為路徑分隔符。傳入相對路徑時,相對路徑前面加上當前目錄就是絕對路徑。

4. .代表當前目錄..代表上級目錄

*/

}

}

獲取文件或者目錄的路徑和名字等操作

package day01;

import java.io.File;

import java.io.IOException;

class Battery{

public static void main(String[] args){

File tt=new File("F:\\test\\test\\..\\hello.txt");

//獲取文件或者目錄的路徑:

System.out.println(tt.getPath()); //返回構造方法傳入的路徑

System.out.println(tt.getAbsolutePath()); //返回絕對路徑

try {

System.out.println(tt.getCanonicalPath());

//返回規范路徑(C:\\Users\\..----->C:\\)

}catch (IOException e){

e.printStackTrace();

}

//獲取文件或者目錄的名字:

System.out.println(tt.getName());

//返回一個用當前文件的絕對路徑構建的File對象;

File gg=tt.getAbsoluteFile();

System.out.println(gg.getName());

//返回文件或目錄的父級目錄:

System.out.println(tt.getParent());

//重命名文件或目錄:

tt.renameTo(new File("F:\\test\\test\\..\\hello2.txt"));

}

}

/*運行結果為:

F:\test\test\..\hello.txt

F:\test\test\..\hello.txt

F:\test\hello.txt

hello.txt

hello.txt

F:\test\test\..

*/

/*----------------補充:--------------------------------

上面的getCanonicalPath()方法,如果去查看它的源碼可以發現它拋出了IOException異常,如果想要使用它,需要在調用的時候try...catch捕獲異常,或者由main()繼續拋出異常,交給JVM處理。

*/

文件檢測

package day01;

import java.io.File;

class Battery{

public static void main(String[] args){

File a=new File("F:\\test\\hello2.txt");

//判斷文件或者目錄是否存在:

System.out.println(a.exists());

//判斷文件是否可讀或可寫:

System.out.println(a.canRead());

System.out.println(a.canWrite());

//判斷當前File對象是不是文件或者目錄:

System.out.println(a.isFile());

System.out.println(a.isDirectory());

}

}

/*運行結果為:

true

true

true

true

false

*/

獲取文件大小和文件的最后修改時間

package day01;

import java.io.File;

class Battery{

public static void main(String[] args){

File a=new File("F:\\test\\hello2.txt");

System.out.println(a.length()); //返回文件的大小,以字節為單位

System.out.println(a.lastModified()); //返回最后修改時間,是一個毫秒數

}

}

/*運行結果為:

11

1580719765617

*/

新建和刪除文件或目錄

package day01;

import java.io.File;

import java.io.IOException;

class Battery{

public static void main(String[] args){

File a=new File("F:\\test\\hello.txt");

if(!a.exists()){ //判斷文件是否不存在

try{

a.createNewFile();

}catch (IOException e){

e.printStackTrace();

}

}

a.delete(); //刪除文件

File b=new File("F:\\test2");

b.mkdir(); //創建單層目錄

File c=new File("F:\\test3\\kobe\\number24");

c.mkdirs();//創建多層目錄

}

}

遍歷目錄下的文件和子目錄

package day01;

import java.io.File;

class Battery{

public static void main(String[] args){

File d=new File("F:\\test3");

System.out.println(d.list().getClass());

//可以看到d.list()返回的是數據類型是class [Ljava.lang.String;

//[:表示返回的類型是數組,L:表示數組元素是一個對象實例

// Java.land.String表示對象是String類型

//下面進行循環輸出目錄下的文件或者子目錄:

String []strArr=d.list();

for (String i:strArr){

System.out.println(i);

}

File e=new File("F:\\test3");

File [] arrFile=e.listFiles();

//e.listFiles()返回test3目錄下的文件或子目錄的file對象

for (File i: arrFile){

System.out.println(i);

}

}

}

/*運行結果為:

class [Ljava.lang.String;

kobe

F:\test3\kobe

*/

上面遍歷文件和子目錄是單層遍歷,如果想要進行多層遍歷(子目錄的子目錄也會被遍歷),可以進行遞歸遍歷。

案例:

package day01;

import java.io.File;

class Rabbit{

public void fds(File a){

if(a.isFile()){

System.out.println(a.getName());

}else {

System.out.println(a.getName());

File []fileArr=a.listFiles();

for (File i:fileArr){

fds(i); //遞歸

}

}

}

}

class RunClass{

public static void main(String[] args) {

Rabbit test=new Rabbit();

File tf=new File("F:\\test3");

test.fds(tf);

}

}

IO流

IO概念:

IO是指Input/Output,即輸入和輸出,以內存為中心:

Input指從外部讀入數據到內存。----例如把文件從磁盤讀取到內存,從網絡讀取數據到內存等

Output指把數據從內存輸出到外部。----例如把數據從內存寫入文件,把數據從內存輸出到網絡等

為什么要以內存為中心?

------因為數據被讀取到內存中才能被處理,代碼是在內存中運行的,數據也必須內存。

IO流概念:

IO流是一種順序讀寫數據的模式,它的特點是單向流動。

------例如: 想要把一張圖片放入一個文件夾,不能整張直接塞進去,而是需要把圖片轉化為一個數據集(例如二進制),把這些數據一點一點傳到文件夾,這個數據的傳遞類似于自來水在水管中的流動,稱為IO流。

同步和異步

同步IO是指,讀寫IO時代碼必須等待數據返回后才繼續執行后續代碼,它的優點是代碼編寫簡單,缺點是CPU執行效率低。

而異步IO是指,讀寫IO時僅發出請求,然后立刻執行后續代碼,它的優點是CPU執行效率高,缺點是代碼編寫復雜。

Java標準庫的包java.io提供了所有的同步IO,而java.nio則是異步IO。

下面我們即將討論的InputStream、OutputStream、Reader和Writer都是同步IO的抽象類的具體實現類

流的分類

按操作數據單位不同分為:字節流(8 bit),字符流(16 bit)

按數據流的流向不同分為:輸入流,輸出流

按流的角色不同分為:節點流,處理流

抽象基類

字節流

字符流

輸入流

InputStream

Reader

輸出流

OutputStream

Writer

Java的IO流共有40多個相關類,實際上都是從上面的四種抽象基類派生的。

9d32ec13007ea017b2b455bbf8a5a6f4.png

字節流

IO流以byte(字節)為最小單位,稱為字節流。字節流非常通用,不僅可以用來操作字符型文檔,還可以操作任何地其它類型文件(圖片、壓縮包等),因為字節流本身使用地就是二進制。

╔════════════╗

║ Memory ║ 內存

╚════════════╝

│0x48

│0x65

│0x6c

│0x6c

│0x6f

│0x21

╔═══════════╗

║ Hard Disk ║ 硬盤

╚═══════════╝

//上面,內存從硬盤(磁盤)讀入了6個字節的數據,是按順序讀入的,是輸入字節流。

//反過來就是輸出字節流:

╔════════════╗

║ Memory ║ 內存

╚════════════╝

│0x21

│0x6f

│0x6c

│0x6c

│0x65

│0x48

╔═══════════╗

║ Hard Disk ║ 硬盤

╚═══════════╝

InputStream

InputStream是Java標準庫提供的最基本的輸入字節流。位于Java.io這個包里。InputStream是一個抽象類,是所有輸入流的父類,這個抽象類定義的最重要的方法是int read()。源代碼如下:

public abstract int read() throws IOException;

構建InputStream對象:

import java.io.IOException;

import java.io.InputStream;

class MainClass{

public static void main(String[] args) {

InputStream is=new InputStream() {

@Override //可以看到新建InputStream輸入流對象必須重寫抽象方法int read()

public int read() throws IOException {

return 0;

}

};

}

}

read()這個方法會讀取輸入流的下一個字節,并返回字節表示的int值(0-255)(ascii碼),讀到末尾就會返回-1

read()方法還可以傳遞參數——read(byte [] b),作用是一次讀取一個字節數組,把輸入流讀取到的內容存放到這個字節數組中,并返回存放到數組的內容的字節數,同樣是到末尾就返回-1。byte數組是作為一個緩沖區,每次存入數組大小為byte.length的數據,存入的數據是一個int

FileInputStream

FileInputStream是InputStream的一個子類,用來從文件中讀取數據。FileInputStream類的構造方法有:

FileInputStream(File file): 傳遞一個文件的File類對象

FileInputStream(String name): 傳遞一個String類型的文件路徑

案例1: int read()的使用

F:\\test\\hello.txt的文件內容:

abclove

package day01;

import java.io.FileInputStream;

import java.io.IOException;

class MainClass{

public static void main(String[] args) throws IOException { //所有與IO操作相關的代碼都必須正確處理IOException

FileInputStream fis=new FileInputStream("F:\\test\\hello.txt"); //創建流對象

for(;;){ //無限循環

int n = fis.read(); //反復調用read()方法,直到n=-1

if (n==-1){

break;

}

System.out.print(n+":"); //打印read()返回的byte值

System.out.println((char)n);

}

fis.close(); //關閉流,釋放對應的底層資源

}

}

/*運行結果為

97:a

98:b

99:c

108:l

111:o

118:v

101:e

*/

//從運行結果可知,read()返回的單字節整數值,是對應字符的acsii碼。通過(char)就可以轉換為對應字符。

案例2:int read(byte [] b)的使用(緩沖)

package day01;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

class MainClass{

public static void main(String[] args) throws IOException {

InputStream cup=new FileInputStream("F:\\test\\hello.txt");

byte [] b=new byte[3];

//b數組是作為一個緩沖區,在下面的循環中,每循環一次,b就會更新一次,輸入流把讀取到的內容放到b中

int len=0; //初始化len為0

while((len=cup.read(b))!=-1){ //len代表存放到數組b的數據的字節數

System.out.print(len+":");

System.out.println(new String(b,0,len)); //用法看下面的補充

}

cup.close();

}

}

/*運行結果為:

3:abc

3:lov

1:e

*/

/*-------------------------補充:----------------------------------------

String類的構造方法public String(byte bytes[], int offset, int length)的用法:

作用:將字節數組的某部分轉為字符串

參數:byte bytes[]表示要被轉的數組

int offset表示偏移量,即從數組的第幾個位置開始轉為字符串,

int length表示總共要轉化的字節數

read()方法是阻塞的(blocking)。讀取IO流相比執行普通代碼,速度要慢很多。

package day01;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

class MainClass{

public static void main(String[] args) throws IOException {

InputStream a=new FileInputStream("F:\\test\\hello.txt");

System.out.println("kobe");

int b=a.read(); // 必須等待read()方法返回才能執行下一行代碼

System.out.println("gigi");

}

}

OutputStream

OutputStream是Java標準庫提供的最基本的輸出流。OutputStream和InputStream一樣,也是抽象類,是所有輸出流的父類。抽象類定義的一個重要的方法是void write(int b),源代碼如下:

public abstract void write(int b) throws IOException;

write()還有重載方法:

write(byte b[]):用于一次性寫入多個字節

write(byte b[], int off, int len):將數組b從off位置開始,把長度為len字節的數據寫入到文件中

和InputStream一樣,OutputStream的write()方法也是阻塞的。

FileOutputStream

FileOutputStream是OutputStream的子類。FileOutputStream類的構造方法有:

FileOutputStream(File file): 傳遞一個文件的File類對象

FileOutputStream(String name): 傳遞一個String類型的文件路徑

案例1:一次寫入一個字節

package day01;

import java.io.*;

class MainClass{

public static void main(String[] args) throws IOException {

OutputStream ops=new FileOutputStream("F:\\test\\outPut.txt");

ops.write(97); //往文件寫入97ascii碼代表的字符a

ops.write(98); //往文件寫入98ascii碼代表的字符b

ops.write(99); //往文件寫入99ascii碼代表的字符c

ops.flush();

ops.close();

}

}

//運行結果是:往F:\\test\\outPut.txt這個文件寫入“abc",如果這個文件不存在,則會新建文件。

從案例1可以看到,OutputStream還提供了一個flush()方法,它的目的是將緩沖區的內容真正輸出到目的地。

為什么要有flush()?因為向磁盤、網絡寫入數據的時候,出于效率的考慮,操作系統并不是輸出一個字節就立刻寫入到文件或者發送到網絡,而是把輸出的字節先放到內存的一個緩沖區里(本質上就是一個byte[]數組),等到緩沖區寫滿了,再一次性寫入文件或者網絡。對于很多IO設備來說,一次寫一個字節和一次寫1000個字節,花費的時間幾乎是完全一樣的,所以OutputStream有個flush()方法,能強制把緩沖區內容輸出。

通常情況下,我們不需要調用這個flush()方法,因為緩沖區寫滿了OutputStream會自動調用它,并且,在調用close()方法關閉OutputStream之前,也會自動調用flush()方法。

但是,在某些情況下,我們必須手動調用flush()方法。舉個例子:

小明正在開發一款在線聊天軟件,當用戶輸入一句話后,就通過OutputStream的write()方法寫入網絡流。小明測試的時候發現,發送方輸入后,接收方根本收不到任何信息,怎么肥四?

原因就在于寫入網絡流是先寫入內存緩沖區,等緩沖區滿了才會一次性發送到網絡。如果緩沖區大小是4K,則發送方要敲幾千個字符后,操作系統才會把緩沖區的內容發送出去,這個時候,接收方會一次性收到大量消息。

解決辦法就是每輸入一句話后,立刻調用flush(),不管當前緩沖區是否已滿,強迫操作系統把緩沖區的內容立刻發送出去。

實際上,InputStream也有緩沖區。例如,從FileInputStream讀取一個字節時,操作系統往往會一次性讀取若干字節到緩沖區,并維護一個指針指向未讀的緩沖區。然后,每次我們調用int read()讀取下一個字節時,可以直接返回緩沖區的下一個字節,避免每次讀一個字節都導致IO操作。當緩沖區全部讀完后繼續調用read(),則會觸發操作系統的下一次讀取并再次填滿緩沖區。

案例2:一次性寫入若干字節

package day01;

import java.io.*;

/**

* 一次性寫入若干字節,通過void write(byte [])來實現

*/

class MainClass{

public static void main(String[] args) throws IOException {

OutputStream ops=new FileOutputStream("F:\\test\\outPut.txt");

ops.write("hello Krystal".getBytes("utf-8") );

ops.flush();

ops.close();

}

}

/*----------------------補充:------------------------------------------

String.getBytes(String decode)方法會根據指定的decode編碼返回某字符串在該編碼下的byte數組

*/

案例3:復制文件

package day01;

import java.io.*;

class MainClass{

public static void main(String[] args) throws IOException {

Stero st=new Stero();

st.fun1("F:\\test\\outPut.txt","F:\\test\\outPut2.txt");

//把outPut.txt復制為outPut2.txt

}

}

class Stero{

void fun1(String intputPath,String outputPath) throws IOException {

InputStream ips=new FileInputStream(intputPath);

OutputStream ops=new FileOutputStream(outputPath);

byte[]a=new byte[3];

int len;

while((len=ips.read(a)) != -1){

ops.write(a,0,len);

}

ops.close(); //先關閉輸出流

ips.close(); //后關閉輸入流

//最早開的最晚關

}

}

正確關閉流

上面的流的案例,存在一個潛在的問題,如果讀取或者寫入過程中,發生了IO錯誤,流就沒法及時關閉,資源也無法釋放。 Java7引入了新的try(resource)語法,只需要編寫try語句,就可讓編譯器自動為我們關閉資源。

案例:自動正確地關閉流

class Cable{

public static void main(String[] args) throws IOException{

//把新建流對象地語句放在try()里面即可

try(FileInputStream sf=new FileInputStream("F:\\test\\hello.txt")){

int n;

while((n=sf.read())!=-1){

System.out.println((char)n);

}

}

}

}

字符流

如果我們需要讀寫的是字符(不是圖片什么的),并且字符不全是單字節表示的ASCII字符,那么按照char來讀寫更方便,這種流稱為字符流。字符流傳輸的最小數據單位是char,Java提供了Reader和Writer兩個基類來操作字符流。

Reader和Writer本質上是一個能自動編解碼的InputStream和OutputStream。

使用Reader,數據源雖然是字節,但我們讀入的數據都是char類型的字符,原因是Reader內部把讀入的byte做了解碼,轉換成了char。使用InputStream,我們讀入的數據和原始二進制數據一模一樣,是byte[]數組,但是我們可以自己把二進制byte[]數組按照某種編碼轉換為字符串。究竟使用Reader還是InputStream,要取決于具體的使用場景。如果數據源不是文本,就只能使用InputStream,如果數據源是文本,使用Reader更方便一些。Writer和OutputStream是類似的。

Reader

Reader是Java的IO庫提供的另一個輸入流接口。和InputStream的區別是,InputStream是一個字節流,即以byte為單位讀取,而Reader是一個字符流,即以char為單位讀取,Reader是所有字符輸入流的父類。Reader類的主要方法是int read(),源代碼是:

public int read() throws IOException;

FileReader

FileReader是Reader的子類,FileReader的用法和FileInputStream的用法極其相似。

案例1:

//hello.txt的內容如下(注意編碼格式要為utf-8,要不然會出錯,另存為就可以改編碼格式)

武漢,加油。

China,add oil.

package day01;

import java.io.FileReader;

import java.io.IOException;

import java.io.Reader;

class RunClas{

public static void main(String[] args) {

Water w=new Water();

try {

w.fun1("F:\\test\\hello.txt");

} catch (IOException e) {

e.printStackTrace();

}

}

}

class Water{

public void fun1(String rPath) throws IOException {

try(Reader fr=new FileReader(rPath)){

char[] a=new char[4]; //創建用于緩沖的字符數組

int len;

while((len=fr.read(a))!=-1){

System.out.println(new String(a,0,len));

}

}

}

}

Writer

Reader是帶編碼轉換器的InputStream,它把byte轉換為char,而Writer就是帶編碼轉換器的OutputStream,它把char轉換為byte并輸出。

Writer是所有字符輸出流的超類,它提供的方法主要有:

寫入一個字符(0~65535):void write(int c);

寫入字符數組的所有字符:void write(char[] c);

寫入String表示的所有字符:void write(String s)。

FileWriter

FileWriter是Writer的一個子類。FileWriter的用法和FileOutputStream的用法很相似。

案例1:使用void write(String s)方法

package day01;

import java.io.*;

class RunClas {

public static void main(String[] args) {

Desk d=new Desk();

try {

d.funF("F:\\test\\FileWriterOutput.txt","Hello,krystal,i'm missing you.");

} catch (IOException e) {

e.printStackTrace();

}

}

}

class Desk {

public void funF(String oPath, String content) throws IOException {

try (Writer a = new FileWriter(oPath)) {

a.write(content);

a.flush();

a.close();

}

}

}

案例2:用字符流進行復制文件

package day01;

import java.io.*;

class RunClas {

public static void main(String[] args) throws IOException {

Desk d = new Desk();

d.funF("F:\\test\\hello.txt", "F:\\test\\hello3.txt");

}

}

class Desk {

public void funF(String iPath, String oPath) throws IOException {

Reader ra = new FileReader(iPath);

Writer wa = new FileWriter(oPath);

char[] charArr = new char[100];

int len;

while ((len = ra.read(charArr)) != -1) {

wa.write(charArr);

}

wa.flush();

wa.close();

}

}

流對文件的操作注意事項:

在寫入一個文件時,目錄下的同名文件會被覆蓋

在讀取一個文件時,必須保證改文件是存在的,否則報異常

緩沖流

為了提高 數據讀寫的速度,Java提供了帶緩沖功能的流類,在使用這些流類時,會創建一個內部緩沖區數組。(基于內存的)。

BufferedInputStream-->FileInputStream

BufferedOutputStream-->FileOutputStream

BufferedReader-->FileReader

BufferedWriter-->FileWriter

緩沖流先把數據緩沖到內存里,然后在內存中做io操作,基于內存的io操作比基于硬盤的操作快7500倍。

案例1:BufferedInputStream的使用

package day01;

import java.io.*;

class ExaF{

public static void main(String[] args) throws IOException {

//創建File流對象:

FileInputStream a=new FileInputStream("F:\\test\\hello.txt");

//創建緩沖流對象:

BufferedInputStream b=new BufferedInputStream(a); //需要傳入FIle流作為參數

byte[] bArr=new byte[100];

int len;

while((len=b.read(bArr))!=-1){

System.out.println(new String(bArr,0,len));

}

}

}

案例2:BufferedOutputStream的使用

package day01;

import java.io.*;

class ExaF{

public static void main(String[] args) throws IOException {

FileOutputStream a=new FileOutputStream("F:\\test\\BOutput.txt");

BufferedOutputStream b=new BufferedOutputStream(a);

b.write("I love you,krystal".getBytes());

b.flush();

b.close();

}

}

案例3:使用字節流+緩沖流實現文件復制

package day01;

import java.io.*;

class ExaF{

public static void main(String[] args) throws IOException {

//創建File流對象:

FileInputStream ia=new FileInputStream("F:\\test\\hello.txt");

FileOutputStream oa=new FileOutputStream("F:\\test\\Chello.txt");

//創建緩沖流對象:

BufferedInputStream ib=new BufferedInputStream(ia);

BufferedOutputStream ob=new BufferedOutputStream(oa);

byte[] bArr=new byte[100];

int len;

while((len=ib.read(bArr))!=-1){

ob.write(bArr);

}

ob.flush();

ob.close();

ib.close();

oa.close();

ia.close();

}

}

案例4:BufferedReader的使用

package day01;

import java.io.*;

class ExaB{

public static void main(String[] args) throws IOException {

FileReader a=new FileReader("F:\\test\\hello.txt");

BufferedReader b=new BufferedReader(a);

char []cArr=new char[100];

int len;

while((len=b.read(cArr))!=-1){

System.out.println(new String(cArr,0,len));

}

b.close();

a.close();

}

}

案例5:BufferedWriter的使用

package day01;

import java.io.*;

class ExaB{

public static void main(String[] args) throws IOException {

FileWriter a=new FileWriter("F:\\test\\brout.txt");

BufferedWriter b=new BufferedWriter(a);

b.write("Hello,krystal!");

b.flush();

b.close();

a.close();

}

}

案例6:使用字符流+緩沖流實現文件的復制

package day01;

import java.io.*;

class ExaB{

public static void main(String[] args) throws IOException {

BufferedReader br=new BufferedReader(new FileReader("F:\\test\\hello.txt"));

BufferedWriter bw=new BufferedWriter(new FileWriter("F:\\test\\em.txt"));

char [] cArr=new char[100];

int len;

while((len=br.read(cArr))!=-1){

bw.write(cArr);

}

bw.flush();

bw.close();

br.close();

}

}

轉換流

轉換流是指InputStreamReader和OutputStreamWriter,上面講了,流的數據都是字符時,轉成字符流更高效,那么轉換流就是用來將字節流轉換成字符流的,并且可以指定字符集的編碼解碼格式。

案例1:轉換字節輸入流為字符輸入流

//"F:\\test\\aa.txt"文件的編碼為GBK,文件內容如下:

中國我愛你。

I love you,China.

package day01;

import java.io.*;

class Bear{

public static void main(String[] args) throws IOException {

//創建文件字節輸入流對象

FileInputStream fis=new FileInputStream("F:\\test\\aa.txt");

//創建轉換流對象

InputStreamReader isr=new InputStreamReader(fis,"utf-8");//指定字符集編碼

char []cArr=new char[10];

int len;

while((len=isr.read(cArr))!=-1){

System.out.println(new String(cArr,0,len));

}

isr.close();

fis.close();

}

}

/*運行結果為:

��?��?

I love you

,China.

*/

/*出現了亂碼,是因為代碼中指定的字符集編碼與讀取的文件的數據的編碼格式不一致,

指定編碼的一行代碼改成:InputStreamReader isr=new InputStreamReader(fis,"GBK");即可避免亂碼*/

案例2:轉換字節輸出流為字符輸出流

package day01;

import java.io.*;

class Bear{

public static void main(String[] args) throws IOException {

FileOutputStream fos=new FileOutputStream("F:\\test\\ors.txt");

OutputStreamWriter osw=new OutputStreamWriter(fos,"utf-8");

osw.write("中國,我愛你");

osw.flush();

osw.close();

fos.close();

}

}

標準輸入輸出流

System.out和System.in是系統標準的輸入和輸出設備(鍵盤和顯示器)

System.in的類型是InputStream

System.out的類型是PrintStream。

案例1:創建一個接受鍵盤輸入的標準輸入流

package day01;

import java.io.*;

class Bear{

public static void main(String[] args) throws IOException {

RedPap rd=new RedPap();

rd.fun();

}

}

class RedPap{

public void fun() throws IOException {

//創建接受鍵盤輸入的輸入流

InputStreamReader isr=new InputStreamReader(System.in);

//把輸入流放到緩沖流里:

BufferedReader bfr=new BufferedReader(isr);

//創建臨時接受數據的字符串:

String str="";

while((str=bfr.readLine())!=null){ //readLine()是緩沖輸入字符流提供的按行讀取終端數據的方法,每一次調用會以字符串形式返回一行內容,讀取完會返回null

System.out.println(str);

}

}

}

//運行結果如下圖:

651d61bb0baebf415a1cc8a2efea906e.png

案例2:將控制臺的輸入內容輸出到文件krystal.txt中,控制臺出現”over“時結束輸出。

package day01;

import java.io.*;

class Bear{

public static void main(String[] args) throws IOException {

Krystal cf=new Krystal();

cf.fun("F:\\test\\Krystal.txt");

}

}

class Krystal{

public void fun(String kPath) throws IOException {

BufferedReader bfr=new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bfw=new BufferedWriter(new FileWriter(kPath));

String str="";

while((str=bfr.readLine())!=null){

if(str.equals("over")){

break;

}

bfw.write(str);

}

bfw.close();

bfr.close();

}

}

f34ab724c4f1b48f21919805e82d307b.png

序列化與反序列化

首先思考兩個問題:

1、如果想把一個類的實例化對象存到電腦的硬盤上,要怎么做?

硬盤存儲的基礎是二進制,需要把對象轉化為一個二進制的字節流,然后把流保存到硬盤上。如果要用存到硬盤里的對象,又得把流轉化為對象再使用。

2、如果想把一個對象通過網絡傳到另一臺機器上,要怎么做?

網絡通信的基礎也是二進制,需要把對象轉化為二進制的數據流,然后通過網絡傳輸流。接收者如果想要使用接收的對象得先把對象的流轉為對象。

因為上面兩類問題的存在,產生了對象的輸入與輸出流。

序列化(Serialize):序列化是指把一個Java對象變成二進制內容,本質上就是一個byte[]數組,用ObjectOutputStream類將一個對象寫入IO流中。

反序列化(Deserialize):用ObjectInputStream類從IO流中恢復對象。

注意事項:

序列化和反序列化針對的是實例化對象的各種屬性,不包括類的屬性。

一個Java對象要能序列化,必須實現一個特殊的java.io.Serializable接口

實現Serializable接口的類的對象的是可序列化的

Serializable接口沒有定義任何方法,它是一個空接口。

我們把這樣的空接口稱為“標記接口”(Marker Interface),實現了標記接口的類僅僅是給自身貼了個“標記”,并沒有增加任何方法。

案例1:

package day01;

import java.io.*;

class AbleObj implements Serializable {

String name;

int age;

String school;

double weigth;

}

class ObjOut{ //序列化類

public void funO(String oosPath) throws IOException {

ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(oosPath)); //定義對象輸出流

AbleObj ao=new AbleObj();

ao.name="krystal";

ao.age=20;

ao.school="SongSanHu";

oos.writeObject(ao);

oos.flush();

oos.close();

}

}

class ObjIn{ //反序列化類

public void funI(String oisPath) throws IOException, ClassNotFoundException {

ObjectInputStream ois =new ObjectInputStream(new FileInputStream(oisPath));

Object a=ois.readObject();

AbleObj b=(AbleObj)a; //強制轉換為AbleObj類型

/*對象的序列化和反序列化使用的類要嚴格一致,序列化是什么類反序列化就用什么類,

包名、類名、類結構等等所有都要一致。*/

System.out.println(b.name);

System.out.println(b.school);

ois.close()

}

}

public class Test01{ //運行類

public static void main(String[] args) throws IOException, ClassNotFoundException {

ObjOut tt=new ObjOut();

tt.funO("F:\\test\\KrystalInfo.txt");

ObjIn kk=new ObjIn();

kk.funI("F:\\test\\KrystalInfo.txt");

}

}

/*運行結果為:

krystal

SongSanHu

*/

安全性

因為Java的序列化機制可以導致一個實例能直接從byte[]數組創建,而不經過構造方法,因此,它存在一定的安全隱患。一個精心構造的byte[]數組被反序列化后可以執行特定的Java代碼,從而導致嚴重的安全漏洞。

實際上,Java本身提供的基于對象的序列化和反序列化機制既存在安全性問題,也存在兼容性問題。更好的序列化方法是通過JSON這樣的通用數據結構來實現,只輸出基本類型(包括String)的內容,而不存儲任何與代碼相關的信息。

隨機存取流

RandomAccessFile類支持"隨機訪問"的方式,即程序可以直接跳到文件的任意地方進行讀寫操作。RandomAccessFile對象包含一個記錄指針,用來標記當前讀寫開始位置,通過void seek(long pos)方法可以將記錄指針定位到pos位置。

案例1:隨機訪問文件(任意位置讀取)

//F:\\test\\AccessTest.txt文件的內容為:

123456789I love you,krystal. Where are you?

package day01;

import java.io.FileInputStream;

import java.io.RandomAccessFile;

public class Test01{

public static void main(String[] args) throws Exception {

RandomIn ii=new RandomIn();

ii.Rfi("F:\\test\\AccessTest.txt");

}

}

class RandomIn{

public void Rfi(String path1) throws Exception{

RandomAccessFile raf=new RandomAccessFile(path1,"rw");

/*參數2是mode模式:

"r":以只讀模式打開文件

"rw":打開以便讀取和寫入(常用)

"rwd":打開以便讀取和寫入,同步文件內容的更新

"rws":打開以便讀取和寫入,同步文件內容和元數據的更新

*/

raf.seek(5); //設置讀取文件內容的起點

byte [] bArr=new byte[100];

int len;

while((len=raf.read(bArr))!=-1){

System.out.println(new String(bArr,0,len));

}

raf.close();

}

}

/*運行結果為:

6789I love you,krystal. Where are you?

*/

案例2:隨機寫入

//F:\\test\\AccessTest.txt文件的內容為:

123456789I love you,krystal. Where are you?

package day01;

import java.io.IOException;

import java.io.RandomAccessFile;

public class Test01{

public static void main(String[] args) throws Exception {

RandomOut oo=new RandomOut();

oo.rof("F:\\test\\AccessTest.txt");

}

}

class RandomOut{

public void rof(String path2) throws IOException {

RandomAccessFile rdaf=new RandomAccessFile(path2,"rw");

rdaf.seek(0);

rdaf.write("Hi,this is Jimmy! ".getBytes());

rdaf.seek(rdaf.length()); //這個相當于給文件末尾追加內容

rdaf.write(" I miss you so much!".getBytes());

rdaf.close();

}

}

/*運行完成后,F:\\test\\AccessTest.txt文件的內容變化如下:

123456789I love you,krystal. Where are you?

Hi,this is Jimmy! u,krystal. Where are you? I miss you so much!

可以看到,在開頭或者中間寫入內容時,會覆蓋掉等長度的原內容。

*/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/534853.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/534853.shtml
英文地址,請注明出處:http://en.pswp.cn/news/534853.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

val_loss突然變很大_女朋友突然變得很冷淡是怎么回事?該怎么辦

原本和女朋友戀愛之后她一直都表現得比較比較熱情,但是最近這段時間她突然對自己冷淡起來,很多男生可能就會很疑惑:女朋友突然變得很冷淡是怎么回事?該怎么辦呢?一、女朋友突然變得很冷淡原因不管怎么說,女…

進程調度rr算法java實現_Java實現進程調度算法(二) RR(時間片輪轉)

一、概述因為這次os作業對用戶在控制臺的輸入輸出有要求,所以我花了挺多的代碼來完善控制臺的顯示。也因為我這次要實現多個類似算法,所以將一些共性單獨提取出來作為一個類。如果只想要和算法有關的核心代碼,看RR類的calc()即可。實現思路&a…

python全局變量global線程安全_對python多線程與global變量詳解

今天早上起來寫爬蟲,基本框架已經搭好,添加多線程爬取功能時,發現出錯:比如在下載文件的url列表中加入200個url,開啟50個線程。我的爬蟲…竟然將50個url爬取并全部命名為0.html,也就是說,最后的…

python123第五章_python 3.5學習筆記(第五章)

本章內容1、什么是模塊2、模塊的導入方法3、搜索路徑4、重要標準庫一、什么是模塊1、模塊本質上是一個以.py 結尾的python文件,包含了python對象定義和python語句。2、模塊是用來從邏輯上組織python代碼(定義變量、函數、類、邏輯等)以實現某種功能3、包&#xff1a…

string 長度_String源碼解析

本章源碼分析基于JDK1.7實現的接口String類被final修飾詞修飾,代表不可修改的特性,它實現了三個接口,Serializable是序列化接口,Compareble是排序接口,Char是字符序列接口。主要成員變量char[]:String通過c…

將你一張表的值覆蓋_山西聯通攜手華為完成長風商務區宏微協同,立體覆蓋,打造5G精品網絡...

近日,中國聯通山西分公司(以下簡稱“山西聯通”)在太原長風商務區繼5G CA超高速率升級之后,又針對長風商務區兩層活動區域進行了5G宏微協同的立體覆蓋,實現了該區域5G網絡的連續部署。長風商務區建筑結構設計新穎,占地面積3.06平方…

16速 java_不停歇的 Java 即將發布 JDK 16,新特性速覽!

之前在 JDK 15 中預覽的密封類和接口限制其余類和接口能夠擴展或實現它們。該計劃的目標包括,容許類或接口的做者控制負責實現它的代碼,提供比訪問修飾符更聲明性的方式來限制超類的使用,以及經過提供模式分析的基礎來支持模式匹配的將來方向…

局域網內文件傳輸速度_詳解蒲公英路由器組網 實現文件共享

蒲公英路由器,除了具備普通路由器的功能之外,如圖:最大的特色是可以實現智能組網:最大的特色是可以實現智能組網:采用全新自主研發的Cloud VPN技術替代傳統VPN,基于SD-WAN智能組網方案,快速組建…

java emoji顯示亂碼_Java 解決Emoji表情過濾問題

Emoji表情從三方數據中獲取沒有過濾,導致存入DB的時候報錯。原因:UTF-8編碼有可能是兩個、三個、四個字節。Emoji表情是4個字節,而Mysql的utf8編碼最多3個字節,所以數據插不進去。方法1.將已經建好的表也轉換成utf8mb42&#xff0…

mongotemplate中save拋出異常_異常處理的三個好習慣 | Python 工匠

文 | piglei 編輯 | EarlGrey推薦 | 編程派(微信ID:codingpy)前言如果你用 Python 編程,那么你就無法避開異常,因為異常在這門語言里無處不在。打個比方,當你在腳本執行時按 ctrlc 退出,解釋器就會產生一個 KeyboardI…

java 百度網盤上傳_使用pcs api往免費的百度網盤上傳下載文件的方法

百度個人云盤空間大,完全免費,而且提供了pcs api供調用操作文件,在平時的項目里往里面保存一些文件是很實用的。環境準備:開通讀寫網盤的權限及獲取access_token:http://blog.csdn.net/langyuezhang/article/details/47206621百度…

python縮進教學_Python縮進和選擇學習

縮進Python最具特色的是用縮進來標明成塊的代碼。我下面以if選擇結構來舉例。if后面跟隨條件,如果條件成立,則執行歸屬于if的一個代碼塊。先看C語言的表達方式(注意,這是C,不是Python!)if ( i > 0 ){ x 1; y 2;}如果i …

php如何新建xml文件,PHP中的生成XML文件的4種方法分享

生成如下XML串Xml代碼title1content12009-10-11title2content22009-11-11方法I.【直接生成字符串】使用純粹的PHP代碼生成字符串,并把這個字符串寫入一個以XML為后綴的文件。這是最原始的生成XML的方法,不過有效!$data_array array(array(ti…

組態王能直接讀取儀表數據嗎_液晶多功能網絡電力儀表PD800H

液晶多功能網絡電力儀表PD800H-H44三相三線多功用電力表面,一般也被稱作網絡電力表面,它是一種數字化的監控設備,其功用集成了電量測量,情況監控,遠程通訊為一體,作業原理上選用了現代核算機技術和數字信號…

python程序顯示自己的版權_手把手教你Pycharm皮膚主題及個性化設置,python程序員必備-Go語言中文社區...

1.設置IDE皮膚主題File -> Settings -> Appearance -> Theme -> 選擇“Alloy.IDEA Theme”根據自己的喜好設置字體大小,以及樣式。2.修改字體大小File -> Settings > Editor -> Colors & Fonts -> Font -> Size -> 設置為“14”3…

java多線程activemq,多線程JMS客戶端ActiveMQ

我正在使用以下代碼創建多個JMS會話,以供多個使用者使用消息。我的問題是代碼以單線程方式運行。即使消息存在于隊列中,第二個線程也無法接收任何內容,而是繼續輪詢。同時,第一個線程完成對第一批的處理,然后返回并使用…

python cnn 實例_基于CNN的紋理合成實踐【附python實現】

Q0: Preliminary knowledge of Texture SynthesisBaseline請見此處,下文所有的代碼修改均建立此代碼基礎之上。1. 紋理合成簡述?紋理合成(Texture Systhesis)技術主要應用于計算機圖形學等領域,被用于模擬幾何模型的表面細節、增強繪制模型的真實感。不…

php使用jasperreport,php-報表引擎指南(Pentaho,JasperReports,BIRT)

我在各種論壇和他們的網站上花費了大約4-5個小時,研究可以幫助我發展的報告工具.我是使用這種工具的新手,可以使用一些特定的指導.我正在開發一個Web應用程序,該應用程序將托管在一臺服務器上,但是多個用戶可以通過登錄進行訪問.每個用戶將擁有自己的帳戶,并且只能訪問僅與與其…

python中dlib庫_python 基于dlib庫的人臉檢測的實現

本周暫時比較清閑,可以保持每日一更的速度。國外身份證項目新增需求,檢測出身份證正面的人臉。最開始考慮mobilenet-ssd,經同事提醒,有現成的人臉庫dlib,那就用傳統方法嘗試一下。dlib安裝dlib的安裝小費一波周折&…

php養老院管理系統,XYCMS養老院建站系統 v3.8

XYCMS養老院建站系統是一個專為養老院而設計的養老院建筑系統。中心信息管理:包括基本信息管理,添加,問答中心信息管理新聞動態管理:管理新聞信息內容,管理相關分類,添加或者刪除生活環境內容管理&#xff…