Java基础——IO流

1、IO流
IO流:输入、输出流(针对的是内存和外围设备(硬盘)的数据交换)
外围设备到内存:输入(读)
内存到外围设备:输出(写)
字符流的由来:其实就是字节流读取文字字节数据后,不直接操作而是先指定的编码表,获取对应的文字
再对这个文字进行操作。简单的说:字节流+编码表。

字节流的两个顶层父类:
1、InputStream
2、OutputStream

字符流的两个顶层父类:
1、Reader
2、Writer

如果要操作文字数据,优先考虑字符流,将数据从内存写到硬盘上,要使用字符流中的输出流:Writer

字符流缓冲区:
BufferWriter
newLine():加入换行符
BufferReader
readLine():读取文本的一行
2、字符流的操作代码示例
2.1字符流读写操作

读操作

package cn.itcast.p2.io.filewriter;
//读文件的第一种方式
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
//      1、创建读取字符数据的流对象
        /*
         * 在创建读取流对象时,必须要明确被读取的文件,一定要确定该文件是存在的
         * 用一个读取流关联一个已存在文件
         * 
         * 
         * */
        FileReader fr=new FileReader("demo.txt");
        int ch;
//      用Reader中的read方法读取字符
//      int ch=fr.read();//每次只读取一个字符,而且是二进制(因为存在磁盘上的都是二进制格式的,由于前面int限制,所以返回的十进制数)
//      System.out.println(ch);//结果:97,读完之后返回的是-1
        while((ch=fr.read())!=-1) {
            System.out.println((char)ch);
        }

    }

}
package cn.itcast.p2.io.filewriter;
//读文件的第二种方式
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo2 {

    public static void main(String[] args) throws IOException {
        FileReader fr=new FileReader("demo.txt");

        /*使用read(char[])读取文本文件数据
         * 先创建字符数组
         * 
         * */
        /*char[]buf=new char[6];
        int num=fr.read(buf);//返回读取到字符数,并把字符存储到buf数组中
        System.out.println(num+":"+new String(buf));//结果:6:abcd(后面有两空格)
        int num1=fr.read(buf);
        System.out.println(num1+":"+new String(buf));//结果:6:adfalx(会把之前的覆盖掉)
        int num2=fr.read(buf);
        System.out.println(num1+":"+new String(buf));//6:ixixlx
        int num3=fr.read(buf);
        System.out.println(num3+":"+new String(buf));//-1:ixixlx(当读到-1直接返回)
*/              
        char[]buf=new char[1024];//一般设置1024的整数倍,以免反复执行下面的语句,提高效率
        int len;
        while((len=fr.read(buf))!=-1) {
            System.out.println(new String(buf,0,len));
        }
    }

}

写操作

package cn.itcast.p2.io.filewriter;
//写文字到硬盘
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {

    private static final String LINE_SEPARATOR = System.getProperty("line.separator");

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //创建一个可以往文件中写入字符数据的字符输出流对象
        /*
         * 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)
         * 如果文件不存在,则会自动创建
         * 如果文件存在,则会被覆盖
         * 
         * */
//      FileWriter fw=new FileWriter("demo.txt");
//      如果构造函数中加入true,可以实现对文件进行续写
        FileWriter fw=new FileWriter("demo.txt",true);
        /*
         * 调用Writer对象中的write(string)方法,写入数据
         * 其实数据写入到临时存储缓冲区中
         * */
//      fw.write("abcde");
        fw.write("abcd"+LINE_SEPARATOR+"adfal");//加入换行符
        fw.write("xixix");//续写入文件
        /*
         * 进行刷新,将数据直接写到目的地中
         * */
        fw.flush();
        /*
         * 关闭流,关闭资源,在关闭流的时候会先调用flush刷新缓冲区中的数据到目的地
         * */
        fw.close();
    }

}

2.1.1 读写实例代码

package cn.itcast.p2.io.filewriter;

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

public class CopyTextTest {
    /*
     * 将C盘中的一个文件复制到D盘
     * 思路:
     * 1、需要读取源
     * 2、将读到的原数据写入到目的地
     * 3、既然是操作文本数据,使用字符流
     * */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //1、读取一个已有的文本文件,使用字符读取流和文件相关联
        FileReader fr=new FileReader("笔记.txt");
        //2、创建一个目的地,用于存储读到数据
        FileWriter fw=new FileWriter("copytext_1.txt");
        //3、频繁的读写操作
        int ch=0;
        while((ch=fr.read())!=-1)
        {
            System.out.println(ch);
            fw.write(ch);
        }
        //4、关闭流资源
        fw.close();
        fr.close();
    }

}

读写异常捕捉

package cn.itcast.p2.io.filewriter;
//异常处理
import java.io.FileWriter;
import java.io.IOException;

public class IOExceptionDemo {

    private static final String LINE_SEPARATOR = System.getProperty("line.separator");

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FileWriter fw=null;//在外面声明
        try {
            fw = new FileWriter("demo.txt");//在里面初始化  位置1

            fw.write("abcd" + LINE_SEPARATOR + "adfal");//加入换行符  位置2

        } catch (IOException e) {
            // TODO: handle exception
            System.out.println(e.toString());
        }finally {
            if(fw!=null)//需要判断它是否为空才能进行下面的fw.close()操作,因为位置1抛出异常时(路径不存在),fw就不存在,为此它也会抛异常
                            //当有限制时,就可以很明确的捕捉到是否是位置2发生写入异常
                try {
                fw.close();//如果不再外面声明,此处就会报错,fw变量没被定义
            } catch (IOException e) {
                // TODO Auto-generated catch block
                throw new RuntimeException("关闭失败");
            }//
        }
    }

}
package cn.itcast.p2.io.filewriter;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyTextTest_2 {

    private static final int BUFFER_SIZE = 1024;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FileReader fr=null;
        FileWriter fw=null;
        try {
            fr=new FileReader("笔记.txt");
            fw=new FileWriter("copytest_2.txt");
            //创建一个临时容器,用于缓存读取到的字符
            char[] buf=new char[BUFFER_SIZE];
            //定义一个变量记录读取到的字符数(其实就是往数组里装的字符个数)
            int len=0;
            while((len=fr.read(buf))!=-1) {
                fw.write(buf, 0, len);
            }
        }
        catch(Exception e) {
            throw new RuntimeException("读写失败");
        }finally {
            if(fw!=null)
                try {
                    fw.close();
                }catch(IOException e) {

                }
            if(fr!=null)
                try {
                    fr.close();
                }catch(IOException e){

                }
        }
    }

}

获取文本的行号

package cn.itcast.p2.io.wrapper;

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

public class LineNumberReaderDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        FileReader fr=new FileReader("笔记.txt");
        LineNumberReader lnr=new LineNumberReader(fr);
        String line=null;
