1? ? ? IO(三)No20
【
Properties屬性集,主要用于操作配置屬性,
是以鍵值對的方式來保存屬性,并且都是String類型
繼承自Hashtable類,所以是一個Map集合,具有Map接口中的所有方法,但是在保存和讀取數據的時候不建議使用put和get方法,因為有可能會出現異常,建議使用Properties中特有的方法進行數據的存儲
常用方法:
1、添加、獲取
setProperty(String key,String value):添加鍵值對
getProperty(String key):通過鍵獲取值《getProperty(Stringkey)
getProperty(Stringkey,StringdefaultValue)》如果鍵不存在返回默認值
2、保存、加載(配合IO流使用)
store():將數據通過輸出流寫到指定文件中
《store(OutputStreamout,Stringcomments)
store(Writerwriter,Stringcomments)參數二:代表注釋》
load():通過輸入流讀取指定文件中的數據
《load(InputStreaminStream)load(Readerreader)》
3、遍歷數據
list():將集合中的所有數據輸出到指定的流中(一般用于調試)
《list(PrintStreamout)list(PrintWriterout)》
stringPropertyNames():獲取集合中鍵的集合(鍵的類型是String類型)
】
【
publicclass Demo {
public static void main(String[] args)throws IOException {
Properties prop = newProperties();
/*
* Properties類繼承于Hashtable類,所以可以使用put方法添加鍵值對,
* 但是Properties類中的數據要求應該都是String類型,使用put方法返回可能會出問題
* 官方建議使用setProperty()方法添加鍵值對
*/
//?????????????? prop.put("textsize",18);
//?????????????? prop.get("textsize");
//保存值
prop.setProperty("textsize","18");
prop.setProperty("textcolor","red");
//獲取值
String size =prop.getProperty("textsize");
String color=prop.getProperty("textcolor");
System.out.println(size);
System.out.println(color);
//將屬性保存到磁盤上
//Properties的作用是將數據持久化保存,實際上就是將數據保存在磁盤上
//?????????????? prop.save(out, comments);
FileOutputStream fos = new FileOutputStream("prop.properties");
prop.store(fos, "注釋");
//從磁盤上讀取屬性數據
Properties prop2 = newProperties();
FileInputStream fis = newFileInputStream("prop.properties");
prop2.load(fis);
System.out.println(prop2);
//遍歷Properties集合(是Map集合)
//list方法一般是用于調試用的
prop2.list(System.out);
//傳統的遍歷Map集合的方式,通過keyset方法獲取鍵的集合,但是元素都是Object類型
//?????????????? prop2.keySet();
Set???? keyset = prop2.stringPropertyNames();
for (String key : keyset) {
String value =prop2.getProperty(key);
System.out.println(key+"..........."+value);
}
}
}
實例:寫一個程序,要求用戶只能打開5次,在第6次打開的時候就拋出異常提示“打開失敗”
publicclass Ex {
public static void main(String[] args){
System.out.println("程序開啟.......");
//檢測使用的次數
check();
System.out.println("程序正常運行.......");
System.out.println("程序結束.......");
}
private static void check() {
/*
* 思路:記錄用戶打開程序的次數,每次打開的時候都記一次,將次數保存在配置文件中,
* 每次打開的時候讀取上一次記錄的次數,如果超出上限,就提示用戶
*/
//
FileInputStream fis =null;
FileOutputStream fos = null;
try {
Properties prop =new Properties();
File file = newFile("prop_ex.properties");
//要保證文件存在
if(!file.exists()){
file.createNewFile();
}
fis = new FileInputStream(file);
//從文件中加載數據到Properties集合中
prop.load(fis);
//通過鍵獲取值,如果鍵值對不存在,就返回指定的默認值
int count=Integer.parseInt(prop.getProperty("count","0"));
count ++;
//判斷打開的次數是否已經超過了上限
if(count>5){
throw newRuntimeException("適用用次數已經超過5次上限,請續費!.......");
}else{
//如果沒有超過
fos = newFileOutputStream(file);
prop.setProperty("count",String.valueOf(count));
prop.store(fos,"open count");
}
} catch (IOException e) {
// TODO: handleexception
}finally{
if(fos != null){
try {
fos.close();
fos= null;
} catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
fis= null;
} catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
】
【
數組流
】
【
byte[] bytes ={97,98,99,100,101};//源字節數組
ByteArrayInputStream bais =//在源數組上創建一個內存輸入流
newByteArrayInputStream(bytes);
int n=0;
byte[] buf = new byte[4];
//讀4個字節放到緩沖buf中,返回有效讀取數
while((n=bais.read(buf))!=-1){
for(int i=0;i
System.out.println(buf[i]);? //打印
}
}
}
//不需要關閉
//創建一個內存輸出流,可以通過它向內置的字節數組中寫字節
ByteArrayOutputStream baos=new ByteArrayOutputStream();
baos.write(65);//往內置字節數組中寫一個字節
baos.write(66);
baos.write(67);
//從中拿出之前寫的字節生成的數組
byte[] array =baos.toByteArray();
for(byte b : array){//遍歷打印,用于驗證
System.out.println(b);
}
//源文件流
FileInputStream fis = newFileInputStream("g:/output.txt");
//目標內存輸出流
ByteArrayOutputStream baos=new? ByteArrayOutputStream();
int n=0;
byte[] buf = new byte[4];//緩沖數組創建
//每次從文件讀4個字節方法緩沖中,有效字節數賦給n,和-1比較判斷是否讀完
while((n=fis.read(buf))!=-1){
baos.write(buf,0,n);?? //沒有讀完就將有效字節寫到內存輸出流
}
fis.close();//需要關閉
//?????????????? baos.close();//不需要關閉
byte[]array=baos.toByteArray();?? //獲取字節數組
for (byte b : array) {//遍歷,驗證
System.out.println((char)b);
}
FileInputStream fis =new FileInputStream(
"g:/MySQL-connector-Java-5.1.7-bin.jar");
ByteArrayOutputStream baos =new ByteArrayOutputStream();
int n = 0;
byte[] buf = newbyte[1024];//緩沖
while ((n = fis.read(buf)) !=-1) {//從文件讀1024字節,有效字節數賦值給n,和-1比較判斷是否結束
baos.write(buf, 0,n);//把有效字節寫到內存輸出流
}
fis.close();
byte[] array =baos.toByteArray(); //用寫進的字節生成數組
//準備從這個字節數組中讀字節
ByteArrayInputStream bais =new ByteArrayInputStream(array);
FileOutputStream fos = newFileOutputStream("g:/copy.jar");
while ((n = bais.read(buf))!= -1) {//從數組讀1024字節,有效字節數賦給n,和-1比較
fos.write(buf, 0,n); //把有效字節寫到copy.jar
}
fos.close();
FileInputStream fis = newFileInputStream("g:/mysql-connector-java-5.1.7-bin.jar");
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int n= 0;
byte[] buf = new byte[1024];
while((n=fis.read(buf))!=-1){//讀源文件只進行一次
baos.write(buf,0,n);
}
fis.close();
byte[] array =baos.toByteArray();
//把文件放到內存中,這些動作不重復進行,這些動作包含了對磁盤的操作
//把內存中的內容拷貝到文件,重復進行
for(int i=1;i<=100;i++){
ByteArrayInputStreambais = new ByteArrayInputStream(array);
FileOutputStream fos= new FileOutputStream("g:/100/"+i+".jar");
//這里也要讀100次,但是每次都是讀內存數組,所以效率大大提高
while((n=bais.read(buf))!=-1){
fos.write(buf,0,n);
}
fos.close();
}
】
內存流(字節數組)節點流、字節流
ByteArrayInputStream
ByteArrayOutputStream
構造方法:
ByteArrayInputStream(byte[]bytes)創建一個內存流,可以從參數字節數組中讀取字節
常用方法:
int read()
int read(byte[] buf)
不需要調用close()方法
構造方法:
ByteArrayOutputStream()創建一個內存輸出流,無參數,可以往內置的字節數組中寫字節
常用方法:
write(int b)
write(byte[] buf,intoff,int len)
不需要調用close()方法
toByteArray()獲得字節數組(之前寫到其中的字節組成的字節數組)
在文件小且不經常變更的情況下,可以用內存流先進行緩存,避免反復磁盤操作
實例:
【
public static void main(String[] args)throws IOException {
//字節數組輸出流
//是以數組作為數據源,將數據寫到數組中
//當數組輸出流被創建的時候內部會自動創建一個數組
ByteArrayOutputStream baso =new ByteArrayOutputStream();
//將數據寫出到數組流內部的數組(內存)中
baso.write("強風125".getBytes());
//取出流中的字節數組
byte[]buf? =baso.toByteArray();
System.out.println(newString(buf));
//在這里因為操作的是內存,所以不需要釋放存放
//?????????????? baso.close();
//使用場景:從網上下載圖片并顯示在界面上
//從內存數組中去數據
ByteArrayInputStream bais =new ByteArrayInputStream(buf);
byte[] cubf? = new byte[1024];
bais.read(cubf);
System.out.println(newString(cubf));
//如果一個數組中的數據比較多,需要分批讀取,那么使用數組流能簡化我們的代碼
//比如:現在有一個字節數組大小為1000,每次讀取300個字節,自到將數據讀完
}
】
對象流是一種處理流、字節流
【
對象流
ObjectInputStream
readObject()
ObjectOutputStream
writeObject()
注意事項:
1、被對象流操作的對象必須先進行序列化(實現Serializable接口)
1)需要在類中定義一個靜態常量(序列值,static final longserialVersionUID)
2)在數據序列化的時候不會對靜態字段(static )和瞬態字段(transient)進行序列化
2、一個文件只能存儲一個對象
】
實例:
【
publicclass Demo {
public static void main(String[] args)throws IOException, ClassNotFoundException {
//?????????????? test1();
//?????????????? writeObj();
readObj();
}
private static void readObj() throwsIOException, ClassNotFoundException {
FileInputStream fis = newFileInputStream("objdemo.object");
ObjectInputStream ois = new ObjectInputStream(fis);
//內部自動進行了反序列化
Student stu =(Student)ois.readObject();
System.out.println(stu);
}
private static void writeObj() throwsIOException {
Student stu = new Student("小強", "男", 18);
//對象流,用于直接操作對象
FileOutputStream fos = newFileOutputStream("objdemo.object");
ObjectOutputStream oos = newObjectOutputStream(fos);
//將對象寫出到指定設備
//注意:對象流操作的對象必須進行序列化
//序列化:只需要實現Serializable
oos.writeObject(stu);
oos.close();
}
private static void test1() throwsIOException, FileNotFoundException {
Student stu = newStudent("小強","男", 18);
FileWriter fw?=? newFileWriter("object.txt");
fw.write(stu.name+"|");
fw.write(stu.gender+"|");
fw.write(stu.age +"");
fw.close();
//從磁盤上讀取對象的數據并生成對象
BufferedReader br = new BufferedReader(newFileReader("object.txt"));
String line = br.readLine();
String[] strs = line.split("\\|");
String name = strs[0];
String gender = strs[1];
int age = Integer.parseInt(strs[2]);
Student stu2 = new Student(name, gender, age);
System.out.println(stu2);
}
}
classStudent implements Serializable/*標記接口*/{
/**
* 序列值,用于標記類的唯一性
* 如果沒有指定序列值,那么編譯器會自動根據類中的成員來自動生成一個序列值
* 建議:在序列化的時候最好要寫上序列值
*/
private static final long serialVersionUID= 10000L;
/**
* static 修飾的類成員不會被序列化
*/
String name;
String gender;
transient int age;???? //瞬態的(不會進行序列化)
public Student(String name, Stringgender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
@Override
public String toString() {
return "Student[name=" + name + ", gender=" + gender + ", age=" + age
+"]";
}
}
】
【
//文件的文件輸出流
FileOutputStream fos = newFileOutputStream("g:/obj");
//用對象輸出流去處理、裝飾fos文件輸出流
ObjectOutputStream oos = newObjectOutputStream(fos);
oos.writeObject("1000phone");//寫一個字符串對象到流中
oos.close();
//對象流裝飾文件流
ObjectOutputStream oos = newObjectOutputStream(
newFileOutputStream("g:/elephant"));
//初始化對象
Elephant mike = newElephant("Mike", 1000);
oos.writeObject(mike);??? //把大象塞進去
oos.close();
】
構造方法:ObjectOutputStream(OutputStream os)參數是它要處理、裝飾的流,增加了寫對象的功能
writeObject(Objectobj)
【
ObjectInputStream ois= //用對象流裝飾文件流
newObjectInputStream(new FileInputStream("g:/obj"));
String str =(String)ois.readObject();?? //讀一個對象
System.out.println("從obj文件中拿出來了:"+str);
ois.close();
ObjectInputStream ois= new ObjectInputStream(
newFileInputStream("g:/elephant"));
//把大象從流中拖出來,拿到的是Object類型,強轉為大象類型
Elephant e =(Elephant)ois.readObject();
System.out.println(e.getName()+"?? "+e.getWeight());
ois.close();
】
構造方法:ObjectInputStream(InputStream is)參數是它要處理、裝飾的流,增加了讀對象的功能
Object readObject()
對象流讀寫,寫的和讀的類型一定要一致。
對象流讀寫的對象必須要可序列化,必須實現Serializable接口,這個接口無抽象方法。
用途:信息的存儲、信息在網絡上的傳遞、信息在組件間傳遞
【
PrintWriterpw = new PrintWriter(
newFileOutputStream("g:/answer.txt",true));
//由于構造方法第二個參數為true ,println會自動刷緩存
pw.println("1000phone");//打印1000phone到文件中并換行
pw.println("Android");//打印android到文件中并換行
pw.println("java");//打印java到文件中并換行
pw.close();
】
PrintWriter輸出流、字符流、處理流
構造方法:
PrintWriter(OutputStreamos,boolean autoFlush)第一個參數是所要裝飾的字節輸出流,第二個參數是表示是否自動刷緩存
PrintWriter(Writerwriter,boolean autoFlush)裝飾字符流
PrintWriter(Stringpath,String csn)在以第一個參數為路徑的文件上建立打印流,字符集由第二個參數指定
println()打印并且換行,在autoFlush為true時,會自動刷緩存
PrintStream用法和PrintWriter差不多,構造方法少一點
實例
【
publicstatic void main(String[] args) throws IOException {
// 打印流(只有輸出流)PrintStream(字節打印流)? PrintWriter (字符打印流)
//?????????????? PrintStream ps = new PrintStream(newFileOutputStream("print.txt"));
PrintStream ps = newPrintStream("print.txt");
/*ps.print(true);
ps.print("中");
ps.print("f");*/
ps.print(18);??? //編碼
ps.write(97);??? //字面值
ps.close();
}
】
【
DataOutputStream dos= //用數據流裝飾文件流
newDataOutputStream(new FileOutputStream("g:/answer.txt"));
dos.writeInt(101);//向數據流中寫100
dos.writeInt(100);
dos.writeInt(70);
dos.writeInt(66);
dos.close();//關閉處理會自動關閉所裝飾的流
DataInputStream dis =new DataInputStream(
new FileInputStream("g:/answer.txt"));
int a=dis.readInt();//用數據流裝飾文件流
System.out.println(a);
System.out.println(dis.readInt());//打印讀出的int數據
System.out.println(dis.readInt());
System.out.println(dis.readInt());
dis.close();
】
DataOutputStream數據輸出流,字節流、處理流
DataOutputStream(OutputStreamos)構造方法參數為它所裝飾的字節輸出流,添加了寫基本類型數據的功能
writeInt(int i)
writeXXX(xxx i)
DataInputStream數據輸入流
DataInputStream(InputStreamis)構造方法參數為它所裝飾的字節輸入流,添加了讀基本數據類型的功能
int readInt()
xxx readXXX()
實例:
【
publicstatic void main(String[] args) throws IOException {
//數據流(過濾流)
FileOutputStream fos = newFileOutputStream("data.txt");
DataOutputStream oos = newDataOutputStream(fos);
oos.writeByte(100);
oos.writeChar('中');
oos.writeShort(1000);
oos.writeInt(1022);
oos.writeLong(12025);
oos.writeFloat(12.2f);
oos.writeDouble(15.4524);
oos.writeBoolean(true);
oos.close();
//讀取數據
FileInputStream fis = new FileInputStream("data.txt");
DataInputStream dis = new DataInputStream(fis);
System.out.println(dis.readByte());
System.out.println(dis.readChar());
System.out.println(dis.readShort());
System.out.println(dis.readInt());
System.out.println(dis.readLong());
System.out.println(dis.readFloat());
System.out.println(dis.readDouble());
dis.close();
}
】
裝飾模式:
1、把被裝飾者通過構造方法傳入裝飾者
2、被裝飾者和裝飾者具有相同的方法(方法名、返回、參數)、具有相同的接口或父類
3、被裝飾者以屬性的形式存在于裝飾者中
【
RandomAccessFile raf= new RandomAccessFile("g:/answer.txt", "rw");
raf.write(65);//A|
raf.write(66);//AB|
raf.seek(0);//將游標一下子跳到第一個位置|AB
raf.write(67);
raf.write(68);
raf.close();
RandomAccessFile raf=new RandomAccessFile("g:/answer.txt", "r");
System.out.println(raf.read());
System.out.println(raf.read());
raf.seek(0);? //游標放到最前
System.out.println(raf.read());
System.out.println(raf.read());
raf.close();
】
RandomAccessFile隨機訪問文件,不是InputStream、OutputStream、Reader、Writer中的任一個子類
RandomAcceessFile(Stringpath,String mode)
構造方法第一個參數表示文件路徑,第二個參數打開模式,如果是"rw"表示可讀可寫,如果是"r"表示只讀
seek(int pos)定位,游標可以隨便向前向后跳,只要不超出范圍(Stream、Reader、Writer只能往后不能往前)