Java其他流

序列流SequenceInputStream:对多个流进行合并。序列流其实是多个输入流的串联,它从输入流的有序集合开始,从第一个输入流开始读取,直到文件末尾,接着从第二个输入流读取,以此类推,直到读完包含最后一个输入流的文件结束

构造函数:

  • SequenceInputStream(InputStream s1, InputStream s2):通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取s2),以提供从此SequenceInputStream 读取的字节。
  • SequenceInputStream(Enumeration<? extends InputStream> e):通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的Enumeration 型参数。

    写个示例:

1.合并两个文件中的数据,使用序列流的第一种构造函数即可

public static void merge1()throws IOException{
        File file1 = new File("F:\\1.txt");
        File file2 = new File("F:\\2.txt");
        File outFile = new File("F:\\a.txt");
        FileInputStream inputStream1 = new FileInputStream(file1);
        FileInputStream inputStream2 = new FileInputStream(file2);
        FileOutputStream outputStream  = new FileOutputStream(outFile);
        SequenceInputStream sequence = new SequenceInputStream(inputStream1,inputStream2);
        byte[] buff = new byte[1024];
        int length = 0;
        while((length = sequence.read(buff))!=-1){
            outputStream.write(buff,0,length);
        }
        sequence.close();
        outputStream.close();
    }

2.若要合并的文件数量大于两个,则需要使用第二种构造函数。对于传递的参数,我们可以利用Vector

public static void merge2()throws IOException{

        File file1 = new File("F:\\1.txt");
        File file2 = new File("F:\\2.txt");
        File file3 = new File("F:\\3.txt");
        File file4 = new File("F:\\4.txt");
        File out = new File("F:\\a.txt");
        FileOutputStream outputStream = new FileOutputStream(out);
        Vector<FileInputStream> vector = new Vector<>();
        vector.add(new FileInputStream(file1));
        vector.add(new FileInputStream(file2));
        vector.add(new FileInputStream(file3));
        vector.add(new FileInputStream(file4));
        //将全部的文件输入流添加到向量中,然后获得向量的迭代器作为序列流构造函数的实参
        Enumeration<FileInputStream> e = vector.elements();
        SequenceInputStream sequence  = new SequenceInputStream(e);
        byte[] buff = new byte[1024];
        int length = 0;
        while((length = sequence.read(buff))!=-1){
            outputStream.write(buff,0,length);
        }
        sequence.close();
        outputStream.close();
    }

下面实现对一个mp3文件的切割及合成

public static void cutFile()throws IOException{
        File file = new File("F:\\1.mp3");
        FileInputStream inputStream = new FileInputStream(file);
        File dir = new File("F:\\music");

        byte[] buff = new byte[1024*1024];
        int length = 0;
        for(int i=1;(length = inputStream.read(buff))!=-1;i++){
            FileOutputStream output = new FileOutputStream(new File(dir,"part"+i+".mp3"));
            output.write(buff,0,length);
            output.close();
        }
        inputStream.close();
    }
    public static void mergeFile()throws IOException{
        File file = new File("F:\\music");
        File[] files = file.listFiles();
        Vector<FileInputStream> vector = new Vector<>();
        for(File f:files){
            if(f.getName().endsWith(".mp3")){
                vector.add(new FileInputStream(f));
            }
        }
        Enumeration<FileInputStream> e = vector.elements();
        SequenceInputStream sequence = new SequenceInputStream(e);
        byte[] buff = new byte[1024];
        int length = 0;
        File out = new File("F:\\hear.mp3");
        FileOutputStream outputStream = new FileOutputStream(out);
        while((length = sequence.read(buff))!=-1){
            outputStream.write(buff,0,length);
        }
        outputStream.close();
        sequence.close();
    }

对象的序列化:可以实现对象的持久化存储


Properties:和流相关的集合对象,继承自HashTable。是一个持久化的属性集,可保存在流中或从流中加载,属性列表中的每个键及其值都是一个String类对象,所以该类不需要泛型

虽然继承自HashTable,顶层接口是Map,如果存放对象可以使用put方法,但是这里不建议使用pu方法,因为它可以允许插入键或者值不是String的项,所以应该使用如下方法:

  • 1,存入键值对:setProperty(key,value);
  • 2,获取指定键对应的值:value getProperty(key);
  • 3,获取集合中所有键元素: Enumeration propertyNames();

