Java IO

Java IO整理

參考文獻一http://www.cnblogs.com/lich/tag/java%20IO/
參考文獻二http://blog.sina.com.cn/s/blog_7ba28b6201011vv0.html
上圖

File類

實例一:創建一個新文件
import java.io.File;
import java.io.IOException;

public class Test1 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test.txt");//為增加可移植性,建議使用File.separator
        try {
            f.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
實例二:刪除一個指定文件
import java.io.File;

public class Test2 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test.txt");
        if(f.exists()){//判斷文件存不存在,如不存在就不用刪除了
            f.delete();
        }
    }
}
實例三:綜合創建,刪除文件的操作
import java.io.File;
import java.io.IOException;
//給定一個路徑,如果此文件存在,則刪除,如果不存在,則創建
public class Test3 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test.txt");
        if(f.exists()){
            f.delete();
        }else{
            try {
                f.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
實例四:創建一個文件夾
import java.io.File;
//使用mkdir()方法創建一個文件夾
public class Test4 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test");
        f.mkdir();//創建文件夾
    }
}
實例五:列出指定目錄的全部文件

如果現在給出了一個目錄,則可以直接列出目錄中的內容。但是列出的方法在File類中存在兩個:

  • 以字符串數組的形式返回:public String[] list()
  • 以File數組的形式返回:public File[] listFiles()
  • 以File數組的形式列出系統所有的根路徑,這是一個靜態方法:static File[] listRoots()
    操作一:使用list()列出全部內容
import java.io.File;

public class Test5 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator);
        String[] str=f.list();
        for(String s:str){
            System.out.println(s);
        }
    }
}

操作二:使用listFiles()列出

import java.io.File;

public class Test6 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator);
        File[] files=f.listFiles();
        for(File file:files){
            System.out.println(file);
        }
    }
}
實例六:判斷一個給定的路徑是否是目錄
import java.io.File;

public class Test7 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator);
        if(f.isDirectory()){
            System.out.println(f.getPath()+"是目錄");
        }else{
            System.out.println(f.getPath()+"不是目錄");
        }
    }
}
實例七:列出指定目錄的全部內容
import java.io.File;

public class Test8 {
    public static void main(String[] args) {
        File f = new File("d:" + File.separator);
        print(f);
    }
    public static void print(File f) {
        if (f != null) {
            if (f.isDirectory()) {
                File[] files = f.listFiles();
                if (files != null) {
                    for (File file : files) {
                            print(file);
                    }
                }
            } else {
                System.out.println(f);
            }
        }
    }
}

總結:

  • File類是在java.io包中唯一與文件本身有關的
  • 可以使用File類創建、刪除等常見的文件操作
  • 在使用File類指定路徑的時候一定要注意操作系統間的差異,盡量使用separator進行分割

RandomAccessFile類

之前的File類只是針對文件本身進行操作的,而如果相對文件內容進行操作,則可以使用RandomAccessFile類,此類屬于隨機讀取類,可以隨機的讀取一個文件中指定位置的數據。
因為在文件中,所有得內容都是按照字節存放的,都有固定的保存位置。

構造函數:
public RandomAccessFile(File file,String mode)throws FileNotFoundException
實例化此類的時候需要傳遞File類。告訴程序應該操作的是哪個文件,之后有個模式,文件的打開模式,常用的兩種模式:

  • r:讀
  • w:寫
  • rw:讀寫,如果使用此模式,如果文件不存在,則會自動創建

