1. 程式人生 > >java(十一)IO流

java(十一)IO流

java io流

深度遍歷演示:

package day22;

import java.io.File;


public class FileTest {


/**

* 需求:對指定目錄進行所有內容的列出。(包含子目錄,前面學的都只能列出當前目錄內容,子目錄不行)

* 也可以理解為深度遍歷。

*/

public static void main(String[] args) {

File dir=new File("e:\\javatest");

listAll_2(dir,0);

}



public static void listAll_1(File dir) {

System.out.println("dir:"+dir.getAbsolutePath());

//獲取指定目錄下當前的所有文件或者文件對象

File[] files=dir.listFiles();

for(int x=0;x<files.length;x++){

if(files[x].isDirectory()){

listAll_1(files[x]); //這就是遞歸

}

else

System.out.println("file:"+files[x].getAbsolutePath());

}

}

public static void listAll_2(File dir, int level) { //定義一個計數器,記錄當前文件的層級,從而決定前面加幾個空格,為什麽不在方法中定義?這就和遞歸有關了。

System.out.println(getSpace(level)+dir.getName());

level++;

File[] files=dir.listFiles();

for(int x=0;x<files.length;x++){

if(files[x].isDirectory()){

listAll_2(files[x],level); //這就是遞歸

}

else

System.out.println(getSpace(level)+files[x].getName());

}

}



private static String getSpace(int level) {

StringBuilder sb=new StringBuilder();

for(int x=0;x<level;x++){

sb.append(" ");

}

return sb.toString();

}

}




上面代碼中涉及到了遞歸,接下來就學習一下遞歸的知識。

遞歸: 函數自身直接或者間接地調用到了自身。

* 什麽時候使用?

* 一個功能在被重復使用,並且每次使用時,參與運算的結果和上一次調用有關。

* 這時可以用遞歸來解決問題。

* 註意:1.遞歸必須明確條件,否則容易棧溢出

* 2.遞歸的次數別太多,否則棧溢出異常。

package day22;

public class DiGuiDemo {


/**

* 遞歸演示。

*/

public static void main(String[] args) {

/*

* 遞歸:函數自身或者直接或者間接調用到了自身

* 什麽時候使用?

* 一個功能在被重復使用,並且每次使用時,參與運算的結果和上一次調用有關。

* 這時可以用遞歸來解決問題

* 註意:1.遞歸必須明確條件,否則容易棧溢出

* 2.遞歸的次數別太多,否則棧溢出異常。

*/

show();

}

public static void show(){

toBin(6); //把一個數轉換成二進制

}

//直接調用自身

public static void toBin(int i) {

if(i>0){

toBin(i/2);

System.out.print(i%2);

}

}

//間接調用自身

public static void method(){

bala();

}

public static void bala(){

method();

}

}







Properties集合

* Map

* |--Hashtable;

* |--Properties;

*

* Properties集合特點:

* 1.該集合中的鍵和值都是字符串。

* 2.集合中的數據可以保存到流中,或者從流中獲取出來。

*

* 通常該集合用於操作以鍵值對形式存在的配置文件。

package day22;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.util.Properties;

import java.util.Set;


public class PropertiesDemo {


/**

* @param args

* @throws IOException

*/

public static void main(String[] args) throws IOException {

//properties集合的基本功能存和取演示

propertiesDemo();

//properties集合和流對象相結合的演示

propertiesDemo2();

//持久化,將集合的數據存儲到文件中

propertiesDemo3();

//把文件中的數據讀取到集合中。

propertiesDemo4();

//修改文件的配置信息

propertiesDemo5();

}


public static void propertiesDemo() {

//創建一個Properties集合

Properties prop=new Properties();

//存儲元素

prop.setProperty("zhangsan", "30");

prop.setProperty("lisi", "32");

prop.setProperty("wangwu", "36");

prop.setProperty("zhaoliu", "20");

//修改元素

prop.setProperty("wangwu", "26");

//取出所有元素

Set<String> names=prop.stringPropertyNames();

for(String name:names){

String value=prop.getProperty(name);

System.out.println(name+":"+value);

}

}

public static void propertiesDemo2() {

Properties prop=new Properties();

prop.setProperty("zhangsan", "30");

prop.setProperty("lisi", "32");

prop.setProperty("wangwu", "36");

prop.setProperty("zhaoliu", "20");

prop.list(System.out); //list方法,列出集合中的鍵和值,一般調試時用。

}

public static void propertiesDemo3() throws IOException{

Properties prop=new Properties();

prop.setProperty("zhangsan", "30");

prop.setProperty("lisi", "32");

prop.setProperty("wangwu", "36");

prop.setProperty("zhaoliu", "20");

// 持久化

//需求:集合中的這些字符串鍵值信息方法一結束就會消失,想要將它們持久化存儲到文件中。

// 就要用到store方法,這需要關聯輸出流,所以創建一個。

FileOutputStream fos=new FileOutputStream("info.txt");

// 將集合數據存儲到文件中,使用store方法。

prop.store(fos, "name+age");

fos.close();

}

public static void propertiesDemo4() throws IOException{

Properties prop=new Properties();

//需求:與Demo3相反,這次要把硬盤中的數據讀到集合中。

//註意:文件中的數據必須是鍵值對。

FileInputStream fis=new FileInputStream("info.txt");

//使用load方法。

prop.load(fis);

fis.close();

prop.list(System.out); //這個list就是驗證一下確實讀取到集合中了。

}

public static void propertiesDemo5() throws IOException{

/*

* 需求:對已有的配置文件信息進行修改。

* 步驟:先讀取這個文件,並將這個文件的鍵值數據存儲到集合中。

* 再通過集合對數據進行修改,最後通過流將修改後的數據存儲到文件中。

*/

File file=new File("info.txt");

if(!file.exists()){

file.createNewFile();

}

FileReader fr=new FileReader("info.txt");

Properties prop=new Properties();

prop.load(fr);

prop.setProperty("wangwu", "16");

FileWriter fw=new FileWriter(file);

prop.store(fw, "");

fr.close();

fw.close();

prop.list(System.out);

}

}

