欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java基础——IO流

程序员文章站 2024-03-04 22:01:36
...

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、转换流操作

Java基础——IO流

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();
        }
    }

}

编码问题

Java基础——IO流

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 其他流的读写

Java基础——IO流

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");
    }

}
相关标签: java