天天看點

java輸出流_Java輸入輸出流

IO流

IO流用來處理裝置之間的資料傳輸,傳輸是通過流的方式

Java用于操作流的對象都在java.io包中

流就是指一連串流動的字元,以先進先出的方式發送資訊的通道。

流的方式

按照流的方向劃分

輸入流:将外部資料源的資料轉換成流,程式通過讀取流中的資料,完成對資料源讀取的通路

輸出流:将流中的資料轉換到對應的資料源中,程式通過向流中寫入資料,完成對資料源寫入

按照類型劃分

位元組流:以位元組為機關(8位),可以通路所有檔案

字元流:以字元為機關(16位Unicode),隻能通路文本檔案

輸出流

比如我們經常使用的 System.out.println("cocci"); 就是将字元串輸出到控制台中,或者說輸出到螢幕中,這裡的螢幕就是輸出裝置,由程式将cocci通過流輸出到目的地。

java輸出流_Java輸入輸出流

輸出裝置除了螢幕,還有列印機、檔案等。

輸入流

比如使用鍵盤接收資料 Scanner sc = new Scanner(System.in); 這裡的System.in就是輸入流,程式從資料源這裡指鍵盤去讀取資料通過流輸入到程式當中。

java輸出流_Java輸入輸出流

輸入裝置除了鍵盤,還有掃描器、檔案等。

File類

檔案和目錄路徑名的抽象表示形式,表示磁盤上的檔案或目錄

檔案:可認為是相關記錄或放在一起的資料的集合

構造方法

java輸出流_Java輸入輸出流

示例:以下三種方式等價,各有不同的使用場景

//Windows中路徑分隔可使用/或者\\

File file1 = new File("d:\\java\\a.txt");

File file2 = new File("d:\\java","a.txt");

File file3 = new File(new File("d:\\"),"java\\a.txt");

常用方法

java輸出流_Java輸入輸出流

注意事項

delete()方法在删除目錄時如果其内有内容則無法删除,需要先清空目錄下的内容,再删除目錄本身

isDirectory()和isFile()方法在判斷是否為檔案或者目錄時,如果檔案或目錄不存在則傳回false

createNewFile()方法在建立檔案時,如果檔案所在的目錄不存在則建立失敗并抛出異常

String[] list()和 File[] listFiles() 都是傳回對象包含的所有的檔案和目錄,傳回類型不同

檔案與目錄的相關操作

public static void main(String[] args) {

File file=new File("d:\\test\\java");

if(file.exists()){

System.out.println("目錄存在,删除目錄");

file.delete(); //隻會删除一級目錄,即java

}else{

boolean b=file.mkdirs(); //建立多級目錄

System.out.println("建立檔案目錄結果:" + b);

}

File file2=new File("d:\\test\\a.txt");

if(file2.exists()){

System.out.println("檔案存在,删除檔案");

file2.delete();

}else{

try {

file2.createNewFile(); //建立檔案

} catch (IOException e) {

e.printStackTrace();

}

System.out.println("建立檔案");

}

//重命名,把a.txt重命名為b.txt

//file2.renameTo(new File("d:\\test\\b.txt"));

//把b.txt剪切到java目錄下并重命名為c.txt

file2.renameTo(new File("d:\\test\\java\\c.txt"));

}

擷取File對象的所有子檔案和目錄

public class TestFile {

public static void main(String[] args) {

//擷取磁盤的所有根目錄

File[] files =File.listRoots();

for(int i=0;i

System.out.println(files[i].getPath());

//輸出的是 C:\ D:\

}

TestFile tf = new TestFile();

//列印Silly目錄下的所有子目錄和檔案

File file=new File("d:\\Silly");

tf.printFile(file,"");

}

public void printFile(File file,String str){

System.out.println(str + file.getName());

if(file.isDirectory()){

File[] files=file.listFiles();

for(int i=0;i

//遞歸調用

printFile(files[i], str+"\t");

}

}

}

}

位元組流

位元組輸入流

InputStream,此抽象類是表示位元組輸入流的所有類的超類,其主要子類如下

java輸出流_Java輸入輸出流

位元組輸出流

OutputStream,此抽象類是位元組輸出流的所有類的超類,其主要子類如下

java輸出流_Java輸入輸出流

過濾器輸入輸出流

FileInputStream

從檔案系統中的某個檔案中獲得輸入位元組

用于讀取諸如圖像資料之類的原始位元組流

構造方法

java輸出流_Java輸入輸出流

主要方法

read方法不帶參數的傳回值為讀取的單個位元組值,帶參數的傳回值表示讀取的位元組長度。如果傳回值為-1,則表示已經達到檔案末尾!