文件記錄指針

  • long getFilePointer():返回文件記錄指針的當前位置
  • void seek(long pos):將文件記錄指針定位到pos位置
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Test9 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        RandomAccessFile raf=new RandomAccessFile(f,"rw");//讀寫模式,如果該路徑不存在會自動創建
        String name1="jim";
        int age1 =20;
        String name2="Tom";
        int age2=30;
        raf.writeBytes(name1);
        raf.writeInt(age1);
        raf.writeBytes(name2);
        raf.writeInt(age2);
        raf.close();
    }
}
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Test10 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        RandomAccessFile raf=new RandomAccessFile(f,"r");//以讀模式打開
        raf.skipBytes(7);//跳過第一個人的信息
        byte[] bs=new byte[3];
        for(int i=0;i<bs.length;i++){
            bs[i]=raf.readByte();
        }
        String name2=new String(bs);
        int age2=raf.readInt();
        System.out.println(name2+"  "+age2);
        
        raf.seek(0);//指針回到文件開頭,讀取第二個人的信息
        for(int i=0;i<bs.length;i++){
            bs[i]=raf.readByte();
        }
        String name1=new String(bs);
        int age1=raf.readInt();
        System.out.println(name1+"  "+age1);
    }
}

字節流和字符流

先來看一下流的概念:
在程序中所有的數據都是以流的方式進行傳輸或保存的,程序需要數據的時候要使用輸入流讀取數據,而當程序需要將一些數據保存起來的時候,就要使用輸出流完成。

程序中的輸入輸出都是以流的形式保存的,流中保存的實際上全都是字節文件。

字節流與字符流

在java.io包中操作文件內容的主要有兩大類:字節流、字符流,兩類都分為輸入和輸出操作。在字節流中輸出數據主要是使用OutputStream完成,輸入使的是InputStream,在字符流中輸出主要是使用Writer類完成,輸入流主要使用Reader類完成。(這四個都是抽象類)

操作流程
在Java中IO操作也是有相應步驟的,以文件操作為例,主要的操作流程如下:

  • 使用File類打開一個文件
  • 通過字節流或字符流的子類,指定輸出的位置
  • 進行讀/寫操作
  • 關閉輸入/輸出

IO操作屬于資源操作,一定要記得關閉

字節流

字節流主要是操作byte類型數據,以byte數組為準,主要操作類就是OutputStream、InputStream

字節輸出流:OutputStream
OutputStream是整個IO包中字節輸出流的最大父類,此類的定義如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
從以上的定義可以發現,此類是一個抽象類,如果想要使用此類的話,則首先必須通過子類實例化對象,那么如果現在要操作的是一個文件,則可以使用:FileOutputStream類。通過向上轉型之后,可以為OutputStream實例化
Closeable表示可以關閉的操作,因為程序運行到最后肯定要關閉
Flushable:表示刷新,清空內存中的數據
FileOutputStream類的構造方法如下:
public FileOutputStream(File file)throws FileNotFoundException

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//寫數據
public class Test11 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        OutputStream out=new FileOutputStream(f);//如果文件不存在會自動創建
        String str="Hello World";
        byte[] b=str.getBytes();
        out.write(b);//因為是字節流,所以要轉化成字節數組進行輸出
        out.close();
    }
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//也可以一個字節一個字節進行輸出
public class Test11 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        OutputStream out=new FileOutputStream(f);//如果文件不存在會自動創建
        String str="Hello World";
        byte[] b=str.getBytes();
        for(int i=0;i<b.length;i++){
            out.write(b[i]);
        }
        out.close();
    }
}

public FileOutputStream(File file,boolean append)throws FileNotFoundException
在構造方法中,如果將append的值設置為true,則表示在文件的末尾追加內容。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Test11 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        OutputStream out=new FileOutputStream(f,true);//追加內容
        String str="\r\nHello World";
        byte[] b=str.getBytes();
        for(int i=0;i<b.length;i++){
            out.write(b[i]);
        }
        out.close();
    }
}
字節輸入流:InputStream

既然程序可以向文件中寫入內容,則就可以通過InputStream從文件中把內容讀取進來,首先來看InputStream類的定義:
public abstract class InputStream extends Object implements Closeable
與OutputStream類一樣,InputStream本身也是一個抽象類,必須依靠其子類,如果現在是從文件中讀取,就用FileInputStream來實現。
觀察FileInputStream類的構造方法:

public FileInputStream(File file)throws FileNotFoundException
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//讀文件
public class Test12 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        int len=in.read(b);
        in.close();
        System.out.println(new String(b,0,len));
    }

}

