Java IO

Java IO整理

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

File類

實例一:創(chuàng)建一個新文件
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();
        }
    }
}
實例三:綜合創(chuàng)建,刪除文件的操作
import java.io.File;
import java.io.IOException;
//給定一個路徑,如果此文件存在,則刪除,如果不存在,則創(chuàng)建
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();
            }
        }
    }
}
實例四:創(chuàng)建一個文件夾
import java.io.File;
//使用mkdir()方法創(chuàng)建一個文件夾
public class Test4 {
    public static void main(String[] args) {
        File f=new File("d:"+File.separator+"test");
        f.mkdir();//創(chuàng)建文件夾
    }
}
實例五:列出指定目錄的全部文件

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

  • 以字符串數(shù)組的形式返回:public String[] list()
  • 以File數(shù)組的形式返回:public File[] listFiles()
  • 以File數(shù)組的形式列出系統(tǒng)所有的根路徑,這是一個靜態(tài)方法: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類創(chuàng)建、刪除等常見的文件操作
  • 在使用File類指定路徑的時候一定要注意操作系統(tǒng)間的差異,盡量使用separator進行分割

RandomAccessFile類

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

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

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

文件記錄指針

  • 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");//讀寫模式,如果該路徑不存在會自動創(chuàng)建
        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);
    }
}

字節(jié)流和字符流

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

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

字節(jié)流與字符流

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

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

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

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

字節(jié)流

字節(jié)流主要是操作byte類型數(shù)據(jù),以byte數(shù)組為準,主要操作類就是OutputStream、InputStream

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

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//寫數(shù)據(jù)
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);//如果文件不存在會自動創(chuàng)建
        String str="Hello World";
        byte[] b=str.getBytes();
        out.write(b);//因為是字節(jié)流,所以要轉化成字節(jié)數(shù)組進行輸出
        out.close();
    }
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//也可以一個字節(jié)一個字節(jié)進行輸出
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);//如果文件不存在會自動創(chuàng)建
        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();
    }
}
字節(jié)輸入流:InputStream

既然程序可以向文件中寫入內容,則就可以通過InputStream從文件中把內容讀取進來,首先來看InputStream類的定義:
public abstract class InputStream extends Object implements Closeable
與OutputStream類一樣,InputStream本身也是一個抽象類,必須依靠其子類,如果現(xiàn)在是從文件中讀取,就用FileInputStream來實現(xiàn)。
觀察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));
    }

}

但以上方法是有問題的,用不用開辟這么大的一個字節(jié)數(shù)組,明顯是浪費嘛,我們可以根據(jù)文件的大小來定義字節(jié)數(shù)組的大小,F(xiàn)ile類中的方法: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;
//我們換種方式,一個字節(jié)一個字節(jié)讀入
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));
    }
}
字符流

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

字符輸出流:Writer

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

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;
//在默認情況下再次輸出會覆蓋,追加的方法也是在構造函數(shù)上加上追加標記
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是使用字符的方式從文件中取出數(shù)據(jù),Reader類的定義如下:
public abstract class Reader extends Objects implements Readable,Closeable
Reader本身也是抽象類,如果現(xiàn)在要從文件中讀取內容,則可以直接使用FileReader子類。
FileReader的構造方法定義如下:
public FileReader(File file)throws FileNotFoundException
以字符數(shù)組的形式讀取出數(shù)據(jù):

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;
//也可以用循環(huán)方式,判斷是否讀到底
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));
    }
}

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

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

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

字符-字節(jié)轉換流

OutputStreamWriter和InputStreamReader
在整個IO包中,實際上就是分為字節(jié)流和字符流,但是除了這兩個流之外,還存在了一組字節(jié)流-字符流的轉換類。
OutputStreamWriter:是Writer的子類,將輸出的字符流變?yōu)樽止?jié)流,即:將一個字符流的輸出對象變成字節(jié)流的輸出對象。
InputStreamReader:是Reader的子類,將輸入的字節(jié)流變?yōu)樽址?,即:將一個字節(jié)流的輸入對象變成字符流的輸入對象。
一般在操作輸入輸出內容就需要使用字節(jié)或字符流,但是有些時候需要將字符流變成字節(jié)流的形式,或者將字節(jié)流變?yōu)樽址鞯男问剑?,就需要另外一組轉換流的操作類。

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

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

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();
    }
}

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

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,只要是字節(jié)輸出流都可以以使用字符的形式操作,InputStreamReader一樣。

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