//      lnr.setLineNumber(100);//设置文本开始行
        while((line=lnr.readLine())!=null)
        {
            System.out.println(lnr.getLineNumber()+":"+line);//获取文本的行号

        }
        lnr.close();
    }

}

2.2字符流缓冲区读写操作

package cn.itcast.p2.io.charstream.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyTextByBufTest {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        FileReader fr=new FileReader("buf.txt");
        BufferedReader bufr=new BufferedReader(fr);

        FileWriter fw=new FileWriter("buf_copy2.txt");
        BufferedWriter bufw=new BufferedWriter(fw);
        String line=null;
        //按行读写
        while((line=bufr.readLine())!=null) {
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
        }

        /*int ch=0;
        while((ch=bufr.read())!=-1) {
            bufw.write(ch);
        }*/
        bufw.close();
        bufr.close();


    }

}
package cn.itcast.p2.io.charstream.test;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferWriterDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        FileWriter fw=new FileWriter("buf.txt");
        //为了提高写入的效率,使用了字符流的缓冲区
        //创建了一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联
        BufferedWriter bufw=new BufferedWriter(fw);
        //使用缓冲区的写入方法将数据先写入到缓冲区中
        bufw.write("abcd");
        bufw.newLine();//写入换行符(只是缓冲区对象有),封装的是System.getProperty("line.separator")
        bufw.write("afhsdnajkl"); 
        //使用缓冲区的刷新方法将数据刷到目的地中
        bufw.flush();
        //关闭缓冲区的(其实关闭的就是被缓冲的流对象)
        bufw.close();
    }

}
package cn.itcast.p2.io.charstream.test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
    demo(); 
    FileReader fr=new FileReader("buf.txt");
    BufferedReader bufr=new BufferedReader(fr);
    String line=null;
    while((line=bufr.readLine())!=null) {
        System.out.println(line);//读取文本的一行
    }
    bufr.close();
    }

    private static void demo() throws IOException {
        // TODO Auto-generated method stub
        FileReader fr=new FileReader("buf.txt");
        char[]buf=new char[1024];
        int len=0;
        while((len=fr.read(buf))!=-1) {
            System.out.println(new String(buf,0,len));
        }
        fr.close();
    }

}

2.2.1自定义缓冲区
自定义类

package cn.itcast.p2.io.charstream.mybuffer;

import java.io.FileReader;
import java.io.IOException;

/*
 * 自定义的读取缓冲区,其实就是模拟一个BufferedReader
 * 分析:
 * 缓冲区中无非就是封装了数组
 * 并对外提供了更多的方法对数组进行访问
 * 其实这些方法最终操作的都是数组的角标
 * 
 * 缓冲的原理:
 * 其实就是从源中获取一批数据装进缓冲区中
 * 再从缓冲区中不断的取出一个一个数据
 * 
 * 在此次取完后,再从源中继续取一批数据进缓冲区
 * 当源中的数据取光时,用-1作为结束标记
 * */
public class MyBufferReader {
    private FileReader r;
    //定义一个数组作为缓冲区
    private char[]buf=new char[1024];
    //定义一个指针用于操作这个数组中的元素,当操作到最后一个元素后,指针归零
    private int pos=0;
    //定义一个计数器用于记录缓冲区中的数据个数,当该数据减到0,就从源中继续获取数据到缓冲区中
    private int count=0;
    MyBufferReader(FileReader r) {
        this.r=r;
    }
    /*
     * 该方法从缓冲区中一次取一个字符
     * 
     * */
    public int myRead() throws IOException {
        if(count==0)
        {
            count=r.read(buf);
        }
        if(count<0)
            return -1;
        char ch=buf[pos++];
        count--;
        return ch;
        /*//1、从源中获取一批数据到缓冲区中,需先做判断,只有计数器为0时,才需要从源中获取数据
        if(count==0) {
            count=r.read(buf);
            if(count<-1) 
                return -1;
            //每次获取数据到缓冲区后,角标归零.
            pos=0;
            char ch=buf[pos];

            pos++;
            count--;
            return ch;
        }else if(count>0) {
            char ch=buf[pos];
            pos++;
            count--;
            return ch;
        }*/
    }
    public String myReadLine() throws IOException {
        StringBuilder sb=new StringBuilder();
        int ch=0;
        while((ch=myRead())!=-1) {
            if(ch=='\r') 
                continue;
            if(ch=='\n')
                return sb.toString();
            sb.append((char)ch);
        }
        if(sb.length()!=0)//没有这个的话,如果最后一行后面没有回车则最后一行打印不出来
            return sb.toString();
        return null;
    }
    public void myClose() throws IOException
    {
        r.close();
    }
}

自定义缓冲区应用

package cn.itcast.p2.io.charstream.mybuffer;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class MyBufferedReaderDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
//  demo(); 
    FileReader fr=new FileReader("buf.txt");
    MyBufferReader bufr=new MyBufferReader(fr);
    String line=null;
    while((line=bufr.myReadLine())!=null) {
        System.out.println(line);//读取文本的一行
    }
    bufr.myClose();
    }

    private static void demo() throws IOException {
        // TODO Auto-generated method stub
        FileReader fr=new FileReader("buf.txt");
        char[]buf=new char[1024];
        int len=0;
        while((len=fr.read(buf))!=-1) {
            System.out.println(new String(buf,0,len));
        }
        fr.close();
    }

}

3、字节流读写操作
3.1 字节流读写示例

package cn.itcast.p2.io.bytestream.demo;

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

public class ByteStreamDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        demo_write();
        demo_read();
    }
    private static void demo_read() throws IOException {
        // TODO Auto-generated method stub
        //创建一个读取流对象和指定文件关联
        FileInputStream fis=new FileInputStream("bytesdemo.txt");

        byte[]buf=new byte[fis.available()];//文件长度,少用,万一文件16个G,导致内存溢出
        fis.read(buf);
        System.out.println(new String(buf));


        //一次读取一个数组长度,建议使用这种
        /*byte[] buf=new byte[1024];
        int len=0;
        while((len=fis.read(buf))!=-1) {
            System.out.println(new String(buf,0,len));
        }*/



        /*//一次读取一个字节
        int ch=0; 
        while((ch=fis.read())!=-1)
        {
            System.out.println((char)ch);
        }*/

        fis.close();
    }
    private static void demo_write() throws IOException {
        // TODO Auto-generated method stub
//      1、创建字节输出流对象,用于操作文件
        FileOutputStream fos=new FileOutputStream("bytesdemo.txt");
//      2、写数据,直接写入到了目的地中
        fos.write("abcddasf".getBytes());
        fos.close();//关闭资源动作
    }


}

3.2 字节流缓冲区读写示例

package cn.itcast.p2.io.bytestream.demo;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyMp3Test {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        copy_1();
        copy_2();
    }