但以上方法是有問題的,用不用開辟這么大的一個字節數組,明顯是浪費嘛,我們可以根據文件的大小來定義字節數組的大小,File類中的方法:public long length()

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test13 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[(int) f.length()];
        in.read(b);
        in.close();
        System.out.println(new String(b));
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//我們換種方式,一個字節一個字節讀入
public class Test14 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[(int) f.length()];
        for(int i=0;i<b.length;i++){
            b[i]=(byte) in.read();
        }
        in.close();
        System.out.println(new String(b));
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//但以上情況只適合知道輸入文件的大小,不知道的話用如下方法:
public class Test15 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        InputStream in=new FileInputStream(f);
        byte[] b=new byte[1024];
        int temp=0;
        int len=0;
        while((temp=in.read())!=-1){//-1為文件讀完的標志
            b[len]=(byte) temp;
            len++;
        }
        in.close();
        System.out.println(new String(b,0,len));
    }
}
字符流

在程序中一個字符等于兩個字節,那么java提供了Reader、Writer兩個專門操作字符流的類。

字符輸出流:Writer

Writer本身是一個字符流的輸出類,此類的定義如下:
public abstract class Writer extends Object implements Appendable,Closeable,Flushable
此類本身也是一個抽象類,如果要使用此類,則肯定要使用其子類,此時如果是向文件中寫入內容,所以應該使用FileWriter的子類。
FileWriter類的構造方法定義如下:
public FileWriter(File file)throws IOException
字符流的操作比字節流操作好在一點,就是可以直接輸出字符串了,不用再像之前那樣進行轉換操作了。
寫文件:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Test16 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Writer out=new FileWriter(f);
        String str="Hello World";
        out.write(str);
        out.close();
    }
}
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//在默認情況下再次輸出會覆蓋,追加的方法也是在構造函數上加上追加標記
public class Test17 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Writer out=new FileWriter(f,true);//追加
        String str="\r\nHello World";
        out.write(str);
        out.close();
    }
}
字符輸入流:Reader

Reader是使用字符的方式從文件中取出數據,Reader類的定義如下:
public abstract class Reader extends Objects implements Readable,Closeable
Reader本身也是抽象類,如果現在要從文件中讀取內容,則可以直接使用FileReader子類。
FileReader的構造方法定義如下:
public FileReader(File file)throws FileNotFoundException
以字符數組的形式讀取出數據:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Test18 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Reader input=new FileReader(f);
        char[] c=new char[1024];
        int len=input.read(c);
        input.close();
        System.out.println(new String(c,0,len));
    }
}
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
//也可以用循環方式,判斷是否讀到底
public class Test19 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Reader input=new FileReader(f);
        char[] c=new char[1024];
        int temp=0;
        int len=0;
        while((temp=input.read())!=-1){
            c[len]=(char) temp;
            len++;
        }
        input.close();
        System.out.println(new String(c,0,len));
    }
}

字節流與字符流的區別
字節流和字符流使用是非常相似的,那么除了操作代碼的不同之外,還有哪些不同呢?
字節流在操作的時候本身是不會用到緩沖區(內存)的,是與文件本身直接操作的,而字符流在操作的時候是使用到緩沖區的
字節流在操作文件時,即使不關閉資源(close方法),文件也能輸出,但是如果字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩沖區,并且可以使用flush方法強制進行刷新緩沖區,這時才能在不close的情況下輸出內容

那開發中究竟用字節流好還是用字符流好呢?
在所有的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是只有在內存中才會形成的,所以使用字節的操作是最多的。

如果要java程序實現一個拷貝功能,應該選用字節流進行操作(可能拷貝的是圖片),并且采用邊讀邊寫的方式(節省內存)。

字符-字節轉換流