java輸出流_Java輸入輸出流

FileOutputStream

構造方法

java輸出流_Java輸入輸出流

主要方法

java輸出流_Java輸入輸出流

示範Demo

public class IOTest {

public static void main(String[] args) {

OutputStream fos = null;

InputStream fis = null;

try {

fos=new FileOutputStream("d:\\silly.txt");

String str="最好的我們隔了一整個青春";

byte[] words=str.getBytes(); //把字元串編碼成位元組序列

//寫入操作

fos.write(words, 0, words.length);

System.out.println("寫入成功!");

fis = new FileInputStream("d:\\silly.txt");

StringBuilder sb = new StringBuilder();

byte[] buf = new byte[1024]; //位元組數組緩存資料

int n = 0; //記錄讀取的位元組長度

//循環讀取資料

while((n = fis.read(buf)) != -1){

//這裡使用三個參數的構造方法,因為最後一次讀取的長度可能達不到buf數組的長度

//是以根據實際讀取的長度n去構造對象更合理

sb.append(new String(buf, 0, n));

buf = new byte[1024]; //重新初始化,避免資料重複

}

System.out.println(sb.toString());

} catch (IOException e) {

e.printStackTrace();

}finally{

try {

//釋放資源

if(fos != null) fos.close();

if(fis != null) fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

檔案複制

public static void main(String[] args) {

//将d盤的圖檔複制到桌面

InputStream is = null;

OutputStream os = null;

try {

//執行個體化輸入輸出流對象

is = new FileInputStream("d:\\girl.jpg");

os = new FileOutputStream("C:\\Users\\ruoxiyuan\\Desktop\\mm.jpg");

//定義一個2048位元組的緩存

byte[] buffer=new byte[2048];

int len= 0; //讀取的位元組長度

while((len = is.read(buffer)) != -1){

//最後一次讀取的長度len不一定能達到buffer數組的長度,也就是空間有可能富餘

//如果直接使用write(buffer)方法可能導緻寫入更多的位元組,新檔案會稍大

os.write(buffer, 0, len);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally{

try {

//釋放資源

if(is != null) is.close();

if(os != null) os.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

字元流

字元輸入流

Reader,此抽象類是表示字元輸入流的所有類的超類,其主要子類如下

java輸出流_Java輸入輸出流

字元輸出流

Writer,此抽象類是表示字元輸出流的所有類的超類,其主要子類如下

java輸出流_Java輸入輸出流

位元組字元轉換流

InputStreamReader:是位元組流通向字元流的橋梁,它使用指定的 charset 讀取位元組并将其解碼為字元。

OutputStreamWriter:是字元流通向位元組流的橋梁,它使用指定的 charset 将寫入其中的字元編碼成位元組。

其使用的字元集可以由構造方法指定,或者使用平台預設的字元集。

FileReader

用來讀取字元檔案的便捷類,使用預設字元集進行編碼,InputStreamReader的子類

構造方法

java輸出流_Java輸入輸出流

常用方法

java輸出流_Java輸入輸出流

FileWriter

用來寫入字元檔案的便捷類,使用預設字元集進行編碼,OutputStreamWriter的子類

構造方法

如果使用new FileWriter(file),已有檔案内容此時會被清空,設定第二個參數為true表示追加内容

java輸出流_Java輸入輸出流

常用方法

java輸出流_Java輸入輸出流

示範Demo

public class IOTest {

public static void main(String[] args) {

try {

FileWriter writer = new FileWriter("d:\\silly.txt");

String str = "成功的人隻會去做他們該做的事情,隻會面對他們的困難,不會有抱怨,"

+ "更不會有羨慕,因為他們心中有目标,理想,動力以及那顆沉澱的心";

writer.write(str);

writer.flush(); //重新整理緩沖區

FileReader reader = new FileReader("d:\\silly.txt");

char[] buffer = new char[1024];//定義緩沖區

int len = 0;

while((len = reader.read(buffer)) != -1){

String res = new String(buffer, 0, len);

System.out.println(res);

}

writer.close();

reader.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

緩沖流

使用緩沖流可以提高讀寫速度,注意緩沖流在調用write方法寫入資料時,是寫入的緩沖區,如果緩沖區滿了自動執行寫操作,緩沖區不滿則需要執行flush方法強制寫入到輸出裝置,調用close方法也會強制寫入

位元組緩沖流

緩沖輸入流BufferedInputStream,緩沖輸出BufferedOutputStream

隻是對位元組流進行了包裝,使用方式和位元組流基本一緻

構造方法:

public BufferedInputStream(InputStream in)

public BufferedOutputStream(OutputStream out)

字元緩沖流

緩沖輸入流BufferedReader

構造方法:public BufferedReader(Reader in)

特殊方法:String readLine() 讀取一個文本行

緩沖輸出流BufferedWriter

構造方法:public BufferedWriter(Writer out)

特殊方法:void newLine() 寫入一個行分隔符

示範Demo

public class IOTest {

public static void main(String[] args) {

try {

FileWriter writer = new FileWriter("d:\\silly.txt");

BufferedWriter bw = new BufferedWriter(writer);

bw.write("書山有路勤為徑");

bw.newLine(); //寫入換行符(根據平台寫入對應的換行符)

bw.write("學海無涯苦作舟");

bw.newLine();

//windows下使用\r\n也能換行

bw.write("世間安得兩全法" + "\r\n");

bw.write("不負如來不負卿");

bw.flush(); //必須重新整理緩沖區

String record = null; //存儲檔案的内容

int count = 0; //記錄行數

FileReader reader = new FileReader("d:\\silly.txt");

BufferedReader br = new BufferedReader(reader);

//每次讀取一整行資料,傳回值為空時說明讀取到檔案末尾

while((record = br.readLine()) != null){

count++;

System.out.println("目前行數"+count+":"+record);

}

bw.close();

br.close();

writer.close();

reader.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

對象序列化與反序列化

序列化:把Java對象轉換為位元組序列的過程

反序列化:把位元組序列恢複為Java對象的過程

隻有實作了Serializable接口的類的對象才能被序列化

序列化用途

把對象的位元組序列永久儲存在硬碟上,通常放在一個檔案中

在網絡上傳送對象的位元組序列

相關類

對象輸入流類:ObjectInPutStream

對象輸出流類:ObjectOutPutStream

序列化步驟

建立一個對象輸出流:ObjectOutPutStream out = new ObjectOutPutStream(OutPutStream out);

調用方法對對象進行序列化 out.writeObject(Object obj); 把對象序列化,得到位元組序列寫入流中

重新整理緩沖并關閉流 out.flush(); out.close();

反序列化步驟

建立一個對象輸入流:ObjectInPutStream in = new ObjectInPutStream(InPutStream in);

調用方法 in.readObject(); 讀取字元序列,把參數反序列化成對象,傳回該對象

關閉流 in.close();

示範Demo

定義一個學生類實作Serializable接口

public class Student implements Serializable{

private String name;

private int age;

public Student(String name, int age) {

super();

this.name = name;

this.age = age;

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + "]";

}

}

實作對象序列化與反序列化

public class IOTest {

public void save(Student stu){

OutputStream os=null;

try {

os = new FileOutputStream("d:\\stu.dat");

ObjectOutputStream oos = new ObjectOutputStream(os);

oos.writeObject(stu);

//寫入其他類型資料

oos.writeBoolean(true);

oos.flush();

oos.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally{

if(os!=null){

try {

os.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

public Student read(){

InputStream is=null;

Student stu=null;

try {

is = new FileInputStream("d:\\stu.dat");

ObjectInputStream ois = new ObjectInputStream(is);

stu = (Student)ois.readObject();

//注意讀取順序要和寫入順序保持一緻

System.out.println(ois.readBoolean());

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}finally{

if(is!=null){

try {

is.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

return stu;

}

public static void main(String[] args) {

Student stu = new Student("小小", 18);

IOTest test = new IOTest();

test.save(stu);

Student res = test.read();

System.out.println(res);

//true

//Student [name=小小, age=18]

}

}

Serializable接口

實作該接口會按預設方式進行序列化和反序列化

預設方式序列化

這種序列化方式僅對非transient的執行個體變量進行序列化

不會序列化對象的transient的執行個體變量,也不會序列化靜态變量

預設方式反序列化

如果記憶體中對象所屬的類還沒有被加載,那麼會先加載并初始化這個類,如果classpath中不存在該類檔案,那麼抛出ClassNotFoundException;

在反序列化時不會調用類的任何構造方法

如果希望控制類的序列化方式添加如下方法

private void writeObject(ObjectOutputStream out) throws IOException

private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException

可序列化類添加該方法後進行可序列化操作會執行該方法,否則按預設方式執行。在以上方法中可以先調用預設的defaultWriteObject()和read方法

序列化說明

對于包含敏感資訊的對象,可以先加密後再序列化,反序列化時需要解密

預設序列化方式會序列化整個對象圖,需要遞歸周遊對象圖,如果對象圖複雜,遞歸周遊需要消耗大量空間和時間,圖内部資料結構為雙向清單

實際應用中,如果對某些成員變量改為transient類型,可以節省空間和時間,提高可序列化的性能