第22天 SequenceInputStream、合并切割、对象的输入输出流、Properties配置文件、.printStream、编码与解码、转换流、递归

来源:互联网 发布:南京财经大学知乎 编辑:程序博客网 时间:2024/06/07 07:09

上节课回顾

输入字节流:

-----------|InputStream  所有输入字节流的基类  抽象类

-----------------|FileInputStream 读取文件数据的输入字节流

-----------------|BufferedInputStream  缓冲输入字符流       该类出现的目的是为了提高读取文件 数据的效率。 这个类其实只不过是在内部维护了一个8kb的字节数组而已。

输出字节流:

-----------| OutputStream 所有输出字节流的基类。  抽象类。

--------------|FileOutputStream向文件输出数据的输出字节流 

--------------|BufferedOutputStream缓冲输出字节流   该类出现的目的也是为了提高向文件写数据的效率。 这个类的也只不过是在内部维护了一个8kb的字节数组而已。

字符流 :  字符流 = 字节流  + 编码(解码)

输入字符流:

---------| Reader   所有输入字符流的基类。 抽象类。

----------------| FileReader读取文件数据的输入字符流。

----------------|BufferedReader 缓冲输入字符流           该类出现的目的是为了提高读取文件数据的效率与拓展FileReader的(readLine)功能。  这个类的也只不过是在内部维护了一个8kb的字符数组而已。

输出字符流:

---------| Writer 所有输出字符流的基类。  抽象类

----------------| FileWriter向文件输出数据的输出字符流 

----------------|BufferedWriter 缓冲输出字符流        该类出现的目的是为了提高写文件数据的效率与拓展FileWriter的(newLine)功能.

1.SequenceInputStream

SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

void

close()闭此输入流并释放与此流关联的所有系统资源。

 