properties的一個練習:

package day22;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Properties;


public class PropertiesTest {


/**

* 需求:定義一個功能,獲取一個應用程序運行的次數,若超過5次,

* 給出 “使用次數已到,請註冊” 的提示,並不要再運行程序。

*

* 思路:1.得有一個計數器,每次程序啟動就計數一次,並且是在原有的基礎上計數。

* 2.計數器就是一個變量。突然冒出一個想法,程序啟動時進行計數,計數器必須存在於內存並進行運算。

* 可是程序一結束,計數器不就消失了嗎?再次啟動程序,計數器不就重置了嘛,但我們需要多次啟動同一個

* 應用程序,啟動的是同一個計數器,這就需要計數器的生命周期變長,從內存存儲到硬盤文件中。

* 3.如何使用這個計數器呢?

* 首先,程序啟動時,應該先讀取這個用於記錄計數器信息的配置文件,獲取上一次計數器次數,

* 其次,對該次數就行自增,並且自增後的次數要重新存儲到配置文件中。

* 4.文件中的信息該如何進行存儲呢?

* 直接存儲次數值可以,但不明確該數據的含義,所以起名字就很重要了。這就有了名字和值得對應,就要用鍵值對。

* 可是映射關系map搞定,又要讀取硬盤上的數據,所以map+IO=Properties。

* @throws IOException

*/

public static void main(String[] args) throws IOException {

getAppCount();

}

public static void getAppCount() throws IOException{

//將配置文件封裝成對象

File confile=new File("count.properties.txt");

if(!confile.exists())

confile.createNewFile();

FileInputStream fis=new FileInputStream(confile);

Properties prop=new Properties();

prop.load(fis);

//從集合中通過鍵獲取次數

String value=prop.getProperty("time");

//定義計數器,記錄獲取到的次數

int count=0;

if(value!=null){

count=Integer.parseInt(value);

if(count>=5){

//System.out.println("使用次數已到,請註冊");

//return; //這樣寫不好,函數結束了,其他程序還在運行。

throw new RuntimeException("使用次數已到,請註冊");

}

}

count++;

//將改變後的次數重新存儲到集合中

prop.setProperty("time", count+"");

FileOutputStream fos=new FileOutputStream(confile);

prop.store(fos, "");

fos.close();

fis.close();

}

}



練習:

package day22;

import java.io.BufferedWriter;

import java.io.File;

import java.io.FileWriter;

import java.io.FilenameFilter;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;


public class Test {


/**

* 需求:獲取指定目錄下,指定擴展名的文件(包含子目錄中的),

* 這些文件的絕對路徑寫入到一個文本文件中。

* 簡單說,就是建立一個指定擴展名的文件的列表。

*

* 思路:1.必須進行深度遍歷。

* 2.要在遍歷的過程中進行過濾。將符合條件的內容都存儲到容器中。

* 3.對容器中的內容進行遍歷並將絕對路徑寫入到文件中。

*/

public static void main(String[] args) {

File dir=new File("e://javatest");

FilenameFilter filter=new FilenameFilter(){


@Override

public boolean accept(File dir, String name) {

return name.endsWith(".java");

}

};

List<File> list=new ArrayList<File>();

getFiles(dir,filter,list);

File destFile=new File(dir,"javalist.txt");

writeToFile(list,destFile);

}

public static void getFiles(File dir,FilenameFilter filter,List<File> list){

/*

* 對指定目錄的內容進行深度遍歷,並按照制定過濾器進行過濾,

* 將過濾後的內容存儲到指定容器list中。

*/

File[] files=dir.listFiles();

for(File file:files){

if(file.isDirectory()){

//遞歸

getFiles(file,filter,list);

}

else{

//對遍歷到的文件進行過濾。將符合條件的File對象存儲到List集合中

if(filter.accept(dir,file.getName())){

list.add(file);

}

}

}

}

public static void writeToFile(List<File> list,File destFile) {

BufferedWriter bufw=null;

try {

bufw=new BufferedWriter(new FileWriter(destFile));

for(File file:list){

bufw.write(file.getAbsolutePath());

bufw.newLine();

bufw.flush();

}

} catch (IOException e) {

throw new RuntimeException("寫入失敗");

} finally{

if(bufw!=null)

try {

bufw.close();

} catch (IOException e) {

throw new RuntimeException("關閉失敗");

}

}

}

}




