Java IO整理
參考文獻(xiàn)一:http://www.cnblogs.com/lich/tag/java%20IO/
參考文獻(xiàn)二:http://blog.sina.com.cn/s/blog_7ba28b6201011vv0.html
上圖
File類
實(shí)例一:創(chuàng)建一個(gè)新文件
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();
}
}
}
實(shí)例二:刪除一個(gè)指定文件
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();
}
}
}
實(shí)例三:綜合創(chuàng)建,刪除文件的操作
import java.io.File;
import java.io.IOException;
//給定一個(gè)路徑胀溺,如果此文件存在膀藐,則刪除罪既,如果不存在凝果,則創(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();
}
}
}
}
實(shí)例四:創(chuàng)建一個(gè)文件夾
import java.io.File;
//使用mkdir()方法創(chuàng)建一個(gè)文件夾
public class Test4 {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"test");
f.mkdir();//創(chuàng)建文件夾
}
}
實(shí)例五:列出指定目錄的全部文件
如果現(xiàn)在給出了一個(gè)目錄,則可以直接列出目錄中的內(nèi)容姐军。但是列出的方法在File類中存在兩個(gè):
- 以字符串?dāng)?shù)組的形式返回:public String[] list()
- 以File數(shù)組的形式返回:public File[] listFiles()
- 以File數(shù)組的形式列出系統(tǒng)所有的根路徑,這是一個(gè)靜態(tài)方法:static File[] listRoots()
操作一:使用list()列出全部?jī)?nèi)容
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);
}
}
}
實(shí)例六:判斷一個(gè)給定的路徑是否是目錄
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()+"不是目錄");
}
}
}
實(shí)例七:列出指定目錄的全部?jī)?nèi)容
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);
}
}
}
}
總結(jié):
- File類是在java.io包中唯一與文件本身有關(guān)的
- 可以使用File類創(chuàng)建尖淘、刪除等常見的文件操作
- 在使用File類指定路徑的時(shí)候一定要注意操作系統(tǒng)間的差異奕锌,盡量使用separator進(jìn)行分割
RandomAccessFile類
之前的File類只是針對(duì)文件本身進(jìn)行操作的,而如果相對(duì)文件內(nèi)容進(jìn)行操作德澈,則可以使用RandomAccessFile類歇攻,此類屬于隨機(jī)讀取類,可以隨機(jī)的讀取一個(gè)文件中指定位置的數(shù)據(jù)梆造。
因?yàn)樵谖募薪墒兀械脙?nèi)容都是按照字節(jié)存放的,都有固定的保存位置镇辉。
構(gòu)造函數(shù):
public RandomAccessFile(File file,String mode)throws FileNotFoundException
實(shí)例化此類的時(shí)候需要傳遞File類屡穗。告訴程序應(yīng)該操作的是哪個(gè)文件,之后有個(gè)模式忽肛,文件的打開模式村砂,常用的兩種模式:
- r:讀
- w:寫
- rw:讀寫,如果使用此模式屹逛,如果文件不存在础废,則會(huì)自動(dòng)創(chuàng)建
文件記錄指針
- long getFilePointer():返回文件記錄指針的當(dāng)前位置
- 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");//讀寫模式,如果該路徑不存在會(huì)自動(dòng)創(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);//跳過第一個(gè)人的信息
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);//指針回到文件開頭罕模,讀取第二個(gè)人的信息
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ù)都是以流的方式進(jìn)行傳輸或保存的评腺,程序需要數(shù)據(jù)的時(shí)候要使用輸入流讀取數(shù)據(jù),而當(dāng)程序需要將一些數(shù)據(jù)保存起來的時(shí)候淑掌,就要使用輸出流完成蒿讥。
程序中的輸入輸出都是以流的形式保存的,流中保存的實(shí)際上全都是字節(jié)文件抛腕。
字節(jié)流與字符流
在java.io包中操作文件內(nèi)容的主要有兩大類:字節(jié)流芋绸、字符流,兩類都分為輸入和輸出操作担敌。在字節(jié)流中輸出數(shù)據(jù)主要是使用OutputStream完成摔敛,輸入使的是InputStream,在字符流中輸出主要是使用Writer類完成全封,輸入流主要使用Reader類完成舷夺。(這四個(gè)都是抽象類)
操作流程
在Java中IO操作也是有相應(yīng)步驟的苦酱,以文件操作為例,主要的操作流程如下:
- 使用File類打開一個(gè)文件
- 通過字節(jié)流或字符流的子類给猾,指定輸出的位置
- 進(jìn)行讀/寫操作
- 關(guān)閉輸入/輸出
IO操作屬于資源操作疫萤,一定要記得關(guān)閉
字節(jié)流
字節(jié)流主要是操作byte類型數(shù)據(jù),以byte數(shù)組為準(zhǔn)敢伸,主要操作類就是OutputStream扯饶、InputStream
字節(jié)輸出流:OutputStream
OutputStream是整個(gè)IO包中字節(jié)輸出流的最大父類,此類的定義如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
從以上的定義可以發(fā)現(xiàn)池颈,此類是一個(gè)抽象類尾序,如果想要使用此類的話,則首先必須通過子類實(shí)例化對(duì)象躯砰,那么如果現(xiàn)在要操作的是一個(gè)文件每币,則可以使用:FileOutputStream類。通過向上轉(zhuǎn)型之后琢歇,可以為OutputStream實(shí)例化
Closeable表示可以關(guān)閉的操作兰怠,因?yàn)槌绦蜻\(yùn)行到最后肯定要關(guān)閉
Flushable:表示刷新,清空內(nèi)存中的數(shù)據(jù)
FileOutputStream類的構(gòu)造方法如下:
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);//如果文件不存在會(huì)自動(dòng)創(chuàng)建
String str="Hello World";
byte[] b=str.getBytes();
out.write(b);//因?yàn)槭亲止?jié)流李茫,所以要轉(zhuǎn)化成字節(jié)數(shù)組進(jìn)行輸出
out.close();
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//也可以一個(gè)字節(jié)一個(gè)字節(jié)進(jìn)行輸出
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);//如果文件不存在會(huì)自動(dòng)創(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
在構(gòu)造方法中揭保,如果將append的值設(shè)置為true,則表示在文件的末尾追加內(nèi)容魄宏。
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);//追加內(nèi)容
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
既然程序可以向文件中寫入內(nèi)容秸侣,則就可以通過InputStream從文件中把內(nèi)容讀取進(jìn)來,首先來看InputStream類的定義:
public abstract class InputStream extends Object implements Closeable
與OutputStream類一樣宠互,InputStream本身也是一個(gè)抽象類味榛,必須依靠其子類,如果現(xiàn)在是從文件中讀取予跌,就用FileInputStream來實(shí)現(xiàn)励负。
觀察FileInputStream類的構(gòu)造方法:
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));
}
}
但以上方法是有問題的,用不用開辟這么大的一個(gè)字節(jié)數(shù)組匕得,明顯是浪費(fèi)嘛,我們可以根據(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;
//我們換種方式汁掠,一個(gè)字節(jié)一個(gè)字節(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為文件讀完的標(biāo)志
b[len]=(byte) temp;
len++;
}
in.close();
System.out.println(new String(b,0,len));
}
}
字符流
在程序中一個(gè)字符等于兩個(gè)字節(jié)集币,那么java提供了Reader考阱、Writer兩個(gè)專門操作字符流的類。
字符輸出流:Writer
Writer本身是一個(gè)字符流的輸出類鞠苟,此類的定義如下:
public abstract class Writer extends Object implements Appendable乞榨,Closeable秽之,F(xiàn)lushable
此類本身也是一個(gè)抽象類,如果要使用此類吃既,則肯定要使用其子類考榨,此時(shí)如果是向文件中寫入內(nèi)容,所以應(yīng)該使用FileWriter的子類鹦倚。
FileWriter類的構(gòu)造方法定義如下:
public FileWriter(File file)throws IOException
字符流的操作比字節(jié)流操作好在一點(diǎn)河质,就是可以直接輸出字符串了,不用再像之前那樣進(jìn)行轉(zhuǎn)換操作了震叙。
寫文件:
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;
//在默認(rèn)情況下再次輸出會(huì)覆蓋掀鹅,追加的方法也是在構(gòu)造函數(shù)上加上追加標(biāo)記
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)在要從文件中讀取內(nèi)容缓升,則可以直接使用FileReader子類械媒。
FileReader的構(gòu)造方法定義如下:
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é)流在操作的時(shí)候本身是不會(huì)用到緩沖區(qū)(內(nèi)存)的,是與文件本身直接操作的拂共,而字符流在操作的時(shí)候是使用到緩沖區(qū)的
字節(jié)流在操作文件時(shí)牺弄,即使不關(guān)閉資源(close方法),文件也能輸出宜狐,但是如果字符流不使用close方法的話势告,則不會(huì)輸出任何內(nèi)容,說明字符流用的是緩沖區(qū)抚恒,并且可以使用flush方法強(qiáng)制進(jìn)行刷新緩沖區(qū)咱台,這時(shí)才能在不close的情況下輸出內(nèi)容
那開發(fā)中究竟用字節(jié)流好還是用字符流好呢?
在所有的硬盤上保存文件或進(jìn)行傳輸?shù)臅r(shí)候都是以字節(jié)的方法進(jìn)行的俭驮,包括圖片也是按字節(jié)完成回溺,而字符是只有在內(nèi)存中才會(huì)形成的,所以使用字節(jié)的操作是最多的混萝。
如果要java程序?qū)崿F(xiàn)一個(gè)拷貝功能遗遵,應(yīng)該選用字節(jié)流進(jìn)行操作(可能拷貝的是圖片),并且采用邊讀邊寫的方式(節(jié)省內(nèi)存)逸嘀。
字符-字節(jié)轉(zhuǎn)換流
OutputStreamWriter和InputStreamReader
在整個(gè)IO包中车要,實(shí)際上就是分為字節(jié)流和字符流,但是除了這兩個(gè)流之外崭倘,還存在了一組字節(jié)流-字符流的轉(zhuǎn)換類翼岁。
OutputStreamWriter:是Writer的子類类垫,將輸出的字符流變?yōu)樽止?jié)流,即:將一個(gè)字符流的輸出對(duì)象變成字節(jié)流的輸出對(duì)象琅坡。
InputStreamReader:是Reader的子類悉患,將輸入的字節(jié)流變?yōu)樽址鳎矗簩⒁粋€(gè)字節(jié)流的輸入對(duì)象變成字符流的輸入對(duì)象脑蠕。
一般在操作輸入輸出內(nèi)容就需要使用字節(jié)或字符流购撼,但是有些時(shí)候需要將字符流變成字節(jié)流的形式,或者將字節(jié)流變?yōu)樽址鞯男问角聪桑杂厍螅托枰硗庖唤M轉(zhuǎn)換流的操作類。
看一下OutputStreamWriter的構(gòu)造方法:
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();
}
}
讀得時(shí)候也可以用字符流形式讀取字節(jié)流的對(duì)象
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的直接子類驰怎,但是在字符流文件的兩個(gè)操作類卻有一些特殊,F(xiàn)ileWriter并不直接是Writer的子類二打,而是OutputStreamWriter的子類县忌,而FileReader也不直接是Reader的子類,而是InputStreamReader的子類继效,那么從這兩個(gè)類的繼承關(guān)系就可以清楚的發(fā)現(xiàn)症杏,不管是使用字節(jié)流還是字符流實(shí)際上最終都是以字節(jié)的形式操作輸入輸出流的。也就是說瑞信,傳輸或者從文件中讀取數(shù)據(jù)的時(shí)候厉颤,文件里真正保存的數(shù)據(jù)永遠(yuǎn)是字節(jié)。
內(nèi)存操作流
ByteArrayInputStream和ByteArrayOutputStream
之前所講解的程序中凡简,輸出和輸入都是從文件中來得逼友,當(dāng)然,也可以將輸出的位置設(shè)置在內(nèi)存之上秤涩,此時(shí)就要使用ByteArrayInputStream帜乞、ByteArrayOutputStream來完成輸入輸出功能了
ByteArrayInputStream的主要功能將內(nèi)容輸入到內(nèi)存之中
ByteArrayOutputStream的主要功能是將內(nèi)存中的數(shù)據(jù)輸出
此時(shí)應(yīng)該把內(nèi)存作為操作點(diǎn)
ByteArrayInputStream類的定義:
public class ByteArrayInputStream extends InputStream
構(gòu)造方法:
public ByteArrayInputStream(byte[] buf)
接受一個(gè)byte數(shù)組,實(shí)際上內(nèi)存的輸入就是在構(gòu)造方法上將數(shù)據(jù)傳入到內(nèi)存中溉仑。
ByteArrayOutputStream:輸出就是從內(nèi)存中寫出數(shù)據(jù)
public void write(int b)
以下是以內(nèi)存操作流完成的一個(gè)大小寫字母轉(zhuǎn)換的程序:
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());
}
}
管道流
管道流(線程通信流)
管道流的主要作用是可以進(jìn)行兩個(gè)線程間的通訊,分為管道輸出流(PipedOutputStream)状植、管道輸入流(PipedInputStream)浊竟,如果想要進(jìn)行管道輸出怨喘,則必須要把輸出流連在輸入流之上,在PipedOutputStream類上有如下的一個(gè)方法用于連接管道:
public void connect(PipedInputStream snk)throws IOException
例子:線程之間用管道流進(jìn)行通訊
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();//啟動(dòng)線程
new Thread(receive).start();//啟動(dòng)線程
}
}
打印流
在整個(gè)IO包中振定,打印流是輸出信息最方便的類必怜,主要包含字節(jié)打印流(PrintStream)和字符打印流(PrintWrite)。打印流提供了非常方便的打印功能后频,可以打印任何的數(shù)據(jù)類型梳庆,例如:小數(shù)、整數(shù)卑惜、字符串等等膏执。
看一下PrintStream的構(gòu)造方法:
public PrintStream(OutputStream out)
在PrintStream中定義的構(gòu)造方法中可以清楚的發(fā)現(xiàn)有一個(gè)構(gòu)造方法可以直接接收OutputStream類的實(shí)例,這是因?yàn)榕cOutputStream相比起來露久,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();
}
}
也就是說此時(shí)征峦,實(shí)際上是將FileOutputStream類的功能包裝了一下,這樣的設(shè)計(jì)在java中稱為裝飾設(shè)計(jì)消请。
類似c語(yǔ)言的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 成績(jī):%f 性別:%c", name,age,score,sex);
output.close();
}
}
System對(duì)IO的支持
System表示系統(tǒng)類栏笆,此類也對(duì)IO給予了一定的支持。
public static final PrintStream out 對(duì)應(yīng)系統(tǒng)標(biāo)準(zhǔn)輸出臊泰,一般是顯示器
public static final PrintStream err 錯(cuò)誤信息輸出
public static final InputStream in 對(duì)應(yīng)著標(biāo)準(zhǔn)輸入蛉加,一般是鍵盤
又是由于歷史遺留問題 全局變量沒有大寫~
System.out
使用System.out輸出的時(shí)候就是將輸出的位置定義在了顯示器之中。
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表示的錯(cuò)誤的標(biāo)準(zhǔn)輸出,如果程序中出現(xiàn)了錯(cuò)誤的話察滑,則直接使用System.err進(jìn)行打印輸出即可打厘。
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的實(shí)例化對(duì)象,而且通過實(shí)例代碼可以發(fā)現(xiàn)贺辰,兩者都可以輸出錯(cuò)誤信息户盯,但是一般來講System.out是將信息顯示給用戶看,是正常的信息顯示饲化,而System.err的信息正好相反是不希望用戶看到莽鸭,會(huì)直接在后臺(tái)打印,是專門顯示錯(cuò)誤的
- 一般來講吃靠,如果要想輸出錯(cuò)誤信息的時(shí)候最好不要使用System.out而是直接使用System.err硫眨,這一點(diǎn)只能從其概念上劃分。
System.in
System.in實(shí)際上是一個(gè)鍵盤的輸入流巢块,其本身是InputStream類型的對(duì)象礁阁。那么巧号,此時(shí)就可以利用此方式完成從鍵盤讀取數(shù)據(jù)的功能。
InputStream對(duì)應(yīng)的是輸入流姥闭,輸入流的話肯定可以從指定位置上讀取丹鸿,之前使用的是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ù)組指定長(zhǎng)度呢:
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ù)都放在內(nèi)存了靠欢,再一次性全部拿出來,要實(shí)現(xiàn)這個(gè)功能的話铜跑,要用到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的重定向伞广,因?yàn)檫@些信息都不太希望用戶看到
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
如果想要接收任意長(zhǎng)度的數(shù)據(jù)拣帽,而且避免亂碼產(chǎn)生,就可以使用BufferedReader類
public class BufferedReader extends Reader
因?yàn)檩斎氲臄?shù)據(jù)有可能出現(xiàn)中文嚼锄,所以减拭,此處使用字符流完成。BufferedReader是從緩沖區(qū)之中讀取內(nèi)容区丑,所有的輸入的字節(jié)數(shù)據(jù)都將放在緩沖區(qū)之中拧粪。
System.in本身表示的是InputStream(字節(jié)流),現(xiàn)在要求接收的是一個(gè)字符流沧侥,需要將字節(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類的功能宴杀,也可以方便的對(duì)輸入數(shù)據(jù)進(jìn)行驗(yàn)證癣朗,此類存放在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更加方便,但是這個(gè)程序是有問題的旺罢,如果輸入的字符串中存在空格旷余,那么就會(huì)截止,如果我們要接收空格的下扁达,將分隔符變成“\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);
}
}
對(duì)象序列化和反序列化
所謂的對(duì)象序列化就是將一個(gè)對(duì)象轉(zhuǎn)換為二進(jìn)制流,如果一個(gè)類的對(duì)象要想實(shí)現(xiàn)序列化跪解,則該對(duì)象所在的類必須實(shí)現(xiàn)Serializable接口炉旷,在此接口中沒有任何的方法,此接口只是作為一個(gè)標(biāo)識(shí),表示本類的對(duì)象具備了序列化的能力窘行。
序列化的思想是“凍結(jié)”對(duì)象狀態(tài)骏啰,傳輸對(duì)象狀態(tài)(寫到磁盤、通過網(wǎng)絡(luò)傳輸?shù)鹊龋┏楦撸缓蟆敖鈨觥睜顟B(tài),重新獲得可用的Java對(duì)象透绩,所有這些事情的發(fā)生有點(diǎn)像魔術(shù)翘骂,這要?dú)w功于ObjectInputStream/ObjectOutputStream類,完全保真的元數(shù)據(jù)以及程序員愿意用Serializable標(biāo)識(shí)接口標(biāo)記他們的類帚豪,從而“參與”這個(gè)過程碳竟。
序列化分為兩大部分:
序列化和反序列化。序列化是這個(gè)過程的第一部分狸臣,將數(shù)據(jù)分解成字節(jié)流莹桅,以便存儲(chǔ)在文件中或在網(wǎng)絡(luò)上傳輸。反序列化就是打開字節(jié)流并重構(gòu)對(duì)象烛亦。對(duì)象序列化不僅要將基本數(shù)據(jù)類型轉(zhuǎn)換成字節(jié)表示诈泼,有時(shí)還要恢復(fù)數(shù)據(jù)∶呵荩恢復(fù)數(shù)據(jù)要求有恢復(fù)數(shù)據(jù)的對(duì)象實(shí)例铐达,如果某個(gè)類能夠被序列化,其子類也可以被序列化檬果。聲明為static和transient類型的成員數(shù)據(jù)不能被序列化瓮孙。因此static代表類的狀態(tài),transient代表對(duì)象的臨時(shí)數(shù)據(jù)选脊。
對(duì)象序列化在一下場(chǎng)景使用比較合適:
- 當(dāng)你想把的內(nèi)存中的對(duì)象狀態(tài)保存到一個(gè)文件中或者數(shù)據(jù)庫(kù)中時(shí)候杭抠;
- 當(dāng)你想用套接字在網(wǎng)絡(luò)上傳送對(duì)象的時(shí)候;
- 當(dāng)你想通過RMI(Remote Method Invocation 遠(yuǎn)程方法調(diào)用)傳輸對(duì)象的時(shí)候恳啥;
如果要想實(shí)現(xiàn)對(duì)象的序列化偏灿,則還要依靠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();
}
}
對(duì)象被實(shí)例化之后,就可以通過ObjectInputStream進(jìn)行反序列化的操作
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);
}
}
以上操作實(shí)際上是整個(gè)對(duì)象進(jìn)行的序列化操作扁藕,如果現(xiàn)在假設(shè)類中的某個(gè)屬性不希望被序列化的話沮峡,則使用transient關(guān)鍵字進(jìn)行聲明;
private transient String name;
由上面可知可以對(duì)一個(gè)對(duì)象序列化亿柑,那么因?yàn)镺bject可以接受任意的引用數(shù)據(jù)類型邢疙,所以也可以同時(shí)對(duì)多個(gè)對(duì)象一起進(jìn)行序列化操作,包括數(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);
}
}
}