首页 > 代码库 > 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=http://www.mamicode.com/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=http://www.mamicode.com/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流