举例:把a.txt与b.txt文件的内容合并

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.Enumeration;import java.util.Vector;public class Demo1 {    public static void main(String[] args) throws IOException {        merge3();    }    //把三个文件合并成一个文件    public static void merge3() throws IOException {        //找到目标文件        File file1 = new File("F:\\a.txt");        File file2 = new File("F:\\b.txt");        File file3 = new File("F:\\c.txt");        File file4 = new File("F:\\d.txt");        //建立对应 的输入输出流对象        FileOutputStream fileOutputStream = new FileOutputStream(file4);        FileInputStream fileInputStream1 = new FileInputStream(file1);        FileInputStream fileInputStream2 = new FileInputStream(file2);        FileInputStream fileInputStream3 = new FileInputStream(file3);        //创建序列流对象        Vector<FileInputStream> vector = new Vector<FileInputStream>();        vector.add(fileInputStream1);        vector.add(fileInputStream2);        vector.add(fileInputStream3);        Enumeration<FileInputStream> e = vector.elements();        SequenceInputStream sequenceInputStream = new SequenceInputStream(e);        //读取文件数据        byte[] buf = new byte[1024];        int length = 0;        while ((length = sequenceInputStream.read(buf)) != -1) {            fileOutputStream.write(buf, 0, length);        }        //关闭资源        sequenceInputStream.close();        fileOutputStream.close();    }    //使用SequenceInputStream合并文件。    public static void merge2() throws IOException {        //找到目标文件        File inFile1 = new File("F:\\a.txt");        File inFile2 = new File("F:\\b.txt");        File outFile = new File("F:\\c.txt");        //建立数据的输入输出通道        FileOutputStream fileOutputStream = new FileOutputStream(outFile);        FileInputStream fileInputStream1 = new FileInputStream(inFile1);        FileInputStream fileInputStream2 = new FileInputStream(inFile2);        //建立序列流对象        SequenceInputStream inputStream = new SequenceInputStream(fileInputStream1,                fileInputStream2);        byte[] buf = new byte[1024];        int length = 0;        while ((length = inputStream.read(buf)) != -1) {            fileOutputStream.write(buf, 0, length);        }        //关闭资源        inputStream.close();        fileOutputStream.close();    }    //需求:把a.txt与b.txt 文件的内容合并。    public static void merge1() throws IOException {        //找到目标文件        File inFile1 = new File("F:\\a.txt");        File inFile2 = new File("F:\\b.txt");        File outFile = new File("F:\\c.txt");        //建立数据的输入输出通道        FileOutputStream fileOutputStream = new FileOutputStream(outFile);        FileInputStream fileInputStream1 = new FileInputStream(inFile1);        FileInputStream fileInputStream2 = new FileInputStream(inFile2);        //把输入流存储到集合中,然后再从集合中读取        ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();        list.add(fileInputStream1);        list.add(fileInputStream2);        //准备一个缓冲数组        byte[] buf = new byte[1024];        int length = 0;        for (int i = 0; i < list.size(); i++) {            FileInputStream fileInputStream = list.get(i);            while ((length = fileInputStream.read(buf)) != -1) {                fileOutputStream.write(buf, 0, length);            }            //关闭资源            fileInputStream.close();        }        fileOutputStream.close();    }}


2.合并切割

需求: 把一首mp3先切割成n份,然后再把这些文件合并起来。

import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.SequenceInputStream;import java.util.Enumeration;import java.util.Vector;public class Demo2 {    public static void main(String[] args) throws IOException {        //cutFile();        mergeFlile();    }    //合并    public static void mergeFlile() throws IOException {        //找到目标文件        File dir = new File("F:\\music");        //通过目标文件夹找到所有的MP3文件,然后把所有的MP3文件添加到vector中。        Vector<FileInputStream> vector = new Vector<FileInputStream>();        File[] files = dir.listFiles();        for (File file : files) {            if (file.getName().endsWith(".mp3")) {                vector.add(new FileInputStream(file));            }        }        //通过Vector获取迭代器        Enumeration<FileInputStream> e = vector.elements();        //创建序列流        SequenceInputStream inputStream = new SequenceInputStream(e);        //建立文件的输出通道        FileOutputStream fileOutputStream = new FileOutputStream("F:\\合并.mp3");        //建立缓冲数组读取文件        byte[] buf = new byte[1024];        int length = 0;        while ((length = inputStream.read(buf)) != -1) {            fileOutputStream.write(buf, 0, length);        }        //关闭资源        fileOutputStream.close();        inputStream.close();    }    //切割MP3    public static void cutFile() throws IOException {        File file = new File("F:\\美女\\1.mp3");        //目标文件夹        File dir = new File("F:\\music");        //建立数据的输入通道        FileInputStream fileInputStream = new FileInputStream(file);        //建立缓冲数组读取        byte[] buf = new byte[1024 * 1024];        int length = 0;        for (int i = 0; (length = fileInputStream.read(buf)) != -1; i++) {            FileOutputStream fileOutputStream = new FileOutputStream(new File(                        dir, "part" + i + ".mp3"));            fileOutputStream.write(buf, 0, length);            fileOutputStream.close();        }        //关闭资源        fileInputStream.close();    }}
3.对象的输入输出流对象
对象的输入输出流 : 对象的输入输出流 主要的作用是用于写对象的信息与读取对象的信息。 对象信息一旦写到文件上那么对象的信息就可以做到持久化了
对象的输出流: ObjectOutputStream .
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。 
对象的输入流: ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。 
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。 
对象输入输出流要注意的细节:
  1. 如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口而已。
  2. 对象的反序列化创建对象的时候并不会调用到构造方法的、
  3. serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出的一个数字。
  4. 使用ObjectInputStream反序列化的时候,ObjeectInputStream会先读取文件中的serialVersionUID,然后与本地的class文件的serialVersionUID
  进行对比,如果这两个id不一致,那么反序列化就失败了。
  5. 如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后
  在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。
  6. 如果一个对象某个数据不想被序列化到硬盘上,可以使用关键字transient修饰。
  7. 如果一个类维护了另外一个类的引用,那么另外一个类也需要实现Serializable接口。
8. 只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。

package cn.xp.other;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInput;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;class Address implements Serializable {    String country;    String city;    public Address(String country, String city) {        this.country = country;        this.city = city;    }}class User implements Serializable {    private static final long serialVersionUID = 1L;    String userName;    String password;    transient int age; // transient 透明    Address address;    public User(String userName, String passwrod) {        this.userName = userName;        this.password = passwrod;    }    public User(String userName, String passwrod, int age, Address address) {        this.userName = userName;        this.password = passwrod;        this.age = age;        this.address = address;    }    @Override    public String toString() {        return "用户名:" + this.userName + " 密码:" + this.password + " 年龄:" +        this.age + " 地址:" + this.address.city;    }}public class Demo3 {    public static void main(String[] args) throws IOException, Exception {        writeObj();        //readObj();    }    //1.把文件中的对象信息读取出来-------->对象的反序列化    public static void readObj() throws IOException, ClassNotFoundException {        //找到目标文件        File file = new File("F:\\obj.txt");        //建立数据的输入通道        FileInputStream fileInputStream = new FileInputStream(file);        //建立对象的输入流对象        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);        //读取对象信息        User user = (User) objectInputStream.readObject(); //创建对象肯定要依赖对象所属 的class文件。        System.out.println("对象的信息:" + user);    }    //定义方法把对象的信息写到硬盘上------>对象的序列化。    public static void writeObj() throws IOException {        //把user对象的信息持久化存储。        Address address = new Address("中国", "广州");        User user = new User("admin", "123", 15, address);        //找到目标文件        File file = new File("F:\\obj.txt");        //建立数据输出流对象        FileOutputStream fileOutputStream = new FileOutputStream(file);        //建立对象的输出流对象        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);        //把对象写出        objectOutputStream.writeObject(user);        //关闭资源        objectOutputStream.close();    }}

4.Properties配置文件

Properties 类表示了一个持久的属性集。Properties可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

一个属性列表可包含另一个属性列表作为它的“默认值”;如果未能在原有的属性列表中搜索到属性键,则搜索第二个属性列表。

因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。如果在“不安全”的 Properties 对象(即包含非 String 的键或值)上调用 store 或 save 方法,则该调用将失败。类似地,如果在“不安全”的 Properties 对象(即包含非 String 的键)上调用 propertyNames 或 list 方法,则该调用将失败。

Properties(配置文件类): 主要用于生产配置文件与读取配置文件的信息。

Properties要注意的细节:

   1. 如果配置文件的信息一旦使用了中文,那么在使用store方法生成配置文件的时候只能使用字符流解决,如果使用字节流生成配置文件的话,

   默认使用的是iso8859-1码表进行编码存储,这时候会出现乱码。

   2. 如果Properties中的内容发生了变化,一定要重新使用Properties生成配置文件,否则配置文件信息不会发生变化。

import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.util.Map;import java.util.Map.Entry;import java.util.Properties;import java.util.Set;public class Demo4 {public static void main(String[] args) throws IOException {creatProperties();//readProperties();}//读取配置文件爱你的信息 public static void readProperties() throws IOException{//创建Properties对象Properties properties = new Properties();//加载配置文件信息到Properties中properties.load(new FileReader("F:\\persons.properties"));//遍历Set<Entry<Object, Object>> entrys = properties.entrySet();for(Entry<Object, Object> entry  :entrys){System.out.println("键:"+ entry.getKey() +" 值:"+ entry.getValue());}//修改狗娃的密码//把修改后的Properties再生成一个配置文件properties.setProperty("狗娃", "007");properties.store(new FileWriter("F:\\persons.properties"), "hehe");}//保存配置文件文件的信息。public static void creatProperties() throws IOException{//创建PropertiesProperties properties = new Properties();properties.setProperty("狗娃", "123");properties.setProperty("狗剩","234");properties.setProperty("铁蛋","345");// 遍历Properties/*Set<Entry<Object, Object>> entrys = properties.entrySet();for(Entry<Object, Object> entry  :entrys){System.out.println("键:"+ entry.getKey() +" 值:"+ entry.getValue());}*///使用Properties生产配置文件。//properties.store(new FileOutputStream("F:\\persons.properties"), "haha"); //第一个参数是一个输出流对象,第二参数是使用一个字符串描述这个配置文件的信 息。properties.store(new FileWriter("F:\\persons.properties"), "hehe");}}


5.properties作业

需求: 使用properties实现本软件只能 运行三次,超过了三次之后就提示购买正版,退jvm.

import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.util.Properties;public class Demo5 {public static void main(String[] args) throws IOException {File file = new File("F:\\count.properties");if(!file.exists()){//如果配置文件不存在,则创建该配置文件file.createNewFile();}//创建Properties对象。Properties properties = new Properties();//把配置文件的信息加载到properties中properties.load(new FileInputStream(file));FileOutputStream fileOutputStream = new FileOutputStream(file);int count = 0; //定义该变量是用于保存软件的运行次数的。//读取配置文件的运行次数String value = properties.getProperty("count");if(value!=null){count = Integer.parseInt(value);}//判断使用的次数是否已经达到了三次,if(count==3){System.out.println("你已经超出了试用次数,请购买正版软件!!");System.exit(0);}count++;System.out.println("你已经使用了本软件第"+count+"次");properties.setProperty("count",count+"");//使用Properties生成一个配置文件properties.store(fileOutputStream,"runtime");}}

6.printStream

打印流可以打印任意类型的数据,而且打印数据之前都会先把数据转换成字符串再进行打印。

import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintStream;class Animal{String name;String color;public Animal(String name,String color){this.name = name;this.color = color;}@Overridepublic String toString() {return "名字:"+this.name+ " 颜色:"+ this.color;}}public class Demo6 {public static void main(String[] args) throws IOException {/*FileOutputStream fileOutputStream = new FileOutputStream("F:\\a.txt");fileOutputStream.write("97".getBytes());fileOutputStream.close();*///打印流可以打印任何类型的数据,而且打印数据之前都会先把数据转换成字符串再进行打印。File file = new  File("F:\\a.txt");//创建一个打印流PrintStream printStream = new PrintStream(file);/*printStream.println(97);printStream.println(3.14);printStream.println('a');printStream.println(true);Animal a = new Animal("老鼠", "黑色");printStream.println(a);//默认标准的输出流就是向控制台输出的,System.setOut(printStream); //重新设置了标准的输出流对象System.out.println("哈哈,猜猜我在哪里!!");*///收集异常的日志信息。File logFile = new File("F:\\2015年1月8日.log");PrintStream logPrintStream = new PrintStream( new FileOutputStream(logFile,true) );try{int c = 4/0;System.out.println("c="+c);int[] arr = null;System.out.println(arr.length);}catch(Exception e){e.printStackTrace(logPrintStream);}}}

7.编码与解码

编码: 把看得懂的字符变成看不懂码值这个过程我们称作为编码。

解码: 把码值查找对应的字符,我们把这个过程称作为解码。

注意: 以后编码与解码一般我们都使用统一的码表。否则非常容易出乱码。

import java.io.UnsupportedEncodingException;import java.util.Arrays;public class Demo7 {    public static void main(String[] args) throws Exception {        /*        String str = "中国";        byte[] buf = str.getBytes("utf-8");// 平台默认的编码表是gbk编码表。  编码        System.out.println("数组的元素:"+Arrays.toString(buf)); //        str = new String(buf,"utf-8");  //默认使用了gbk码表去解码。        System.out.println("解码后的字符串:"+ str);        */        /*String str = "a中国"; // ,0, 97, 78, 45, 86, -3        byte[] buf = str.getBytes("unicode");  //编码与解码的时候指定 的码表是unicode实际上就是用了utf-16.        System.out.println("数组的内容:"+ Arrays.toString(buf));        */        String str = "大家好";        byte[] buf = str.getBytes(); //使用gbk进行编码        System.out.println("字节数组:" + Arrays.toString(buf)); // -76, -13, -68, -46, -70, -61        str = new String(buf, "iso8859-1");        // 出现乱码之后都可以被还原吗?         byte[] buf2 = str.getBytes("iso8859-1");        str = new String(buf2, "gbk");        System.out.println(str);    }}

8.转换流

输入字节流的转换流:InputStreamReader是字节流通向字符流的桥

   InputStreamReader

输出字节流的转换流:

   OutputStreamWriter   可以把输出字节流转换成输出字符流 。 

转换流的作用:

   1. 如果目前所 获取到的是一个字节流需要转换字符流使用,这时候就可以使用转换流。  字节流---->字符流

   2. 使用转换流可以指定编码表进行读写文件。

import java.io.BufferedReader;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.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.InetSocketAddress;import java.net.Socket;public class Demo8 {    public static void main(String[] args) throws IOException {        //readTest();        //writeTest();'        //writeTest2();        readTest2();    }    //使用输入字节流的转换流指定码表进行读取文件数据    public static void readTest2() throws IOException {        File file = new File("F:\\a.txt");        FileInputStream fileInputStream = new FileInputStream(file);        //创建字节流的转换流并且指定码表进行读取        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,                "utf-8");        char[] buf = new char[1024];        int length = 0;        while ((length = inputStreamReader.read(buf)) != -1) {            System.out.println(new String(buf, 0, length));        }    }    //使用输出字节流的转换流指定码表写出数据    public static void writeTest2() throws IOException {        File file = new File("F:\\a.txt");        //建立数据的输出通道        FileOutputStream fileOutputStream = new FileOutputStream(file);        //把输出字节流转换成字符流并且指定编码表。        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,                "utf-8");        outputStreamWriter.write("新中国好啊");        //关闭资源        outputStreamWriter.close();    }    public static void writeTest() throws IOException {        File file = new File("F:\\a.txt");        FileOutputStream fileOutputStream = new FileOutputStream(file);        //把输出字节流转换成输出字符流。        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);        outputStreamWriter.write("大家好");        outputStreamWriter.close();    }    public static void readTest() throws IOException {        InputStream in = System.in; //获取了标准的输入流。                                    //System.out.println("读到 的字符:"+ (char)in.read());  //read()一次只能读取一个字节。                                    //需要把字节流转换成字符流。        InputStreamReader inputStreamReader = new InputStreamReader(in);        //使用字符流的缓冲类        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);        String line = null;        while ((line = bufferedReader.readLine()) != null) {            System.out.println("内容:" + line);        }    }}

9.递归

递归:函数的自身调用函数的自身。

 递归的使用前提: 必须要有条件的情况下调用。

public class Demo9 {    public static void main(String[] args) {        int result = print(5);        System.out.println("结果:" + result);    }    public static int print(int num) {        if (num == 1) {            return 1;        } else {            return num * print(num - 1);        }    }    public static int test(int num) {        int result = 1;        while (num > 0) {            result = result * num;            num--;        }        return result;    }}

10.递归的练习

需求1:列出一个文件夹的子孙文件与目录。

 

 2,列出指定目录中所有的子孙文件与子孙目录名,要求名称前面要有相应数量的空格:

      第一级前面有0个,第二级前面有1个,第三级前面有2个...,以此类推。

 

3,列出指定目录中所有的子孙文件与子孙目录名,要求要是树状结构,效果如下所示:

      |--src

      |   |--cn

      |   |   |--xp

      |   |   |  |--a_helloworld

      |   |   |  |   |--HelloWorld.java

      |   |   |  |--b_for

      |   |   |  |   |--ForTest.java

      |   |   |  |--c_api

      |   |   |  |   |--Student.java

      |--bin

      |   |--cn

      |   |   |--xp

      |   |   |  |--i_exception

      |   |   |  |   |--ExceptionTest.class

      |   |   |  |--h_linecount

      |   |   |  |   |--LineCounter3.class

      |   |   |  |   |--LineCounter2.class

      |   |  |   |   |--LineCounter.class

      |--lib

      |   |--commons-io.jar

 

需求4: 删除一个非空的文件夹。

作业:  剪切一个非空目录。


import java.io.File;public class Demo10 {    public static void main(String[] args) {        /*        File dir = new File("F:\\1208project\\day22");                listFiles3(dir,"|--");*/        File dir = new File("F:\\aa");        deleteDir(dir);    }    //删除了一个非空的目录    public static void deleteDir(File dir) { // bb        File[] files = dir.listFiles(); //列出了所有的子文件        for (File file : files) {            if (file.isFile()) {                file.delete();            } else if (file.isDirectory()) {                deleteDir(file);            }        }        dir.delete();    }    public static void listFiles3(File dir, String space) { //space 存储的是空格        File[] files = dir.listFiles(); //列出所有 的子文件        for (File file : files) {            if (file.isFile()) {                System.out.println(space + file.getName());            } else if (file.isDirectory()) {                System.out.println(space + file.getName());                listFiles3(file, "|   " + space);            }        }    }    //列出一个文件夹的子孙文件与目录。    public static void listFiles2(File dir, String space) { //space 存储的是空格        File[] files = dir.listFiles(); //列出所有 的子文件        for (File file : files) {            if (file.isFile()) {                System.out.println(space + file.getName());            } else if (file.isDirectory()) {                System.out.println(space + file.getName());                listFiles2(file, "  " + space);            }        }    }    //列出一个文件夹的子孙文件与目录。    public static void listFiles1(File dir) {        File[] files = dir.listFiles(); //列出所有 的子文件        for (File file : files) {            if (file.isFile()) {                System.out.println("文件名:" + file.getName());            } else if (file.isDirectory()) {                System.out.println("文件夹:" + file.getName());                listFiles1(file);            }        }    }}







0 0
原创粉丝点击