IO流 - 七、流的操作规律 - 需求体现

1、需求:复制一个文本文件

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

FileWriter fw = new FileWriter("b.txt");

BufferedReader bufr = new BufferedReader(fr);

BufferedWriter bufw = new BufferedWriter(fw);

2、需求:读取键盘录入信息,写入到文件中

源:InputStream in = System.in;

转换流:InputStreamReader isr = new InputStreamReader(in);

目的:FileWriter fw = new FileWriter("b.txt");

高效:BufferedReader = new BufferedReader(isr);

     BufferedWriter = new BufferedWriter(fw);

3、需求:将一个文本文件显示在控制台上

源:FileReader fr = new FileReader("a.txt");

读: String line = bufr.readLine();

目的:OutputStream out = System.out;

      OutputStreamWriter osw = new OutputStreamWriter(out);

高效:BufferedReader bufr = new BufferedReader(fr);
     BufferedWriter bufw = new BufferedWriter(osw);

4、需求:读取键盘录入数据,显示在控制台上

源:InputStream in = System.in    ;

目的:OutputStream out = System.out;

转换流:InputStreamReader isr = new InputStreamReader(in);
        OutputStreamWriter isw = new OutputStreamWriter(out);

高效:BufferedReader bufr = new BufferedReader(isr);
      BufferedWriter bufw = new BufferedWriter(isw);

IO流 - 十一、打印流

打印流字符流与字节流

PrintWriter与PrintStream

可以直接操作输出流和文件

1、PrintStream 字节打印流

/**
    PrintStream:
    1、提供了打印方法可以对多种数据类型值进行打印,并保持数据的表现形式。
    2、它不抛IOException
    构造函数,接收三种类型的值:
    1、字符串路径
    2、File对象
    3、字节输出流
*/
610: 0000-0000 0000-0000 0000-0010 0110-0001
PrintStream out = new PrintStream("print.txt");
out.write(610);//b ,只写最低8位
out.print(97);//97,将97先变成字符,保持原样形式打印到目的地。
out.close;

2、PrintWriter 字符打印流

/**
    构造函数参数:
    1、字符串路径
    2、File对象
    3、字节输出流
    4、字符输出流
*/


public class PrintWriterDemo1 {

    public static void main(String[] args) throws IOException {
        //键盘输入流
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

        //打印流,自动刷新缓冲区
        PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);

        String line = null;
        while((line = bufr.readLine()) != null) {
            if("over".equals(line))
                break;
            out.println(line.toUpperCase());
        }
        out.close();
        bufr.close();
    }

}

IO流 - 六、流的操作基本规律

转换流:

InputStreamReader:字节到字符的桥梁,解码。

OutputStramWriter:节符到字节的桥梁,编码。

操作规律:找到应该用哪些对象

1、明确源和目的

源:InputStream Reader

目的:OutputStream Writer

2、明确数据是否是纯文本数据

源:是纯文本数据:Reader;不是纯文本数据:InputStream

目的:是纯文本数据:Writer;是纯文本数据:OutputStream

3、明确具体的设备

源设备

硬盘:File
键盘:System.in
内存:数组
网络:Socket流

目的设备
硬盘:File
控制台:System.out
内存:数组
网络:Socket流

4、是否需要其它功能(装饰类)

1、高效缓冲区:Buffer

...

IO流 - 十三、IO流 - 文件切割合并

1、文件切割

public class SplitFile {

    private static final int SIZE = 1024*1024;

    public static void main(String[] args) throws IOException {
        //指定切割文件
        File file = new File("IMG_0215.JPG");

        //读取流
        FileInputStream fis = new FileInputStream(file);

        //写入流
        FileOutputStream fos = null;

        //缓冲区
        byte[] buf = new byte[SIZE];

        //存储目录
        File dir = new File("//Users//haojie//eclipse-workspace//hello world//partfiles");
        if(!dir.exists())
            dir.mkdir();

        //切割
        int length = 0;
        int count = 1;
        while((length = fis.read(buf)) != -1) {
            fos = new FileOutputStream(new File(dir,(count++)+".part"));
            fos.write(buf, 0, length);;
        }

        //关闭流
        fos.close();
        fis.close();
    }

}

2、文件合并

public class Merge {

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