OutputStreamWriter和InputStreamReader
在整個IO包中,實際上就是分為字節流和字符流,但是除了這兩個流之外,還存在了一組字節流-字符流的轉換類。
OutputStreamWriter:是Writer的子類,將輸出的字符流變為字節流,即:將一個字符流的輸出對象變成字節流的輸出對象。
InputStreamReader:是Reader的子類,將輸入的字節流變為字符流,即:將一個字節流的輸入對象變成字符流的輸入對象。
一般在操作輸入輸出內容就需要使用字節或字符流,但是有些時候需要將字符流變成字節流的形式,或者將字節流變為字符流的形式,所以,就需要另外一組轉換流的操作類。

看一下OutputStreamWriter的構造方法:
public OutputStreamWriter(OutputStream out)

例如,將字節的文件輸出流,以字符的形式輸出

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class Test20 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Writer out=new OutputStreamWriter(new FileOutputStream(f));
        out.write("Hello World!!!");
        out.close();
    }
}

讀得時候也可以用字符流形式讀取字節流的對象

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

public class Test21 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        Reader input=new InputStreamReader(new FileInputStream(f));
        char[] c=new char[1024];
        int len=input.read(c);
        input.close();
        System.out.println(new String(c,0,len));
    }
}

以上操作只是以文件操作為例,OutputStreamWriter中接受的類型是OutputStream,只要是字節輸出流都可以以使用字符的形式操作,InputStreamReader一樣。

FileWriter和FileReader的說明
從JDK文檔中可以知道FileOutputStream是OutputStream的直接子類。FileInputStream也是InputStream的直接子類,但是在字符流文件的兩個操作類卻有一些特殊,FileWriter并不直接是Writer的子類,而是OutputStreamWriter的子類,而FileReader也不直接是Reader的子類,而是InputStreamReader的子類,那么從這兩個類的繼承關系就可以清楚的發現,不管是使用字節流還是字符流實際上最終都是以字節的形式操作輸入輸出流的。也就是說,傳輸或者從文件中讀取數據的時候,文件里真正保存的數據永遠是字節。

內存操作流

ByteArrayInputStream和ByteArrayOutputStream

之前所講解的程序中,輸出和輸入都是從文件中來得,當然,也可以將輸出的位置設置在內存之上,此時就要使用ByteArrayInputStream、ByteArrayOutputStream來完成輸入輸出功能了
ByteArrayInputStream的主要功能將內容輸入到內存之中
ByteArrayOutputStream的主要功能是將內存中的數據輸出
此時應該把內存作為操作點

ByteArrayInputStream類的定義:
public class ByteArrayInputStream extends InputStream
構造方法:
public ByteArrayInputStream(byte[] buf)
接受一個byte數組,實際上內存的輸入就是在構造方法上將數據傳入到內存中。
ByteArrayOutputStream:輸出就是從內存中寫出數據
public void write(int b)

以下是以內存操作流完成的一個大小寫字母轉換的程序:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class Test22 {
    public static void main(String[] args) throws IOException {
        String str="HELLO WORlD!!!";
        InputStream input=new ByteArrayInputStream(str.getBytes());
        OutputStream output=new ByteArrayOutputStream();
        int temp=0;
        while((temp=input.read())!=-1){
            output.write(Character.toLowerCase(temp));
        }
        input.close();
        output.close();
        System.out.println(output.toString());
    }
}

管道流

管道流(線程通信流)
管道流的主要作用是可以進行兩個線程間的通訊,分為管道輸出流(PipedOutputStream)、管道輸入流(PipedInputStream),如果想要進行管道輸出,則必須要把輸出流連在輸入流之上,在PipedOutputStream類上有如下的一個方法用于連接管道:
public void connect(PipedInputStream snk)throws IOException

例子:線程之間用管道流進行通訊

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

class Send implements Runnable{