內存操作流

ByteArrayInputStream和ByteArrayOutputStream

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

ByteArrayInputStream類的定義:
public class ByteArrayInputStream extends InputStream
構造方法:
public ByteArrayInputStream(byte[] buf)
接受一個byte數(shù)組,實際上內存的輸入就是在構造方法上將數(shù)據(jù)傳入到內存中。
ByteArrayOutputStream:輸出就是從內存中寫出數(shù)據(jù)
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包中,打印流是輸出信息最方便的類,主要包含字節(jié)打印流(PrintStream)和字符打印流(PrintWrite)。打印流提供了非常方便的打印功能,可以打印任何的數(shù)據(jù)類型,例如:小數(shù)、整數(shù)、字符串等等。

看一下PrintStream的構造方法:
public PrintStream(OutputStream out)
在PrintStream中定義的構造方法中可以清楚的發(fā)現(xiàn)有一個構造方法可以直接接收OutputStream類的實例,這是因為與OutputStream相比起來,PrintStream可以更加方便的輸出數(shù)據(jù),這就好比將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表示系統(tǒng)類,此類也對IO給予了一定的支持。
public static final PrintStream out 對應系統(tǒng)標準輸出,一般是顯示器
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表示的錯誤的標準輸出,如果程序中出現(xiàn)了錯誤的話,則直接使用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的區(qū)別
  • System.out和System.err都是PrintStream的實例化對象,而且通過實例代碼可以發(fā)現(xiàn),兩者都可以輸出錯誤信息,但是一般來講System.out是將信息顯示給用戶看,是正常的信息顯示,而System.err的信息正好相反是不希望用戶看到,會直接在后臺打印,是專門顯示錯誤的
  • 一般來講,如果要想輸出錯誤信息的時候最好不要使用System.out而是直接使用System.err,這一點只能從其概念上劃分。
System.in

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

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數(shù)組指定長度呢:

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());
    }
}

但以上代碼還是有很大問題的,輸入中文的話~,所以最好的方法還是一次性把數(shù)據(jù)都放在內存了,再一次性全部拿出來,要實現(xiàn)這個功能的話,要用到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

如果想要接收任意長度的數(shù)據(jù),而且避免亂碼產生,就可以使用BufferedReader
public class BufferedReader extends Reader
因為輸入的數(shù)據(jù)有可能出現(xiàn)中文,所以,此處使用字符流完成。BufferedReader是從緩沖區(qū)之中讀取內容,所有的輸入的字節(jié)數(shù)據(jù)都將放在緩沖區(qū)之中。
System.in本身表示的是InputStream(字節(jié)流),現(xiàn)在要求接收的是一個字符流,需要將字節(jié)流變成字符流才可以,所以要用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提供了專門的輸入數(shù)據(jù)類,此類可以完成BufferedReader類的功能,也可以方便的對輸入數(shù)據(jù)進行驗證,此類存放在java.util包中
使用Scanner接收鍵盤的輸入數(shù)據(jù):

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);
    }
}

對象序列化和反序列化

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

序列化的思想是“凍結”對象狀態(tài),傳輸對象狀態(tài)(寫到磁盤、通過網絡傳輸?shù)鹊龋缓蟆敖鈨觥睜顟B(tài),重新獲得可用的Java對象,所有這些事情的發(fā)生有點像魔術,這要歸功于ObjectInputStream/ObjectOutputStream類,完全保真的元數(shù)據(jù)以及程序員愿意用Serializable標識接口標記他們的類,從而“參與”這個過程。

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

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

如果要想實現(xiàn)對象的序列化,則還要依靠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);   
    }   
  
}  

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

private transient String name;  

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

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);   
        }   
    }   
  
}  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

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

友情鏈接更多精彩內容