//使用缓冲区复制音频文件
    private static void copy_2() throws IOException {
        // TODO Auto-generated method stub
        FileInputStream fis=new FileInputStream("0.mp3");
        BufferedInputStream bufis=new BufferedInputStream(fis);

        FileOutputStream fos=new FileOutputStream("2.mp3");
        BufferedOutputStream bufos=new BufferedOutputStream(fos);

        int ch=0;
        while((ch=bufis.read())!=-1) {
            fos.write(ch); 
        }
        bufis.close();
        bufos.close();
    }


    private static void copy_1() throws IOException {
        // TODO Auto-generated method stub
        FileInputStream fis=new FileInputStream("0.mp3");
        FileOutputStream fos=new FileOutputStream("1.mp3");

        byte[]buf=new byte[1024];
        int len=0;
        while((len=fis.read(buf))!=-1) {
            fos.write(buf,0,len);
        }
        fos.close();
        fis.close();
    }

}

4 装饰设计模式
装饰设计模式:
对一组对象的功能进行增强时,就可以使用该模式进行问题的增强

装饰和继承都能事项一样的特点:进行功能的拓展。有什么区别呢?
首先有一个继承体系。
writer
|—TextWriter:用于操作文本
|—MediaWriter:用于操作媒体
想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展
效率提高需要加入缓冲技术

Writer
|—TextWriter:用于操作文本
|—BufferTextWriter:加入了缓冲技术的操作文本对象
|—MediaWriter:用于操作媒体
|—BufferMediaWriter:

如果这个体系进行功能扩展,有多个流对象
那么这个流要提高效率,是不是也要产生子类呢?这时就会发现只为提高功能进行的扩展
导致继承体系越来越臃肿,不够灵活

既然加入的都是同一种技术—缓冲
前一种是让缓冲和具体的对象相结合
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将那个对象和缓冲关联

class Buffer{
Buffer(TextWriter w)
{}
Buffer(MediaWriter w)
{}
}

装饰类:
class BufferWriter extends Writer{
BufferWriter(Writer w)
{
}
}

Writer
|—TextWriter:用于操作文本
|—MediaWriter:用于操作媒体
|—BufferWriter:用于提高效率
装饰比继承灵活
特点:装饰类和被装饰类都必须所属同一个接口或者父类

举例

package cn.itcast.p2.io.wrapper;

public class PersonDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Person p=new Person();
//      p.chifan();
        NewPerson p1=new NewPerson(p);
        p1.chifan();

        NewPerson2 p2=new NewPerson2();
        p2.chifan();
    }

}
class Person{
    void chifan() {
        System.out.println("吃饭");
    }
}
//这个类的出现是为了增强Person而出现的
class NewPerson{
    private Person p;
    NewPerson(Person p){
        this.p=p;
    }
    public void chifan() {
        System.out.println("开胃酒");
        p.chifan();
        System.out.println("甜点");
    }
}
//继承实现Person的增强
class NewPerson2 extends Person{
    public void chifan() {
        System.out.println("开胃酒");
        super.chifan();
        System.out.println("甜点");
    }
}

5、转换流操作

这里写图片描述

5.1 字节流和字符流之间的转换(没有使用转换流)

package cn.itcast.p1.transstream.demo;

import java.io.IOException;
import java.io.InputStream;

/*
 * 读取一个键盘录入的数据,并打印在控制台上
 * 键盘本身就是一个标准的输入设备
 * 对于Java而言,对于这种输入设备都有对应的对象
 * 
 * */
public class TransStreamDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
//      readKey();
        readKey2();
    }

    private static void readKey2() throws IOException {
        // TODO Auto-generated method stub
        /*
         * 获取用户键盘录入的数据
         * 并将数据变成大写显示在控制台上
         * 如果用户输入的是over,结束键盘录入
         * 
         * 思路:
         * 1、因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串
         * 2、那就需要一个容器,StringBuilder
         * 3、在用户回车之前将录入的数据变成字符串判断即可
         * 
         * */
//      1、创建容器
        StringBuilder sb=new StringBuilder();
//      2、获取键盘读取流
        InputStream in=System.in;
//      3、定义变量记录读取到的字节,并循环获取
        int ch=0;
        while((ch=in.read())!=-1) {
//          在存储之前需要判断是否是换行标记,因为换行标记不存储
            if(ch=='\r')
                continue;
            if(ch=='\n') {
                String temp=sb.toString();
                if("over".equals(temp))
                    break;
                System.out.println(temp.toUpperCase());
                sb.delete(0, sb.length());
            }
            else
//          将读取到的字节存储到StringBuilder中    
            sb.append((char)ch);
        }
        System.out.println(sb);
    }

    private static void readKey() throws IOException {
        // TODO Auto-generated method stub
        InputStream in=System.in;
        int ch=in.read();//阻塞式方法,没有数据就一直等
        System.out.println(ch);
//      in.close();//默认的输入设备和输出设备都不需要关闭,一旦关闭则整个
//      InputStream in=System.in;int ch=in.read();就会报错,这个流就不存在了,它是随着系统的关闭而消失的,系统运行而存在的(除非系统关了重启)
    }

}

5.2 转换流
转换流:
InputStreamReader:字节到字符的桥梁。解码
OutputStreamWriter:字符到字节的桥梁。编码
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道开发时用到哪些对象,只要通过四个明确即可。

1、明确源和目的(汇)
源:InputStream Reader
目的:OutputStream Writer

2、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系

3、明确具体的设备
源设备:
硬盘:File
键盘:System.in
内存:数组(缓冲区)
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流

4、是否需要其他额外功能
1、是否需要高效(缓冲区);
是,就加上buffer;

例如:
需求1:复制一个文本文件
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本
是!
源:Reader
目的:Writer
3、明确具体设备
源:
硬盘:File
目的:
硬盘:File
FileReader fr=new FileReader(“a.txt”)
FileWriter fw=new FileWriter(“b.txt”)
4、需要额外功能吗?
需要,需要高效
BufferedReader bufr=new BufferedReader(new FileReader(“a.txt”));
BufferedWriter bufw=new BufferedWriter(new FileWriter(“b.txt”));

需求2:将键盘输入数据存储到硬盘
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确是否是纯文本
是!
源:Reader
目的:Writer
3、明确具体设备
源:
键盘 System.in
目的地:
硬盘 File
InputStream in=System.in
FileWriter fw=new FileWriter(“a.txt”);
这样做可以完成,但是麻烦,将读取的字节数据转成字符串,再由字符流操作
4、需要额外功能吗?
需要。转换将字节流转成字符流。因为明确源是Reader,这样操作文本数据更加便捷
所以要将已有的字节流转成字符流,使用字节—》字符。InputStreamReader
InputStreamReader isr=new InputStreamReader(System.in);
FileWriter fw=new FileWriter(“b.txt”);
还需要功能吗?
需要高效!
BufferReader bufr=new BufferReader(new InputStreamReader(System.in));
BufferWriter bufw=new BufferWriter(FileWriter(“b.txt”));