在jdk1.6版本给该类提供一个新的方法。Set<String> stringPropertyNames();

  • 4,列出该集合中的所有键值对,可以通过参数打印流指定列出到的目的地。

list(PrintStream);
list(PrintWriter);
例:list(System.out):将集合中的键值对打印到控制台。
list(new PrintStream(“prop.txt”)):将集合中的键值对存储到prop.txt文件中。

  • 5,可以将流中的规则数据加载进行集合,并称为键值对:load(InputStream)

jdk1.6版本。提供了新的方法:load(Reader)—->如果数据包含中文,应该使用字符流对象
注意:流中的数据要是”键=值” 的规则数据。
- 6,可以将集合中的数据进行指定目的的存储:store(OutputStram,String comment)

jdk1.6版本。提供了新的方法–>store(Writer ,String comment):使用该方法存储时,会带着当时存储的时间。
*注意:
Properties只加载key=value这样的键值对,与文件名无关,注释使用#*
利用Properties类读写配置文件:

public static void writeProperties()throws IOException{
        Properties properties = new Properties();
        properties.setProperty("Dream","123");
        properties.setProperty("Mary","345");
        properties.setProperty("Thia","456");
        FileOutputStream output = new FileOutputStream(new File("F:\\new.properties"));
        properties.store(output,"newProperties");  //如果写入的配置文件包含中文,则需要传递字符流对象
        //写出的默认编码是ISO8859-1,字符流对象的编码是GBK
        output.close();
}
public static void readProperties()throws IOException{
        Properties properties = new Properties();
        properties.load(new FileInputStream(new File("F:\\new.properties")));  //如果读取的配置文件中包含中文,则需要传递字符流对象
        Set<Map.Entry<Object,Object>> entries = properties.entrySet();
        for(Map.Entry<Object,Object> entry : entries){
            System.out.println("键:"+entry.getKey()+" 值:"+entry.getValue());
        }
}

示例:记录一个程序运行的次数,当满足指定次数时,该程序就不可以再继续运行了。
通常可用于软件使用次数的限定。

   public static void isAccess()throws IOException{
        //获得配置文件流对象
        Properties properties = new Properties();
        //获取文件对象
        File file = new File("F:\\exe.properties");
        //如果配置文件不存在,则创建文件
        if(!file.exists()){
            file.createNewFile();
        }
        //加载配置文件信息
        properties.load(new FileInputStream(file));
        int count = 0;
        //获取配置文件的count信息,如果是新创建的该文件,则读取的值是null
        String val = properties.getProperty("count");
        if(val!=null){
            count = Integer.parseInt(val);
        }
        //如果已经使用3次,则退出JVM
        if(count == 3){
            System.out.println("您的试用已经结束,请购买正版!");
            System.exit(0);
        }
        //每使用一次,count++
        count++;
        System.out.println("第"+count+"次使用本软件");
        //将最新的配置信息写出
        properties.setProperty("count",count+"");
        //每当新创建一个输出流对象时,会清空文件的内容,所以下面的语句必须等先读取完文件信息之后才能写出,否则将永远读不到上一次设置的count值
        FileOutputStream output = new FileOutputStream(file);
        properties.store(output,"UseAuthority");
        output.close();
    }

打印流:可以打印任何数据,而且打印数据之前将数据先转换为字符串再打印
PrintStream字节打印流对象:打印流本身并没有写数据的能力,其内部维护了一个BufferedWriter对象和OutputStreamWriter对象实现真正的写数据;通过构造函数传入的输出流OutputStream对象构造OutputStreamWriter对象;如果只传入文件名,则创建FileOutputStream类对象构造OutputStreamWriter对象,再将OutputStreamWriter对象传递给BufferedWriter对象

package BasicObject.day21;

import java.io.IOException;
import java.io.PrintStream;

/**
 * Created by Dream on 2017/11/7.
 */
class Animal{
    String name;
    String color;
    public Animal(String name,String color){
        this.name = name;
        this.color = color;
    }
    public String toString(){
        return ("名字:"+name+" 颜色:"+color);
    }
}
public class PrintStreamPractice {
    public static void main(String[] args)throws IOException{
        //创建具有指定文件且不带自动行刷新的新打印流
        PrintStream printStream = new PrintStream("F:\\1.txt");
        printStream.println(97);
        printStream.println("a");
        printStream.println("Hello World!");
        printStream.println(true);
        printStream.println(new Animal("Mouse","Black"));
    }
}

