黑马程序员_Java IO(下)

1,字符编码

在Java程序的开发中最常见的是ISO8859-1,GBK/GBK2312,unicode,UTF编码.

ISO8859-1:属于单字节编码,最多只能表示0-255的字符范围,主要在英文上应用.

GBK/GB2312:中文的国际编码,专门用来表示汉字,是双字节编码,如果在此编码中出现中文,则使用ISO8859-1编码,GBK可以表示简体中文和繁体中文,而GB2312只能表示简体中文,GBK兼容GB2312

unicode:Java中使用此编码方式,是最标准的一种编码,使用十六进制进行编码,但此编码不兼容ISO8859-1编码

UTF:它兼容ISO8859-1编码,同时也可以用来表示所有的语言字符,不过UTF编码是不定长编码,每一个字符的长度为1-6个字节不等,一般在中文网页中使用此编码,可以节约空间

在IO体系中,使用到转化流的时候,我们可以对输入或者输出的内容指定其特定的编码表

黑马程序员_Java IO(下)黑马程序员_Java IO(下)

2,内存操作流

在IO中,是使用ArrayByteInputStream和ArrayByteOutputStream来完成内存的输入和输出,由于数据是在内存中进行操作的,不涉及到具体的文件,所以在输出的时候,

ArrayByteOutputStream这个类只需要构造无参的构造方法.

内存中数据的存在方式都是字节,所以在ArrayByteInputStream中的构造函数传入的是byte类型的数组.

黑马程序员_Java IO(下)黑马程序员_Java IO(下)

package cn.bytearray;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ByteArrayDemo {
    public static void main(String[] args) throws IOException {
        String str = "abcsw";
        ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        System.out.println("available:"+bis.available());
        int len = 0;
        byte[] buf = new byte[1024];
        while((len=bis.read(buf))!=-1){
            String s = new String(buf,0,len);
            System.out.println(s);
        }
        bis.close();
        bos.close();
    }
}

关于内存操作流的使用

内存操作流一般在生成临时信息的时候才会使用到,如果将这些临时信息保存在文件中,当代码执行完毕的时候,在将储存临时信息的文件删除,这样操作起来会比较麻烦,这个时候使用内存操作流是最合适的.

3,数据操作流

 

4,跟踪行号的缓冲字符输入流(LineNumberReader)

该类在对读到的字符输入流的时候,可以为该文本文件上加上行号,它里面也有读取文本行的方法,还有一个可以获取当前行号的方法

黑马程序员_Java IO(下)黑马程序员_Java IO(下)

package cn.linenumberread;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class LineNumberReadDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("各种需求.txt");
        LineNumberReader lnr = new LineNumberReader(fr);
        String lin = null;
        while((lin=lnr.readLine())!=null){
            System.out.println(lnr.getLineNumber()+":"+lin);
        }
        fr.close();
        lnr.close();
    }    

}

输出结果的实例,该输出结果的左侧就具备了行号

黑马程序员_Java IO(下)

5,关于window中的‘\r‘和‘\n‘的知识点

在Java中\r的阿斯科码值是13,\n的阿斯科码值是10.在window中的换行是有两个阿斯科码值13和10组成的,其实在window中的enter键,这个键按一下,它是实现了2个动作的,

\r和\n,所以在window中的换行是/r/n.

package cn.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class ReadKeyBoard {
    public static void main(String[] args) throws IOException {
        //ReadKey_1();
        ReadKey_2();
    }

    public static void ReadKey_2() throws IOException {
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
        String temp = null;
        while((temp=bufr.readLine())!=null){
            if("over".equals(temp))
                break;
            System.out.println(temp.toUpperCase());
            bufw.newLine();
        }
        bufr.close();
        bufw.close();
    }

    public static void ReadKey_1() throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream in = System.in;
        int len = 0;
        while((len=in.read())!=-1){
            if(len==‘\r‘)
                continue;
            if(len==‘\n‘){
                String str = sb.toString();
                if("over".equals(str))
                    break;
                System.out.println(str.toUpperCase());
                sb.delete(0, sb.length());
            }
            else
            sb.append((char)len);
        }
    }

}

在以上代码中,ReadKey_1这个方法是原始的在控制台上打印出内容,在window中,打印的时候,当一句话打完,就回按一下enter键,这个时候对于程序来说,会产生两个char,\r和\n,这个时候就必须对程序进行判断,当是/r的时候,我们不记录字符,当/n的时候,表示一句话完成了,就得记录打印的数据,然后再把它显示在控制台上去