需求3:将一个文本文件数据显示在控制台上
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确是否是纯文本
是!
源:Reader
目的:Writer
3、明确具体的设备
源:
硬盘 File
目的:
控制台 System.out

FileReader fr=new FileReader("b.txt");
OutputStream out=System.out;

4、是否需要额外功能
    需要转换.因为一个汉字是两个字节,输出是一个一个字节的输出转换成字符操作更加便捷
    FileReader fr=new FileReader("a.txt");
    OutputStreamWriter osw=new OutputStreamWriter(System.out);
    需要高效
    BufferedReader bfr=new BufferedReader(new FileReader("a.txt"));
    BufferedReader bfw=new BufferedWriter(new OutputStreamWriter(System.out));

需求4:读取键盘录入数据,显示在控制台上
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确是否是纯文本
是!
源:Reader
目的:Writer

3、明确设备
    源:
        键盘  System.in
    目的地:
        控制台 System.out
4、是否需要额外功能?
    需要转换,因为都是字节流,但是操作的确实文本数据
    所以使用字符流操作起来更为便捷
    InputStreamReader isr=new InputStreamReader(System.in);
    OutputStreamWriter osw=new OutputStreamWriter(System.out);
    为了将其高效
    BufferReader bufr=new BufferReader(new InputStreamReader(System.in));
    BufferWriter bufw=new BufferWriter(new OutputStreamWriter(System.out));

5、将一个中文字符串数据按照指定的编码表写入到一个文本文件中
    1、目的    OutputStream    writer
    2、是纯文本  Writer
    3、设备:硬盘 File
    FileWriter fw=new FileWriter("a.txt")
    fw.write("你好");
    注意:既然需求已经明确了指定编码表的动作
    那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地编码表
    只能使用其父类 OutputStreamWriter
    OutputStreamWriter接收一个字节输出流对象,既然是操作文本文件,那么该对象应该是FileOutputStream

    OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("a.txt"),编码名字);

    需要高效吗?
    BufferWriter bufw=new BufferWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),编码名字));

什么时候使用转换流呢?
1、源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁
提高对文本操作的便捷
2、一旦操作文本涉及到具体的指定编码表时,必须使用转换流

5.2.1 字节流转成字符流

package cn.itcast.p1.transstream.demo;

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

public class TransStreamDemo_2 {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
//      字节流
        InputStream in=System.in;
//      将字节转成字符的桥梁,转换流
        InputStreamReader isr=new InputStreamReader(in);
//      字符流
        BufferedReader bufr=new BufferedReader(isr);
        String line=null;
        while((line=bufr.readLine())!=null) {
            if("over".equals(line))
                break;
            System.out.println(line.toUpperCase());
        }
    }

}

缓冲区+转换流

package cn.itcast.p1.transstream.demo;

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

public class TransStreamDemo_3 {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
        String line=null;
        while((line=bufr.readLine())!=null) {
            if("over".equals(line))
                break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();
        }
    }

}

编码问题

这里写图片描述

package cn.itcast.p1.transstream.demo;

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.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

public class TransStreamDemo_5 {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        writeText();
        writeText_1();
        writeText_2();
        readText();
        readText_1();
    }

    private static void readText_1() throws IOException {
        // TODO Auto-generated method stub
//      用什么编码就用什么解码
        InputStreamReader isr=new InputStreamReader(new FileInputStream("gbk_2.txt"),"gbk");
        char[] buf=new char[10];
        int len=isr.read(buf);
        String str=new String(buf,0,len);
        System.out.println(str);
        isr.close();
    }

    private static void readText() throws IOException {
        // TODO Auto-generated method stub
        FileReader fr=new FileReader("gbk_2.txt");//因为编码是gbk,而默认编码是utf-8所以解码的时候乱码
        char[] buf=new char[10];
        int len=fr.read(buf);
        String str=new String(buf,0,len);
        System.out.println(str);
        fr.close();
    }

    private static void writeText_2() throws IOException {
        // TODO Auto-generated method stub
//      用utf-8进行编码其中的文本
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"utf-8");
        osw.write("你好");
        osw.close();
    }

    private static void writeText_1() throws IOException {
        // TODO Auto-generated method stub
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("gbk_2.txt"),"GBK");
        /*
         * FileWriter fw=new FileWriter("gbk_1.txt");
         * 这句代码和上面的功能是一样的
         * FileWriter:其实就是转换流指定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件
         *              简单说:操作文件的字节流+本机默认的编码表(utf-8)
         * 如果操作文本文件需要明确具体的编码。FileWriter就行不通了,它不能改变编码,只能使用转换流了
         * 
         * */
        osw.write("你好");
        osw.close();
    }

    private static void writeText() throws IOException {
        // TODO Auto-generated method stub
        FileWriter fw=new FileWriter("gbk_1.txt");
        fw.write("你好");
        fw.close();
    }

}

6、文件操作

6.1 封装成文件对象

package cn.itcast.p2.File.demo;

import java.io.File;

public class FileDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        constructorDemo();
    }

    private static void constructorDemo() {
        // TODO Auto-generated method stub
//      可以将一个已存在的或者不存在的文件或者目录封装成File文件对象
        File file=new File("a.txt");

//      以下两种方法和上面一样,只不过下面的将路径和文件名分开了,上面的可以使用绝对路径
        /*File f2=new File("c:\\","a.txt");

        File f=new File("c:\\");
        File f3=new File(f,"a.txt");*/
//      File.separator表示路径分割符:window下是:\\  Linux下是:\
        File f4=new File("c:"+File.separator+"abc"+File.separator+"a.txt");
        System.out.println(f4);
    }

}

6.2 文件的基本操作

package cn.itcast.p2.File.demo;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;

public class FileMethodDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        /*
         * File对象的常见方法
         *  1、获取
         *      1.1获取文件名称
         *      1.2获取文件路径
         *      1.3获取文件大小
         *      1.4获取文件修改时间
         *  2、创建与删除
         *      boolean 
         *  3、判断
         *  4、重命名
         * 
         * */