IO包中的其他類:

打印流:PrintWriter和PrintStream。可以直接操作輸入流和文件。

1.它提供了打印方法可以對多種數據類型值進行打印,並保持數據的表示形式。

2.它不拋IOException.

3.他的構造函數接收三種類型的值:

a.字符串路徑

b.File對象

c.字節輸出流

序列流:SequenceInputStream,對多個流進行合並。




練習:文件切割器和文件合並器

package day22;


import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Properties;


public class splitFileDemo {


/**

* 練習:文件切割器

* @throws IOException

*/

private static final int SIZE = 1024*1024; //這就是1M。

public static void main(String[] args) throws IOException {

File file=new File("e:\\javatest\\eclipse\\HelloJava\\LoginScreenLoop.mp3");

splitFile(file);

}

public static void splitFile(File file) throws IOException{

//用讀取流關聯源文件

FileInputStream fis=new FileInputStream(file);

//定義一個1M的自定義緩沖區

byte[] buf=new byte[SIZE]; //定義一個指定大小的緩沖區,待會就把文件要切成這麽大的。

//創建目的

FileOutputStream fos=null;

int len=0;

int count=1;

/*

* 切割文件時,必須要記錄被切割文件的名稱和切割出來的碎片文件的個數,以方便合並。

* 這個信息為了進行簡單的描述,使用鍵值對的方式,用到了properties對象。

*/

Properties prop=new Properties();

File dir=new File("e:\\javatest\\eclipse\\HelloJava\\partfiles");

if(!dir.exists()){

dir.mkdirs();

}

while((len=fis.read(buf))!=-1){

fos=new FileOutputStream(new File(dir,(count++)+".part")); //碎片文件文件名要註意,類型也別直接就寫txt

fos.write(buf,0,len);

fos.close();

}

fos.close();

fis.close();

//將被切割文件的信息保存到prop中。

prop.setProperty("partcount", count+"");

prop.setProperty("filename", file.getName());

//將prop的數據存儲到文件中。

fos=new FileOutputStream(new File(dir,count+".properties"));

prop.store(fos, "save file information");

}

}




package day22;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.SequenceInputStream;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Enumeration;

import java.util.Properties;


public class MergerDemo {


/**

* 文件合並器

*

* 文件切割器切了之後肯定還要合並嘛

* @throws IOException

*/

public static void main(String[] args) throws IOException {

File dir=new File("partfiles");

mergeFile(dir);

}

public static void mergeFile(File dir) throws IOException{

//先拿被切割文件的配置信息。不知道這個文件叫啥,只知道後綴名是.properties。所以要用過濾器

File[] files=dir.listFiles(new SuffixFilter(".properties"));

if(files.length!=1)

throw new RuntimeException(dir+",該目錄下沒有properties擴展名的文件或者不唯一");

//記錄配置文件對象,並獲取文件中的信息

File confile=files[0];

Properties prop=new Properties();

FileInputStream fis=new FileInputStream(confile);

prop.load(fis);

String filename=prop.getProperty("filename");

int count =Integer.parseInt(prop.getProperty("partcount"));

//獲取該目錄下的碎片文件

File[] partFiles=dir.listFiles(new SuffixFilter(".part"));

if(partFiles.length!=count-1){

throw new RuntimeException("碎片文件不符合要求");

}

//將碎片文件和流對象關聯並存儲到集合中

ArrayList<FileInputStream> al=new ArrayList<FileInputStream>();

for(int x=1;x<=partFiles.length;x++){

al.add(new FileInputStream(new File(dir,x+".part")));

}

//將多個流合並成一個序列流

Enumeration<FileInputStream> en=Collections.enumeration(al);

SequenceInputStream sis=new SequenceInputStream(en);

FileOutputStream fos=new FileOutputStream(new File(dir,filename));

byte[] buf=new byte[1024];

int len=0;

while((len=sis.read(buf))!=-1){

fos.write(buf,0,len);

}

fos.close();

sis.close();

}

}