    private PipedOutputStream pos;//管道輸出流
    public Send(){
        pos=new PipedOutputStream();
    }
    @Override
    public void run() {
        String str="Hello World!";
        try {
            pos.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            pos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public PipedOutputStream getPos() {
        return pos;
    }
}

class Receive implements Runnable{

    private PipedInputStream pis;//管道輸入流
    public Receive(){
        pis=new PipedInputStream();
    }
    @Override
    public void run() {
        byte[] b=new byte[1024];
        int len=0;
        try {
            len=pis.read(b);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            pis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(new String(b,0,len));
    }
    public PipedInputStream getPis() {
        return pis;
    }
}

public class Test23 {
    public static void main(String[] args) {
        Send send=new Send();
        Receive receive=new Receive();
        try {
            send.getPos().connect(receive.getPis());//連接管道
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(send).start();//啟動線程
        new Thread(receive).start();//啟動線程
    }
}

打印流

在整個IO包中,打印流是輸出信息最方便的類,主要包含字節打印流(PrintStream)和字符打印流(PrintWrite)。打印流提供了非常方便的打印功能,可以打印任何的數據類型,例如:小數、整數、字符串等等。

看一下PrintStream的構造方法:
public PrintStream(OutputStream out)
在PrintStream中定義的構造方法中可以清楚的發現有一個構造方法可以直接接收OutputStream類的實例,這是因為與OutputStream相比起來,PrintStream可以更加方便的輸出數據,這就好比將OutputStream類重新包裝了一下,使之輸出更加方便。

使用PrintStream輸出信息

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class Test24 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        PrintStream output=new PrintStream(new FileOutputStream(f));
        output.println("Hello World!");
        output.print("1+1="+2);
        output.close();
    }
}

也就是說此時,實際上是將FileOutputStream類的功能包裝了一下,這樣的設計在java中稱為裝飾設計。

類似c語言的printf:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class Test25 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        PrintStream output=new PrintStream(new FileOutputStream(f));
        String name="Jim";
        int age=20;
        float score=90.5f;
        char sex='M';
        output.printf("姓名:%s 年齡:%d 成績:%f 性別:%c", name,age,score,sex);
        output.close();
    }
}

System對IO的支持

System表示系統類,此類也對IO給予了一定的支持。
public static final PrintStream out 對應系統標準輸出,一般是顯示器
public static final PrintStream err 錯誤信息輸出
public static final InputStream in 對應著標準輸入,一般是鍵盤

又是由于歷史遺留問題 全局變量沒有大寫~

System.out

使用System.out輸出的時候就是將輸出的位置定義在了顯示器之中。
FileOutputStream是定位在文件里,而System.out是定位在屏幕上。
使用OutputStream完成屏幕上輸出(PrintStream是OutputStream的子類)

import java.io.IOException; 
import java.io.OutputStream; 
public class Test26 { 
            public static void main(String[] args) throws IOException { 
     
          OutputStream out=System.out;
          out.write("Hello World!".getBytes()); 
          out.close();  
       }
}
System.err

System.err表示的錯誤的標準輸出,如果程序中出現了錯誤的話,則直接使用System.err進行打印輸出即可。

public class Test27 {
    public static void main(String[] args) {
        String str="Hello World";
        try{
        int a=Integer.parseInt(str);
        }catch(Exception e){
            System.err.println(e);
        }
    }
}
System.out與System.err的區別
  • System.out和System.err都是PrintStream的實例化對象,而且通過實例代碼可以發現,兩者都可以輸出錯誤信息,但是一般來講System.out是將信息顯示給用戶看,是正常的信息顯示,而System.err的信息正好相反是不希望用戶看到,會直接在后臺打印,是專門顯示錯誤的
  • 一般來講,如果要想輸出錯誤信息的時候最好不要使用System.out而是直接使用System.err,這一點只能從其概念上劃分。
System.in

System.in實際上是一個鍵盤的輸入流,其本身是InputStream類型的對象。那么,此時就可以利用此方式完成從鍵盤讀取數據的功能。

InputStream對應的是輸入流,輸入流的話肯定可以從指定位置上讀取,之前使用的是FileInputStream是從文件中讀取的

import java.io.IOException;
import java.io.InputStream;

public class Test28 {
    public static void main(String[] args) throws IOException {
        InputStream in=System.in;
        byte[] b=new byte[1024];
        int len=in.read(b);
        System.out.println(new String(b,0,len));
    }
}

如果不使用byte數組指定長度呢:

import java.io.IOException;
import java.io.InputStream;