//      getDemo();
//      createAndDeleteDemo();
//      isDemo();
//      renameToDemo();
        listRootDemo();
    }

    private static void listRootDemo() {
        // TODO Auto-generated method stub
        File file=new File("d:\\");
        System.out.println("getFreeSpace:"+file.getFreeSpace());//打印空闲空间
        System.out.println("getTotalSpace:"+file.getFreeSpace());//打印总共空间
        System.out.println("getUsableSpace:"+file.getFreeSpace());//打印可用空间
//      File[]files=File.listRoots();
//      for(File file:files)
//          System.out.println(file);//打印根目录,即C:\ D:\ E:\  F:\

    }

    private static void renameToDemo() {
        // TODO Auto-generated method stub
        File f1=new File("a.txt");
        File f2=new File("aa.txt");
        boolean b=f1.renameTo(f2);//将a.txt重命名为aa.txt,如果是aa.txt和a.txt是不同的盘,则变成了剪切并重命名,a.txt不存在了,变成了其他盘的aa.txt
        System.out.println("b="+b);
    }

    private static void isDemo() {
        // TODO Auto-generated method stub
        File f=new File("a.txt");
//      boolean b=f.exists();//判断文件是否存在
//      System.out.println(b);
        System.out.println(f.isDirectory());//判断是否是目录
        System.out.println(f.isFile());//判断是否是文件,一般先判断是否存在再判断文件与否,假如不存在,则会返回false

    }

    private static void createAndDeleteDemo() throws IOException {
        // TODO Auto-generated method stub
        File file=new File("file.txt");
        /*
         * 和输出流不一样,如果文件不存在则创建,存在则不创建
         * */
//      boolean b=file.createNewFile();//创建新文件
//      System.out.println("b="+b);

        //创建目录
        /*File dir=new File("abc");
         * File dir1=new File("abc\\d\\d\cc");
        boolean b=dir1.mkdirs();//创建多级目录
        dir.mkdir();//创建单级目录
        System.out.println("b="+b);
        System.out.println(dir.delete());//删除目录,里面如果有文件则删不掉,删除多级目录时只删除了最里面的那个目录
        */

        boolean b=file.delete();//删除文件

    }

    private static void getDemo() {
        // TODO Auto-generated method stub
        File file=new File("a.txt");
        String name=file.getName();//获取文件名称
        String absPath=file.getAbsolutePath();//获取文件绝对路径
        String path=file.getPath();//获取相对路径
        long len=file.length();//获取文件大小
        long time=file.lastModified();//获取最近一次修改时间

        Date date=new Date(time);
        DateFormat dateFormat=DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
        String str_time=dateFormat.format(date);

        System.out.println("parent path:"+file.getParent());//获取文件的父目录
        System.out.println(name);
        System.out.println(absPath);
        System.out.println(path);
        System.out.println(len);
        System.out.println(time);
        System.out.println(str_time);
    }


}

6.3 过滤文件

过滤器

隐藏文件的过滤器

package cn.itcast.p2.filter;

import java.io.File;
import java.io.FileFilter;
import java.nio.file.Path;

public class FilterByHadden implements FileFilter {

    @Override
    public boolean accept(File pathname) {
        // TODO Auto-generated method stub
        return !pathname.isHidden();
    }

}

后缀名的过滤器(.java)

package cn.itcast.p2.filter;

import java.io.File;
import java.io.FilenameFilter;

public class filterByName implements FilenameFilter {

    @Override
    public boolean accept(File dir, String name) {
        // TODO Auto-generated method stub

        return name.endsWith(".java");
    }

}

后缀名的通用过滤器

package cn.itcast.p2.filter;

import java.io.File;
import java.io.FilenameFilter;

public class ShufflxFilter implements FilenameFilter {

    private String suffix;
    @Override
    public boolean accept(File dir, String name) {
        // TODO Auto-generated method stub

        return name.endsWith(suffix);
    }
    public ShufflxFilter( String suffix) {
        super();
        this.suffix=suffix;
        // TODO Auto-generated constructor stub
    }

}

过滤文件的代码示例

package cn.itcast.p2.File.demo;

import java.io.File;

import cn.itcast.p2.filter.FilterByHadden;
import cn.itcast.p2.filter.ShufflxFilter;

public class FileListDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
//      listDemo();
//      listDemo_2();
        listDemo_3();
    }

    private static void listDemo_3() {
        // TODO Auto-generated method stub
        File dir=new File("c:\\");
        File[]files=dir.listFiles(new FilterByHadden());
        for(File file:files) {
            System.out.println(file);
        }
    }

    private static void listDemo_2() {
        // TODO Auto-generated method stub
        File dir=new File("c:\\");
//      String[]names=dir.list(new filterByName());//过滤器
        String[]names=dir.list(new ShufflxFilter(".java"));//根据自定义后缀名过滤文件
        for(String name:names)
        {
            System.out.println(name);
        }
    }

    private static void listDemo() {
        // TODO Auto-generated method stub
        File file=new File("c:\\");
        /*
         * 获取当前目录的文件以及文件夹名称,包含隐藏文件
         * 调用list方法的File对象中封装的必须是目录
         * 否则会发生NullPointerException异常
         * 如果访问的是系统级目录也会发生指针异常
         * 如果目录存在但是没有内容,会返回一个数组,但是长度为0
         * 
         * */
        String[]names=file.list();//获取当前目录的文件以及文件夹名称,包含隐藏文件
        for(String name:names)
        {
            System.out.println(name);
        }
    }

}

获取目录下的文件

package cn.itcast.p2.File.test;

import java.io.File;

/*
 * 需求:对指定目录进行所有内容的列出(包含子目录中的内容)
 * 也可以理解为深度遍历
 * 
 * */
public class FileTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File dir=new File("I:\\");
        listAll(dir,0);
    }

    private static void listAll(File dir,int level) {
        // TODO Auto-generated method stub
//      获取指定目录下当前的所有文件夹或者文件对象
        File[]files=dir.listFiles();
        for(int x=0;x<files.length;x++) {
            if(files[x].isDirectory()) {
                listAll(files[x],level);
            }
            else    
                System.out.println(getSpace(level)+files[x].getName());
        }
    }

    private static String getSpace(int level) {
        // TODO Auto-generated method stub
        StringBuilder sb=new StringBuilder();
        for(int x=0;x<level;x++) {
            sb.append("|--");
        }
        return sb.toString();
    }

}

删除目录下的文件

package cn.itcast.p2.File.test;

import java.io.File;

/*
 * 删除一个带有内容的目录
 * 原理:必须从最里面往外删
 * 
 * 
 * */
public class RemoveDirTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File dir=new File("");
//      dir.delete();
        removeDir(dir);
    }

    private static void removeDir(File dir) {
        // TODO Auto-generated method stub
        File[]files=dir.listFiles();
        for(File file:files) {
            if(file.isDirectory()) {
                removeDir(file);
            }else {
                System.out.println(file+":"+file.delete());
            }
        }
        System.out.println(dir+":"+dir.delete());
    }

}

7 Properties
7.1 Properties基本操作