        File dir = new File("//Users//haojie//eclipse-workspace//hello world//partfiles");
        mergeFile(dir);
    }

    public static void mergeFile(File dir) throws IOException {
        //读取流
        ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
        for(int x=1; x<3; 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,"1.JPG"));
        //缓冲区
        byte[] buf = new byte[1024];
        int length = 0;
        while((length = sis.read(buf)) != -1) {
            fos.write(buf, 0, length);
        }
        //关闭流
        fos.close();
        sis.close();
    }

}

3、文件切割合并+配置文件

public class FileSplitMergeUtil {

    private static final int SIZE = 1024*1024;

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

        //切割
        File file = new File("IMG_0215.JPG");
        splitFile(file);

        //合并
        File dir = new File("//Users//haojie//eclipse-workspace//hello world//partfiles");
        mergeFile(dir);
    }

    //切割传入的文件
    public static void splitFile(File file) throws IOException {

        //读取流
        FileInputStream fis = new FileInputStream(file);

        //写入流
        FileOutputStream fos = null;

        //缓冲区
        byte[] buf = new byte[SIZE];

        //存储目录
        File dir = new File("//Users//haojie//eclipse-workspace//hello world//partfiles");
        if(!dir.exists())
            dir.mkdir();

        //切割
        int length = 0;
        int count = 1;
        while((length = fis.read(buf)) != -1) {
            fos = new FileOutputStream(new File(dir,(count++)+".part"));
            fos.write(buf, 0, length);
            fos.close();
        }

        /**
         * 配置文件
         * partcount 碎片数量
         * filename 被切割文件名称
         */
        Properties prop = new Properties();

        //配置文件设置
        prop.setProperty("partcount", count+"");
        prop.setProperty("filename", file.getName());

        //配置文件输出流
        fos = new FileOutputStream(new File(dir,count+".properties"));

        //写入配置信息
        prop.store(fos, "fileinfo");

        //关闭流
        fos.close();
        fis.close();
    }

    public static void mergeFile(File dir) throws IOException {
        //过滤配置文件
        File[] files = dir.listFiles(new SuffixFilter(".properties"));
        if(files.length != 1)
            throw new RuntimeException(dir+"获取配置文件失败");
        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=0; x<partFiles.length; x++) {
            al.add(new FileInputStream(partFiles[x]));
        }

        //合并流
        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 length = 0;
        while((length = sis.read(buf)) != -1) {
            fos.write(buf, 0, length);
        }

        //关闭流
        fos.close();
        sis.close();
    }
}

public class SuffixFilter implements FilenameFilter {

    private String suffix;

    public SuffixFilter(String suffix) {
        super();
        this.suffix = suffix;
    }

    public boolean accept(File dir, String name) {
        return name.endsWith(suffix);
    }

}

IO流 - 十五、RandomAccessFile

随机访问文件,自身具备读写的方法。

通过skipBytes(int x),seek(int x)来达到随机访问。

特点:

1、不是IO体系中的子类。

2、该对象既能读也能写。

3、该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素。

4、可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置。

5、其实该对象就是将字节输入流和输出流进行了封装。

6、该对象的源或目的只能是文件。通过构造函数就可以看出。可以是文本文件,也可是媒体文件。

public class RandomAccessDemo1 {

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

        //randomWrite();

        randomRead();

    }

    public static void randomRead() throws FileNotFoundException, IOException {
        RandomAccessFile raf = new RandomAccessFile("ranacc.txt","r");
        //读4个字节,获取张三
        byte[] buf = new byte[4];
        raf.read(buf);
        String name = new String(buf);
        System.out.println("name="+name);

        //再读4个字节,读取年龄
        int age = raf.readInt();
        System.out.println("age="+age);

        //获取指针位置
        System.out.println("pos:"+raf.getFilePointer());//pos:8

        //设置指针位置,raf.seek(8);//随机读取,只要指定指针的位置即可

        raf.close();
    }

    public static void randomWrite() throws FileNotFoundException, IOException {
        RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw");

        raf.write("张三".getBytes());
        raf.writeInt(97);

        raf.close();
    }

}

随机写入&细节

//往指定位置写入数据

raf.seek(3*8);
raf.write("哈哈".getBytes());
raf.writeInt(108);
raf.close;

IO流 - 十六、管道流 - PipedStream