文件中数据:
97
a
Hello World!
true
名字:Mouse 颜色:Black

平时输出数据到控制台上,我们使用的是System.out.println()方式,其中out就是一个PrintStream类型的标准输出流,如果我们想将数据输出到文件中,那么可以通过System的static void setOut(PrintStream out)方法,重新分配“标准”输出流,那么就可以直接输出数据到文件了。

PrintStream printStream = new PrintStream("F:\\1.txt");
//setOut(PrintStream out) 重新分配“标准”输出流。
System.setOut(printStream);
System.out.println("Hello World!");

PrintStream还有一个很重要的作用就是用于输出日志文件。对于出现错误的日志,我们之前习惯于输出到控制台上,但是控制台可容纳的数据是有限的,如果日志非常多,那么就会有信息的丢失,所以写出到文件上更合理。

  public static void ErrorLog()throws IOException{
        /*这种情况下仅能输出一条错误日志信息,但是现在想每次将错误信息追加到错误日志文件中
        PrintStream printStream = new PrintStream("F:\\error.log");
        */
        File file = new File("F:\\error.log");
        FileOutputStream outputStream = new FileOutputStream(file,true);
        //打印流本身没有可以在文件后面追加的方法,但是传递的输出流可以通过构造参数的设置实现追加数据
        PrintStream printStream = new PrintStream(outputStream);
        try{
            int result = 3/0;
        }catch (Exception e){
            e.printStackTrace(printStream);
        }
    }

转换流:字节流通向字符流的桥梁
为什么需要这种转换呢?
我们需要写字符数据,但是仅仅能获得字节流,那么如果此时有这样一个类,可以将字节流转换为字符流,那么就非常方便了,否则还得借助String类来实现编码和解码从而读写字符。

输入字节流转换为输入字符流:InputStreamReader
示例:

    public static void InputStream2Reader()throws IOException{
        InputStream in = System.in; //获得标准输入字节流
        InputStreamReader inputStreamReader = new InputStreamReader(in);  //输入字节流流转输入字符流
        BufferedReader reader  = new BufferedReader(inputStreamReader);
        String line = null;
        while((line = reader.readLine())!= null){  //利用缓冲输入流实现按行读取
            System.out.println(line);
        }
    }

输出字节流转换为输出字符流:OutputStreamWriter
示例:

   public static void OutputStream2Writer()throws IOException{
        FileOutputStream fileOutputStream = new FileOutputStream("F:\\aa.txt");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
        BufferedWriter writer = new BufferedWriter(outputStreamWriter);
        String str = "Hello,我是耿耿Dream";
        writer.write(str);
        writer.close();
    }

可能会纳闷,在上述示例中,直接使用FileWriter不就可以了,为什么非的使用字节流对象然后转换,确实在上述示例中可以直接使用,但是在实际应用中,有时候获取到的流对象是字节流,但是使用字符流读写更加方便,此时需要将字节流转换为字符流,那么该类的价值就体现出来了!
Plus:使用转换流还可以指定码表,FileReader和FileWriter是不能指定码表的,而转换流可以!

   public static void readCoding()throws IOException{
        File file = new File("F:\\code.txt");
        FileInputStream inputStream = new FileInputStream(file);
        //设定利用gbk码表进行解码
        InputStreamReader reader = new InputStreamReader(inputStream,"gbk");
        char[] buff = new char[1024];
        int length = 0;
        //read(char[] cbuf, int offset, int length)将字符读入数组中的某一部分
        while((length = reader.read(buff))!=-1){
            System.out.println(new String(buff,0,length));
        }
    }
    public static void writeCoding()throws IOException{
        File file = new File("F:\\code.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        //设定利用gbk码表进行编码
        OutputStreamWriter writer = new OutputStreamWriter(fileOutputStream,"gbk");
        String str = "我是耿耿Dream";  //写出到文件,大小为13个字节
        writer.write(str);
        writer.close();
    }

如果设定的编码解码使用的码表不一样,则会出现乱码,即不能得到原来的数据!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值