IO包中的其他類:

操作基本數據類型:

DataInputStream和DataOutputStream

操作字節數組:

ByteArrayInputStream和ByteArrayOutputStream

操作字符數組:

CharArrayReader和CharArrayWriter

操作字符串:

StringReader和StrinWriter


DataInputStream和DataOutputStream:

package day22;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;


public class DataStreamDemo {


/**

* @param args

* @throws IOException

*/

public static void main(String[] args) throws IOException {

writeData();

readData();

}


public static void readData() throws IOException {

DataInputStream dis=new DataInputStream(new FileInputStream("data.txt"));

String str=dis.readUTF();

System.out.println(str);

}


public static void writeData() throws IOException {

DataOutputStream dos=new DataOutputStream(new FileOutputStream("data.txt"));

dos.writeUTF("你好");

dos.close();

}

}



ByteArrayInputStream和ByteArrayOutputStream:

這兩個類關閉無效,關閉後還可以調用且不拋異常。因為此類中的方法不調用底層資源,只是在內存中操作一個數組。


package day22;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;


public class ByteArrayStream {


/**

* @param args

*/

public static void main(String[] args) {

ByteArrayInputStream bis=new ByteArrayInputStream("abcdefg".getBytes());

ByteArrayOutputStream bos=new ByteArrayOutputStream();

int ch=0;

while((ch=bis.read())!=-1){

bos.write(ch);

}

//bis這裏不用關 ,關了也沒用。

System.out.println(bos.toString());

}


}



CharArrayReader和CharArrayWriter

StringReader和StrinWriter

這四個和ByteArrayInputStream,ByteArrayOutputStream類似,類比學習即可。






編碼表:

ASCII:美國標準信息交換碼 用一個字節的7位可以表示。所以0開頭的一般是美國碼表。

ISO8859-1:拉丁碼表。歐洲碼表,用一個字節的8位表示。

GB2312:中國的中文編碼表

GBK:中國的中文編碼表的升級,融合了更多的中文文字符號。

Unicode:國際標準碼,融合了多種文字。所有文字都用兩個字節來表示,java語言使用就是unicode。

UTF-8:最多用三個字節來表示一個字符。


package day22;

import java.io.IOException;


public class EncodeDemo {


/**

* 字符串--> 字節數組 編碼

* 字節數組--> 字符串 解碼

* @throws IOException

*

*/

public static void main(String[] args) throws IOException {

String str="你好";

//編碼

byte[] buf=str.getBytes("GBK");

//你好對應的編碼(GBK): -60 -29 -70 -61

//你好對應的編碼(UTF-8): -28 -67 -96 -27 -91 -67

printBytes(buf);

//解碼

String s1=new String(buf,"GBK");

System.out.println("s1="+s1);

}


public static void printBytes(byte[] buf) {

for(Byte b:buf){

System.out.print(b+" ");

}

}


}



一個練習:

package day22;

import java.io.IOException;


public class EncodeTest {


/**

* 在java中,字符串“abcd”與字符串“ab你好”的長度是一樣的,都是四個字符。

* 但對應的字節數不同,因為一個漢字占兩個字節。

* 定義一個方法,按照最大字節數來去子串。

* 如:對於“ab你好”,如果取三個字節,那麽子串就是ab與“你”字的半個

* 那麽半個就要舍棄。如果取四個字節就是“ab你”,取五個就是“ab你”。

* @throws IOException

*/

public static void main(String[] args) throws IOException {

String str="ab你好cd謝謝";

int len=str.getBytes("GBK").length;

for(int x=0;x<len;x++){

System.out.println("截取"+(x+1)+"個字節的結果是:"+cutStringByU8Byte(str,x+1));

}

}

//用U8碼表做的方法

public static String cutStringByU8Byte(String str, int len) throws IOException {

byte[] buf=str.getBytes("UTF-8");

int count=0;

for(int x=len-1;x>=0;x--){

if(buf[x]<0)

count++;

else

break;

}

if(count%3==0)

return new String(buf,0,len,"utf-8");

else if(count%3==1)

return new String(buf,0,len-1,"utf-8");

else

return new String(buf,0,len-2,"utf-8");

}

//用GBK做的方法

public static String cutStringByByte(String str,int len) throws IOException{

byte[] buf=str.getBytes("gbk");

int count=0;

for(int x=len-1;x>=0;x--){

if(buf[x]<0)

count++;

else

break;

}

if(count%2==0)

return new String(buf,0,len);

else

return new String(buf,0,len-1);

}

}



本文出自 “12946849” 博客,請務必保留此出處http://12956849.blog.51cto.com/12946849/1949953

java(十一)IO流