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