那么每次记录的字符该如何处理,这个时候就得想到容器的存在,而由于容器一定义就会一直存在在程序中,就是每次打印结果都是把上次记录的数据也打印出来,这个时候,没记录一次数据,打印数据之后,就得删除上次打印的内容,集合清空一般使用clear方法,StringBuffer和StringBuilder用delete方法

 

6,对象序列化(ObjectOutputStream和ObjectInputStream)

对象序列化就是将一个对象变成二进制的数据流的一种方法,,如果一个类需要被序列化,那么对象所在的类必须实现java.io.Serializable接口,该接口中没有定义任何的方法,它只是一个标示接口,标示这一个类具有被序列化的能力.

使用对象输出流输出序列化对象的步骤叫做序列化,反之叫做反序列化

 

 

 

 

 

 

 

 

 

对象序列化和对象反序列化操作时的版本兼容的问题

在对象序列化和反序列化的时候,JDK版本的不统一的话就有可能会造成异常,所以在序列化操作的时候引入一个serialVersionUID的常量,例如

private static final long serialVersionUID = 1L;这里的具体内容可以我们自己决定

一个对象被序列化的内容,只有对象的属性被序列化了

既然Serializable接口中没有任何方法的话,是不是所有的类都可以实现该接口?

不可以,这样在以后的JDK版本的升级中,会出现问题,以后升级的时候,有可能会在该接口中增加方法的.

transient关键字

如果一个对象中的某个属性不希望被序列化,则可以使用该关键字进行声明.

package cn.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

import cn.bean.Person;

public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException, IOException {
        File f = new File("person.txt");
        ObjectOutputStream ops = new ObjectOutputStream(new FileOutputStream(f));
        ops.writeObject(new Person("wjd",20));
        ops.close();
    }

}
package cn.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

import cn.bean.Person;

public class ObjectInputStreamDemo {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        File f = new File("person.txt");
        ObjectInputStream ops = new ObjectInputStream(new FileInputStream(f));
        Person p = (Person)ops.readObject();
        System.out.println(p.getName()+".."+p.getAge());
    }

}
package cn.bean;

import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}

7,打印流(PrintStream和PrintWriter)

PrintStream:字节打印流,提供的打印方法可以对多种的数据类型的值进行打印,并保持数据的表示形式,不会抛出IO异常,

                 构造函数传三种类型的数据,字符串路径,File对象,字节输出流(outputstream)

PrintWriter:字符打印流,构造函数传入的参数有,字节输出流,字符输出流(writer),File对象,字符串路径

TIPS:当在上面两个类中传入的是字符或者是字节输出流的时候,都可以在构造函数中加入一个自动刷新的功能true.

package cn.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out,true);
        String str = null;
        while((str=bufr.readLine())!=null){
            if("over".equals(str))
                break;
            pw.println(str);
            //pw.flush();这里一定要刷新下,才能在控制台上打印出内容来
        }
        bufr.close();
        pw.close();
    }

}
package cn.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        //FileReader f = new FileReader("w.txt");
        PrintStream ps = new PrintStream("w.txt");
        ps.println("奥巴马");
        ps.println(11);
    }
}                                                                                                                                                 

8,将文件切割和合并的2个需求

需求切割一首MP3歌曲,并要求有切割后的配置信息文件,记录歌曲的名字和切割后的切割文件的个数

1,创建一个fileinputstream对象,将源和需要切割的文件相互关联起来

2,创建一个fileoutputstream对象,由于被切割的文件的个数的不确定性,目的的初始值为null

3,定义变量计数器count用来记录切割后文件名的前缀,变量len,用于进行读操作,记录读到数据的长度

4,定义配置文件信息的对象,properties,创建一个File对象的目录文件夹mik,用来保存切割好的文件和配置文件

5,进行标准的读写操作,在while循环中,确定切割文件的数量,利用计数器count来命名切割文件的文件名

6,设置配置信息的键值对于关系,比如原始文件+原始文件名,part+切割后的数量

7,fos对象中,设定需要放配置文件的位置和配置文件的名称

8,将配置文件的信息放进去,store

9,关闭流操作