public class Test29 {
    public static void main(String[] args) throws IOException {
        InputStream in=System.in;
        StringBuilder buf=new StringBuilder();
        int temp=0;
        while((temp=in.read())!=-1){
            char c=(char) temp;
            if(c=='\n')break;
            buf.append(c);
        }
        in.close();
        System.out.println(buf.toString());
    }
}

但以上代碼還是有很大問題的,輸入中文的話~,所以最好的方法還是一次性把數據都放在內存了,再一次性全部拿出來,要實現這個功能的話,要用到BufferedReader類

輸入輸出重定向

System.out、System.err、System.in都有重定向功能,分別是setOut、setErr、setIn方法
System.out重定向

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;

public class Test30 {
    public static void main(String[] args) throws FileNotFoundException {
        File f = new File("d:" + File.separator+"test.txt");
        System.setOut(new PrintStream(f));
        String str="This is a test!";
        System.out.println(str);
    }
}

****System.err重定向****

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

public class Test31 {
    public static void main(String[] args) {
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        System.setErr(new PrintStream(out));
        System.err.println("Test---------------");
        System.out.println(out.toString());
    }
}

一般不建議修改err的重定向,因為這些信息都不太希望用戶看到
System.in重定向

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test32 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:" + File.separator+"test.txt");
        System.setIn(new FileInputStream(f));
        InputStream in=System.in;
        byte[] b=new byte[1024];
        int len=in.read(b);
        in.close();
        System.out.println(new String(b,0,len));
    }
}

BufferReader和Scanner

如果想要接收任意長度的數據,而且避免亂碼產生,就可以使用BufferedReader
public class BufferedReader extends Reader
因為輸入的數據有可能出現中文,所以,此處使用字符流完成。BufferedReader是從緩沖區之中讀取內容,所有的輸入的字節數據都將放在緩沖區之中。
System.in本身表示的是InputStream(字節流),現在要求接收的是一個字符流,需要將字節流變成字符流才可以,所以要用InputStreamReader

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test33 {
    public static void main(String[] args) throws IOException {
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        String str=reader.readLine();
        System.out.println(str);
    }
}

在JDK1.5之后Java提供了專門的輸入數據類,此類可以完成BufferedReader類的功能,也可以方便的對輸入數據進行驗證,此類存放在java.util包中
使用Scanner接收鍵盤的輸入數據:

import java.util.Scanner;

public class Test34 {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        String str=s.next();
        System.out.println(str);
    }
}

比直接使用BufferedReader更加方便,但是這個程序是有問題的,如果輸入的字符串中存在空格,那么就會截止,如果我們要接收空格的下,將分隔符變成“\n”。

import java.util.Scanner;

public class Test34 {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        s.useDelimiter("\n");//使用分隔符
        String str=s.next();
        System.out.println(str);
    }
}

對象序列化和反序列化

所謂的對象序列化就是將一個對象轉換為二進制流,如果一個類的對象要想實現序列化,則該對象所在的類必須實現Serializable接口,在此接口中沒有任何的方法,此接口只是作為一個標識,表示本類的對象具備了序列化的能力。

序列化的思想是“凍結”對象狀態,傳輸對象狀態(寫到磁盤、通過網絡傳輸等等),然后“解凍”狀態,重新獲得可用的Java對象,所有這些事情的發生有點像魔術,這要歸功于ObjectInputStream/ObjectOutputStream類,完全保真的元數據以及程序員愿意用Serializable標識接口標記他們的類,從而“參與”這個過程。

序列化分為兩大部分:
序列化和反序列化。序列化是這個過程的第一部分,將數據分解成字節流,以便存儲在文件中或在網絡上傳輸。反序列化就是打開字節流并重構對象。對象序列化不僅要將基本數據類型轉換成字節表示,有時還要恢復數據?;謴蛿祿笥谢謴蛿祿膶ο髮嵗?,如果某個類能夠被序列化,其子類也可以被序列化。聲明為static和transient類型的成員數據不能被序列化。因此static代表類的狀態,transient代表對象的臨時數據。
對象序列化在一下場景使用比較合適:

  • 當你想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;
  • 當你想用套接字在網絡上傳送對象的時候;
  • 當你想通過RMI(Remote Method Invocation 遠程方法調用)傳輸對象的時候;