package cn.itcast.p2.properties;

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 {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        /*
         * Map
         *  |--Hashtable
         *      |--Properties:
         * 
         * Properties集合:
         * 特点:
         * 1、该集合中的键和值都是字符串类型
         * 2、集合中的数据保存到流中,或者从流获取(字节流、字符流都行)
         * 
         * 通常该集合用于操作以键值对形式存在的配置文件
         * 
         * 
         * 
         * */
//      propertiesDemo();
//      methodDemo();
//      methodDemo_2();
//      methodDemo_3();
        methodDemo_4();
    }
    private static void methodDemo_4() throws IOException {
        // TODO Auto-generated method stub
//      对已有的配置文件中的信息进行修改
        /*
         * 读取这个文件
         * 并将这个文件中的键值数据存储到集合中
         * 再通过集合对数据进行修改
         * 再通过流将修改后的数据存储到文件中
         * */
        File file=new File("info.txt");
        if(!file.exists()) {
            file.createNewFile();
        }
        FileReader fr=new FileReader(file);
//      FileWriter fw=new FileWriter(file);//放到这个位置里面将只有wangwu=16这一条信息
//      创建集合存储配置信息
        Properties prop=new Properties();
//      将流中信息存储到集合中
        prop.load(fr);
        prop.setProperty("wangwu", "16");
//      创建输出流
        FileWriter fw=new FileWriter(file);//因为这个file也就是info.txt是新建的(覆盖了之前的info.txt),将集合中的所有信息输出到里头
//      将集合中的信息存储到输出流中
        prop.store(fw, "modify wangwu");
        fw.close();
        fr.close();
    }
    private static void methodDemo_3() throws IOException {
        // TODO Auto-generated method stub
        Properties prop=new Properties();
//      集合中的数据来自于一个文件
//      注意:必须保证该文件中的数据是键值对
//      需要使用到读取流
        FileInputStream fis=new FileInputStream("info.txt");
//      使用load方法
        prop.load(fis);

        prop.list(System.out);
    }
    private static void methodDemo_2() throws IOException {
        // TODO Auto-generated method stub
        Properties prop=new Properties();
//      存储元素
        prop.setProperty("zhangsan", "30");
        prop.setProperty("lisi", "31");
        prop.setProperty("wangwu", "26");
        prop.setProperty("zhaoliu", "20");

//      想要将这些集合中的字符串键值信息持久化存储到文件中
//      需要关联输出流
        FileOutputStream fos=new FileOutputStream("info.txt");
//      将集合中数据存储到文件中,使用Store方法
        prop.store(fos, "name+age");
        fos.close();

    }
    private static void methodDemo() {
        // TODO Auto-generated method stub
//      演示Properties集合和流对象相结合的功能
        Properties prop=new Properties();
//      存储元素
        prop.setProperty("zhangsan", "30");
        prop.setProperty("lisi", "31");
        prop.setProperty("wangwu", "26");
        prop.setProperty("zhaoliu", "20");

        prop.list(System.out);//将存储的元素打印输出到控制台

    }
    /*
     * Properties集合的存和取
     * 
     * 
     * */

    private static void propertiesDemo() {
        // TODO Auto-generated method stub
//      创建一个Properties集合
        Properties prop=new Properties();
//      存储元素
        prop.setProperty("zhangsan", "30");
        prop.setProperty("lisi", "31");
        prop.setProperty("wangwu", "26");
        prop.setProperty("zhaoliu", "20");
//      修改元素
        prop.setProperty("wangwu", "36");
//      取出所有元素
        Set<String>names=prop.stringPropertyNames();
        for(String name:names) {
            String value=prop.getProperty(name);
            System.out.println(name+":"+value);
        }
    }

}

7.2 Properties案例示例

package cn.itcast.p2.properties;

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;

/*
 * 获取指定目录下,指定扩展名的文件(包含子目录中的)
 * 这些文件的绝对路径写入到一个文本文件中
 * 
 * 简单的说,就是建立一个指定扩展名的文件的列表
 * 
 * 思路:
 * 1、必须进行深度遍历
 * 2、要在遍历的过程中进行过滤,将符合条件的内容都存储到容器中
 * 3、对容器中的内容进行遍历并将绝对路径写入到文件中
 * 
 * 
 * */
public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File dir=new File("J:\\协同中心");
        FilenameFilter filter=new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                // TODO Auto-generated method stub

                return name.endsWith(".xlsx");
            }

        };
        List<File>list=new ArrayList<File>();
        getFiles(dir,filter,list);
        File destfile=new File(dir,"javalist.txt");
        writerToFile(list,destfile);
    }

    private static void getFiles(File dir,FilenameFilter filter,List<File>list) {
        // TODO Auto-generated method stub
        File[]files=dir.listFiles();
        for(File file:files) {
            if(file.isDirectory()) {
                getFiles(file,filter,list);
            }else {
//              对过滤器进行过滤,将符合条件的对象存储到集合中
                if(filter.accept(dir, file.getName())) {
                    list.add(file);
                }
            }
        }
    }
    public static void writerToFile(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) {
                // TODO Auto-generated catch block
                throw new RuntimeException("写入失败");
            }finally {
                if(bufw!=null)
                    try {
                        bufw.close();
                    }catch(IOException e){
                        throw new RuntimeException("关闭失败");
                    }
            }

    }
}
package cn.itcast.p2.properties;

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

/*
 * 定义功能,获取一个应用程序运行的次数,如果超过5次,给出使用次数已到请注册的提示,并终止程序的运行
 * 思路:
 * 1、应该有计数器
 * 每次程序启动都需要计数一次,并且是在原有的次数上进行计数
 * 2、计数器就是一个变量,程序启动时进行计数,计数器必须存在于内存并进行运算
 * 可是程序一结束,计数器就消失了,那么再次启动该程序,计数器又被重新初始化了
 * 而我们需要多次启动同一个应用程序,使用的是同一个计数器
 * 这就需要计数器的生命周期变长,从内存存储到硬盘文件中
 * 3、如何使用计数器呢?
 *  首先,程序启动时,应该先读取这个用于记录计数器信息的配置文件,获取上一次计数器次数
 *  其次,对该次数进行自增,并将自增后的次数重新存储到配置文件中。
 * 4、文件中的信息该如何进行存储并体现?
 * 直接存储次数值可以,但是不明确该数据的含义。所以起名字变得很重要
 * 这就有了名字和值的对应,所以可以使用键值对
 * 映射关系可以使用map集合搞定,由于又需要读取硬盘上的数据,所以用map+io=properties搞定
 * 
 * */

public class PropertiesTest {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        getAppCount();
    } 

    private static void getAppCount() throws IOException {
        // TODO Auto-generated method stub
//      将配置文件封装成File对象
        File confile=new File("count.properties");
        if(!confile.exists()) {
            confile.createNewFile();
        }
        FileInputStream fis=new FileInputStream(confile);
        Properties prop=new Properties();
        prop.load(fis);
//      从集合中通过键获取次数
        String value=prop.getProperty("time");
//      定义计数器,记录获取到的次数
        int count=0;
        if(value!=null) {
            count=Integer.parseInt(value);
            if(count>=5) {
                System.out.println("使用次数已到,请注册");
                throw new RuntimeException();
            }
        }
        count++;
//      将改变后的次数重新存储到集合中
        prop.setProperty("time", count+"");
        FileOutputStream fos=new FileOutputStream(confile);
        prop.store(fos, "");
        fos.close();
        fis.close();
    }

}

8 其他流
8.1 打印流

package cn.itcast.p2.print.demo;