package cn.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class SplitMP3 {
    public static void main(String[] args) throws IOException {
        File f = new File("d:"+File.separator+"pushu.mp3");
        SplitMP3(f);
    }

    public static void SplitMP3(File f) throws IOException {
        //创建源,将需要切割的文件与源进行关联
        FileInputStream fis = new FileInputStream(f);
        //创建目的,由于切割文件的数量不确定性,初始值为null
        FileOutputStream fos = null;
        //创建一个1m的缓冲区
        byte[] buf = new byte[1048576];
        //创建两个变量,计数器count和记录读到数据长度的len
        int count = 1;
        int len = 0;
        //创建配置信息对象,并创建相应的放切割文件和配置信息文件的File对象
        Properties pro = new Properties();
        File file = new File("d:"+File.separator+"parts");
        if(!file.exists())
            file.mkdirs();
        //开始读写操作,进行文件的切割并存储到对于的文件夹中
        while((len=fis.read(buf))!=-1){
            fos = new FileOutputStream(new File(file,(count++)+".part"));
            fos.write(buf, 0, len);
        }
        //将关键的信息加入到配置文件中
        pro.setProperty("filename", f.getName());
        pro.setProperty("part", count+"");
        fos = new FileOutputStream(new File(file,count+".info"));
        pro.store(fos, "splitMp3 info");
        //各种关闭流
        fis.close();
        fos.close();
    }

}

需求 将上面分割的文件,在合并成一首MP3歌曲,必须要读取配置文件中的信息来完成

1,对方法中传入的File对象的目录参数进行listFiles方法,返回一个File数组,在listFiles的方法中传入一个文件过滤器,作用是在目录中去寻找后缀名是.info的配置文件.由于配置文件肯定只有一个存在,所以取出File[]数组中的第一个元素,这个就是配置文件的File对象

2,创建配置文件properties对象,和fileinputstream对象,将配置文件的File对象穿入fileinputstream对象的构造函数,然后在加载配置文件

Load,通过配置文件对象的方法,去得到mp3的文件名,被分割的文件的个数

3,再次使用文件过滤器,找到目录中后缀名是.part的文件(被分割的文件),

这样就得到一个File[]的数组

4,创建arraylist集合对象,使用for循环,在File[]通过fileinputstream,加入到arraylist集合中,再使用collections这个集合工具类,来得到该集合的枚举对象

5,创建源sequenceinputstream类,将枚举对象给它,再创建目的Fileoutputstream,传入file对象,这个使用到了上面在配置文件中得到的MP3文件名的那个字符串变量.

6,进行标准的读写操作

7,关闭各个流

在上述2个分割和合并的需求中,我们在字节输入和输出流,传入File对象的时候,一定要留意到File中有个构造方法可以传两个对象的,一个是爹,一个是儿子.

package cn.io;

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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;

public class MergeMP3 {
    public static void main(String[] args) throws IOException {
        File dir = new File("d:"+File.separator+"parts");
        //MergeMP3(dir);
        MergeMP3_2(dir);
    }

    public static void MergeMP3_2(File dir) throws IOException {
        File[] fileInfo = dir.listFiles(new FindNameFilter(".info"));
        File info = fileInfo[0];
        FileInputStream fis = new FileInputStream(info);
        Properties pro = new Properties();
        pro.load(fis);
        int part = Integer.parseInt(pro.getProperty("part"));
        String filename = pro.getProperty("filename");
        File[] filemp3 = dir.listFiles(new FindNameFilter(".part"));
        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
        for(int i=0;i<filemp3.length;i++){
            al.add(new FileInputStream(filemp3[i]));
        }
        Enumeration<FileInputStream> en = Collections.enumeration(al);
        SequenceInputStream sis = new SequenceInputStream(en);
        FileOutputStream fos = new FileOutputStream(new File(dir,filename));
        byte[] buf = new byte[10];
        int len = 0;
        while((len=sis.read(buf))!=-1){
            fos.write(buf, 0, len);
        }
        fis.close();
        fos.close();
        sis.close();
    }

    public static void MergeMP3(File dir) throws IOException {
        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
        for(int i=1;i<8;i++){
            al.add(new FileInputStream(new File(dir,i+".part")));
        }
        Enumeration<FileInputStream> en = Collections.enumeration(al);
        SequenceInputStream sis = new SequenceInputStream(en);
        int len=0;
        FileOutputStream fis = new FileOutputStream(new File(dir,"3.mp3"));
        while((len=sis.read())!=-1){
            fis.write(len);
        }
        sis.close();
        fis.close();
    }

}

黑马程序员_Java IO(下),布布扣,bubuko.com

黑马程序员_Java IO(下)

上一篇:Windows客户端C/C++编程规范“建议”——前言


下一篇:通过java类文件识别JDK编译版本