PipedInputStream和PipedOutputStream

输入输出可以直接进行连接,通过结合线程使用。

public class PipedStreamDemo1 {

    public static void main(String[] args) throws IOException {
        PipedInputStream input = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();
        input.connect(out);

        new Thread(new Input(input)).start();
        new Thread(new Output(out)).start();

    }

}

class Input implements Runnable {
    private PipedInputStream in;
    Input(PipedInputStream in) {
        this.in = in;
    }

    public void run() {
        try {
            byte[] buf = new byte[1024];
            int length = in.read(buf);
            String s = new String(buf,0,length);
            System.out.println("s="+s);
            in.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

class Output implements Runnable {
    private PipedOutputStream out;
    Output(PipedOutputStream out) {
        this.out = out;
    }

    public void run() {
        try {
            out.write("aaaaaaaaa".getBytes());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

IO流 - 十七、操作基本数据类型的流对象 - DataStream

DataInputStream与DataOutputStream

public class DataStream {

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

        writeData();
        readData();

    }

    private static void readData() throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("abc.txt"));
        String str = dis.readUTF();
        System.out.println(str);
        dis.close();
    }

    private static void writeData() throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("abc.txt"));
        dos.writeUTF("你好");
        dos.close();
    }

}

IO流 - 十八、操作数组的流

1、操作字节数组的流:

源和目的都是内存,没有调用底层资源,关闭流无效,关闭流后仍可用。

ByteArrayInputStream与ByteArrayOutputStream

public class ArrayStreamDemo1 {

    public static void main(String[] args) {

        ByteArrayInputStream bis = new ByteArrayInputStream("abcde".getBytes());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int ch = 0;
        while((ch = bis.read()) != -1) {
            bos.write(ch);
        }
        System.out.println(bos.toString());
    }

}

操作字符数组的流:

CharArrayInputStream与CharArrayOutputStream

操作字符串的流

StringReader与StringWriter

IO流 - 十二、序列流 - SequenceInputStream

对多个流进行合并

1、构造方法

SequenceInputStream(Enumeration<? extends InputStream> e)

public class demo1 {

    public static void main(String[] args) throws IOException {
        /**
         * 将1.txt,2.txt,3.txt文件中的数据合并到一个文件4.txt中
         */
        Vector<FileInputStream> v = new Vector<FileInputStream>();
        v.add(new FileInputStream("1.txt"));
        v.add(new FileInputStream("2.txt"));
        v.add(new FileInputStream("3.txt"));

        Enumeration<FileInputStream> en = v.elements();

        SequenceInputStream sis = new SequenceInputStream(en);

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

        byte[] buf = new byte[1024];

        int length = 0;

        while((length = sis.read(buf)) != -1 ) {
            fos.write(buf,0,length);
        }

        fos.close();
        sis.close();
    }

}

2、枚举和迭代

//Vctor集合效率低。

Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));

Enumeration<FileInputStream> en = v.elements();

//ArrayList集合代替
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
//用集合工具类中的方法,返回Enumeration类对象
Enumeration<FileInputStream> en = Collections.enumeration(al);

IO流 - 十四、IO流 - 对象的序列化、反序列化

ObjectInputStream与ObjectOutputStream

被操作的对象需要实现Serializable标记接口

1、ObjectOutputStream-对象序列化

将对象写到硬盘上。

FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeInt(12345);
oos.writeObject("Today");
oos.writeObject(new Date());

oos.close;

存储自定义对象时,要实现对象序列化,对象要实现Serializable接口

class Person implements Serializable{
    ...
}

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
oos.writeObject(new Person("小强",30));
oos.close;

2、ObjectInputStream-对象反序列化

读取存储在硬盘上的对象。

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“obj.object”));

Person p = ois.readObject();
System.out.println(p.getName()+p.getAge());

ois.close();

3、序列化接口 - Seriallizable

显示化序列号

class Person {
    private static final long serialVersionUID = 97274;
}

将对象存储到硬盘后,即使改动了Person类,依然能识别该类和取出的对象是同一个版本。

4、关键字 - transient

静态属性不会加入序列化写入到硬盘中。

非静态属性,如果不想写入到硬盘中,需要关键字transient(短暂的)修饰。

private static int age;

private transient String name;

都不会被序列化写入硬盘中。