如果要想實現對象的序列化,則還要依靠ObjectOutputStream類和ObjectInputStream類,前者屬于序列化操作,而或者屬于反序列化操作。

public class Person implements Serializable {   
    private String name;   
    private int age;   
  
    public Person(String name, int age) {   
        super();   
        this.name = name;   
        this.age = age;   
    }   
  
    public String toString() {   
        return "姓名:" + this.name + ",年齡:" + this.age;   
    }   
  
    public int getAge() {   
        return age;   
    }   
  
    public void setAge(int age) {   
        this.age = age;   
    }   
  
    public String getName() {   
        return name;   
    }   
  
    public void setName(String name) {   
        this.name = name;   
    }   
  
}  

下面通過ObjectOutputStream完成序列化操作:

public class ObjectOutputStreamDemo {   
    public static void main(String args[]) throws Exception {   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectOutputStream oos = null;   
        oos = new ObjectOutputStream(new FileOutputStream(file));   
        Person per = new Person("王旭東", 21);   
        oos.writeObject(per);   
        oos.close();   
    }   
  
}  

對象被實例化之后,就可以通過ObjectInputStream進行反序列化的操作

public class ObjectInputStreamDemo {   
    public static void main(String args[]) throws Exception {   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectInputStream ois = null;   
        ois = new ObjectInputStream(new FileInputStream(file));   
        Object obj = ois.readObject();   
        Person per = (Person) obj;   
        System.out.println(per);   
    }   
  
}  

以上操作實際上是整個對象進行的序列化操作,如果現在假設類中的某個屬性不希望被序列化的話,則使用transient關鍵字進行聲明;

private transient String name;  

由上面可知可以對一個對象序列化,那么因為Object可以接受任意的引用數據類型,所以也可以同時對多個對象一起進行序列化操作,包括數組;

public class SerializableDemo {   
    public static void main(String args[]) throws Exception {   
        Person per[] = { new Person("張三", 30), new Person("李四", 40),new Person("王五", 50) };   
        serializable(per);   
        Person p[] = (Person[]) delSerializable();   
        print(p);   
    }   
    public static void serializable(Object obj) throws Exception {   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectOutputStream oos = null;   
        oos = new ObjectOutputStream(new FileOutputStream(file));   
        oos.writeObject(obj);   
        oos.close();   
    }   
    public static Object delSerializable() throws Exception {   
        Object temp = null;   
        File file = new File("d:" + File.separator + "demo.txt");   
        ObjectInputStream ois = null;   
        ois = new ObjectInputStream(new FileInputStream(file));   
        temp = ois.readObject();   
        return temp;   
    }   
    public static void print(Person per[]) {   
        for (Person p : per) {   
            System.out.println(p);   
        }   
    }   
  
}  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容

  • tags:io categories:總結 date: 2017-03-28 22:49:50 不僅僅在JAVA領...
    行徑行閱讀 2,196評論 0 3
  • 標準輸入輸出,文件的操作,網絡上的數據流,字符串流,對象流,zip文件流等等,java中將輸入輸出抽象稱為流,就好...
    navy_legend閱讀 726評論 0 0
  • 本文對 Java 中的 IO 流的概念和操作進行了梳理總結,并給出了對中文亂碼問題的解決方法。 1. 什么是流 J...
    Skye_kh閱讀 783評論 0 2
  • 學習Java中的IO,首先要理解Java中IO的流模型。所謂流,可以假想成河流,流的數據源,就是河流的發源地,流是...
    GhostStories閱讀 468評論 0 5
  • 曾經以為回家是一張車票的距離,當我由原來一年的三四次回家變成兩次一次,甚至零次時,才發現原來回家的路最艱難。 1、...
    我不是蝸牛閱讀 375評論 1 1