import java.io.FileNotFoundException;
import java.io.PrintStream;

public class PrintDemo {

    public static void main(String[] args) throws FileNotFoundException {
        // TODO Auto-generated method stub
        /*
         * PrintStream:
         * 1、提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式
         * 2、它不抛IOException
         * 
         * 构造函数,接收三种类型的值:
         * 1、字符串路径
         * 2、File对象
         * 3、字节输出流
         * 
         * */
        PrintStream out=new PrintStream("print.txt");
//      out.write(97);//只将低8为转成字符写入进去
        out.print(97);//将97先变成字符保持原样将数据打印到目的地
        out.close();
    }

}
package cn.itcast.p2.print.demo;

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

public class PrintWriterDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        /*
         * PrintWriter:字符打印流
         * 构造函数参数:
         * 1、字符串路径
         * 2、File对象
         * 3、字节输出流
         * 4、字符输出流
         * 
         * */
        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
//      PrintWriter out=new PrintWriter(System.out,true);//加了true可以自动刷新(相当于位置1的功能)
        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.flush();//位置1
        }
        out.close();
        bufr.close();

    }

}

8.2 序列流

package cn.itcast.p2.print.demo;

import java.io.FileInputStream;
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;

public class SequenceInputStreamDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        /*
         * 需求:将1.txt 2.txt 3.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();*/
//      上面方法也可,建议用下面的
        ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
        for(int x=1;x<=3;x++) {
            al.add(new FileInputStream(x+".txt"));
        }
        Enumeration<FileInputStream>en=Collections.enumeration(al);//将列表转成枚举

        SequenceInputStream sis=new SequenceInputStream(en);//序列流需传一个枚举
        FileOutputStream fos=new FileOutputStream("4.txt");

        byte[]buf=new byte[1024];
        int len=0;
        while((len=sis.read(buf))!=-1) {
            fos.write(buf,0,len);
        }
        fos.close();
        sis.close();
    }

}

8.2.1 序列流案例示例

文件切割

package cn.itcast.io.p1.splitfile;

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

public class SplitFileDemo {

    private static final int SIZE = 1024*1024;

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //切割文件
        File file=new File("J:\\01.mp3");
//      splitFile(file);
//      文件切割+配置文件
        splitFile_2(file);
    }

    private static void splitFile_2(File file) throws IOException{
        // TODO Auto-generated method stub
//      用读取流关联源文件
        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("J:\\partfiles");
        if(!dir.exists())
            dir.mkdirs();
        while((len=fis.read(buf))!=-1) {
            fos=new FileOutputStream(new File(dir,(count++)+".part"));
            fos.write(buf,0,len);
            fos.close();
        }
//      将被切割文件的信息保存到prop集合中
        prop.setProperty("partcount", count+"");
        prop.setProperty("filename", file.getName());


        fos=new FileOutputStream(new File(dir,count+".properties"));
//      将prop集合中的数据存储到文件中
        prop.store(fos, "save file info");

        fos.close();
        fis.close();
    }

    private static void splitFile(File file) throws IOException {
        // TODO Auto-generated method stub
//      用读取流关联源文件
        FileInputStream fis=new FileInputStream(file);
//      定义一个1M的缓冲区
        byte[]buf=new byte[SIZE];
//      创建目的
        FileOutputStream fos=null;
        int len=0;
        int count=1;
        File dir=new File("J:\\partfiles");
        if(!dir.exists())
            dir.mkdirs();
        while((len=fis.read(buf))!=-1) {
            fos=new FileOutputStream(new File(dir,(count++)+".part"));
            fos.write(buf,0,len);
        }
        fos.close();
        fis.close();
    }

}

文件合并

过滤器

package cn.itcast.io.p1.splitfile;

import java.io.File;
import java.io.FilenameFilter;

public class SuffixFilter implements FilenameFilter {

    private String suffix;
    @Override
    public boolean accept(File dir, String name) {
        // TODO Auto-generated method stub
        return name.endsWith(suffix);
    }
    public SuffixFilter(String suffix) {
        super();
        this.suffix = suffix;
    }

}

合并

package cn.itcast.io.p1.splitfile;

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

public class MergeFileDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //合并文件
        File dir=new File("J:\\partfiles");
//      mergeFile(dir);
        mergeFile_2(dir);
    }

    private static void mergeFile_2(File dir) throws IOException {
        // TODO Auto-generated method stub
//      获取指定目录下的配置文件对象
        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("碎片文件不符合要求,个数不对!应该"+count+"个");

        }
//      将碎片文件和流对象关联并存储到集合中
        ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
        for(int x=1;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 len=0;
        while((len=sis.read(buf))!=-1) {
            fos.write(buf, 0, len);
        }
        fos.close();
        sis.close();
    }

    private static void mergeFile(File dir) throws IOException {
        // TODO Auto-generated method stub
        ArrayList<FileInputStream>al=new ArrayList<FileInputStream>();
        for(int x=1;x<8;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,"02.mp3"));
        byte[] buf=new byte[1024];
        int len=0;
        while((len=sis.read(buf))!=-1) {
            fos.write(buf, 0, len);
        }
        fos.close();
        sis.close();
    }

}

8.2.2 对象序列化和反序列化

Person类实现Serializable接口

package cn.itcast.io.p2.bean;

import java.io.Serializable;
/*
 * Serializable用于给序列化的类加入ID号
 * 用于判断类和对象是否是同一个版本
 * transient:非静态数据不想被序列化可以使用这个关键字修饰
 * 
 * 
 * */
public class Person implements Serializable/*标记接口*/{

    private static final long serialVersionUID=95271;//如果不自定义这个ID的话,系统会根据类型等自动算出一个ID,但这个根据编译器版本算出有所差异,所以
                                                    //可能导致,在不同编译器下序列化的文件,在另一个版本编译器下不能被反序列化(序列化和反序列化的时候它需要校正这个ID)
                                                    //为此,如果你将某个对象序列化后,然后将这个类中的private String name;改成public String name它也不能被反序列化,ID号变了
    private String name;
//  private transient String name;//不会被序列化
//  private static int age;//静态数据的值不会被序列化,比如这个反序列化回来就是0(它在静态去,对象在堆区)
    private int 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;
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }


}

对象序列化和反序列化

package cn.itcast.io.p1.splitfile;

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

import cn.itcast.io.p2.bean.Person;

public class objectStreamDemo {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        // TODO Auto-generated method stub
        writeObject();
        readObject();

    }
    private static void readObject() throws FileNotFoundException, IOException, ClassNotFoundException {
        // TODO Auto-generated method stub
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.object"));
//      对象的反序列化
        Person p=(Person)ois.readObject();
        System.out.println(p.getName()+":"+p.getAge());
        ois.close();

    }
    private static void writeObject() throws FileNotFoundException, IOException {
        // TODO Auto-generated method stub

        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("obj.object"));
//      对象序列化,被序列化的对象必须实现Serializable接口
        oos.writeObject(new Person("小强",30));
        oos.close();

    }

}

9 其他流的读写

这里写图片描述

9.1 文件随机读写

package cn.itcast.io.p1.splitfile;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        /*
         * RandomAccessFile不是io体系中的子类
         * 特点:
         * 1、该对象既能读又能写
         * 2、该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素
         * 3、可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置
         * 4、其实该对象就是将字节输入流和输出流进行了封装
         * 5、该对象的源和目的只能是文件(文本文件、媒体文件都可)
         * 
         * */
        writeFile();
        readFile();
        randomWrite();
    }
private static void randomWrite() throws IOException {
        // TODO Auto-generated method stub
        RandomAccessFile raf=new RandomAccessFile("ranacc.txt","rw");
//      raf.write("赵六".getBytes());//这样的话就覆盖了之前数组里的张三和102(因为文件存在,它不会重新创建,也就是该数组存在,只会覆盖)
//      raf.writeInt(102);
//      往指定位置写入数据
        raf.seek(5*8);//定位指针位置
        raf.write("哈哈".getBytes());
        raf.writeInt(108);

        raf.close();
    }
private static void readFile() throws IOException {
        // TODO Auto-generated method stub
        RandomAccessFile raf=new RandomAccessFile("ranacc.txt","r");

//      通过seek设置指针的位置
//      raf.seek(1*8);//将指针移到第8个字节的位置


        byte[]buf=new byte[6];//因为系统编码是utf-8,所以一个汉字是三个字节存储的,为此这里是6,如果变成4,则后面那个字是乱码
        raf.read(buf);

        String name=new String(buf);

        int age=raf.readInt();
        System.out.println("name="+name);
        System.out.println("age="+age);
        System.out.println("pos:"+raf.getFilePointer());//获取指针当前位置
        raf.close();
    }
//  使用RandomAccessFile对象写入一些人员信息,比如姓名和年龄

    private static void writeFile() throws IOException {
        // TODO Auto-generated method stub
        //如果文件不存在,则创建,如果文件存在,不创建
        RandomAccessFile raf=new RandomAccessFile("ranacc.txt","rw");

        raf.write("张三".getBytes());//写入的是字节
//      raf.write(97);//只写低8位
        raf.writeInt(908);//都写入
        raf.close();

    }


}

9.2 基本数据类型的读写

package cn.itcast.io.p3.dataStream;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataStreamDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
//      操作基本数据类型的流
        writeData();
        readData();
    }

    private static void readData() throws IOException {
        // TODO Auto-generated method stub
        DataInputStream r=new DataInputStream(new FileInputStream("data.txt"));
        System.out.println(r.readUTF());
        r.close();
    }

    private static void writeData() throws IOException {
        // TODO Auto-generated method stub
        DataOutputStream dis =new DataOutputStream(new FileOutputStream("data.txt"));
        dis.writeUTF("你好");//修改版的utf-8,前面有一个标识符
        dis.close();
    }

}

9.3 字节数组读写

package cn.itcast.io.p3.byteStream;

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

public class byteStreamDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ByteArrayInputStream bis=new ByteArrayInputStream("abcd".getBytes());
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        int len=0;
        while((len=bis.read())!=-1) {
            bos.write(len);
        }
        System.out.println(bos.toString());
    }

}

9.4 管道流读写

package cn.itcast.io.p1.piped;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class pipedDemo {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        PipedInputStream input=new PipedInputStream();
        PipedOutputStream output=new PipedOutputStream();
        input.connect(output);//输入流连接输出流
        new Thread(new Input(input)).start();
        new Thread(new Output(output)).start();

    }

}
class Input implements Runnable{
    private PipedInputStream in;
    Input(PipedInputStream in){
        this.in=in;
    }
    public void run() {
        try {
            byte[]buf=new byte[1024];
            int len=in.read(buf);
            String s=new String(buf,0,len);
            System.out.println("s="+s);
            in.close();
        }catch(Exception e) {

        }
    }
}
class Output implements Runnable{
    private PipedOutputStream out;
    Output(PipedOutputStream out){
        this.out=out;
    }
    public void run() {
        try {
            out.write("hi,管道来了".getBytes());
        }catch(Exception e) {

        }
    }
}

10. 编码解码
10.1 编码解码解析

package cn.itcast.io.p4.encode;

import java.io.UnsupportedEncodingException;

public class EncodeDemo {

    public static void main(String[] args) throws UnsupportedEncodingException {
        // TODO Auto-generated method stub
        /*
         * 字符串--->字节数组:编码
         * 字节数组--->字符串:解码
         * 
         * */
        String str="你好";
//      编码
        byte[]buf=str.getBytes();
//      byte[]buf=str.getBytes("GBK");//指定为GBK编码
//      printBytes(buf);
//      解码
        String s1=new String(buf);//默认方式解码
//      String s1=new String(buf,"utf-8");//指定码表解码
        System.out.println("s1="+s1);
        errorEncode();

    }

    private static void errorEncode() throws UnsupportedEncodingException {
        // TODO Auto-generated method stub
        /*
         * 如果编码编错了,解不出来
         * 如果编码对了,解错了,有可能有救
         * */
        String str="你好";
        byte[]buf=str.getBytes();
        String s1=new String(buf,"iso8859-1");//编码是utf-8,用iso8859-1解码
        System.out.println("s1="+s1);//结果:s1=ä½ å¥½

        byte[]buf2=s1.getBytes("iso8859-1");//获取源字节
        String s2=new String(buf2,"utf-8");
        System.out.println("s2="+s2);

    }

    private static void printBytes(byte[] buf) {
        // TODO Auto-generated method stub
        for(byte b:buf) {
            System.out.println(b);
        }
    }

}

10.2 编码解码案例

package cn.itcast.io.p4.encode;

import java.io.UnsupportedEncodingException;

public class Test {

    public static void main(String[] args) throws UnsupportedEncodingException {
        // TODO Auto-generated method stub
        /*
         * 在java中,字符串"abcd"与字符串"ab你好"的长度是一样,都是四个字节。
         * 但对应的字节数不同,一个汉字占两个字节
         * 定义一个方法,按照最大的字节数来取字串
         * 如:对于"ab你好",如果取三个字节,那么子串就是ab与"你"字的半个
         * 那么半个就要舍弃,如果取四个字节就是"ab你",取五个字节还是"ab你"
         * 
         * */
        String str="ab你好cd谢谢";
        int len=str.getBytes("GBK").length;
        for(int x=0;x<len;x++) {
            System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByte(str,x+1));
        }

    }

    private static String cutStringByte(String str,int len) throws UnsupportedEncodingException {
        // TODO Auto-generated method stub
        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,"gbk");//将buf里的从0到len长度的字节码按GBK解码
        else
            return new String(buf,0,len-1,"gbk");
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值