基础IO流

 

大家好
今天给大家分享一下可能会用到的知识点:

基础IO流

 

 

1.背景介绍

流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。

数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

2.知识剖析

IO流的分类

 

根据处理数据类型的不同分为:字符流和字节流

根据数据流向不同分为:输入流和输出流

 

 

字符流和字节流

字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

 

输入字节流InputStream:

InputStream 是所有的输入字节流的父类,它是一个抽象类。

ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。

ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

 

字节流和字符流的区别:

 

读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

 

 

输入流和输出流

对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。

 

 

Reader 是所有的输入字符流的父类,它是一个抽象类。

CharReader、StringReader 是两种基本的介质流,它们分别从Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。

BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。

InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。

 

 

Writer 是所有的输出字符流的父类,它是一个抽象类。

CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,

BufferedWriter 是一个装饰器为Writer 提供缓冲功能。

PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。

OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究SourceCode)。功能和使用和OutputStream 极其类似。

 

 

3.常见问题

字符流是否可以操作字节,如拷贝图片?

 

4.解决方案

public class CopyImageWithReader {



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

            Test();
        }
        public static void Test() throws IOException{

            File fileFrom = new File("D:\\yuanpan\\tuppppppp\\动漫里的风景也是风景\\030.jpg");
            File fileTo = new File("D:\\cc\\tupian\\result2.jpg");
            //建立数据的输入输出通道
            FileReader input = new FileReader(fileFrom);

            //每新创建一个FileOutputStream的时候,默认情况下FileOutputStream 的指针是指向了文件的开始的位置。 每写出一次,指向都会出现相应移动。
            FileWriter output = new FileWriter(fileTo);

            //建立缓冲数据,边读边写
            //如果传入了缓冲数组,内容是存储到缓冲数组中,返回值是存储到缓冲数组中的字节个数。
            int length = 0;

            char[] buf = new char[1024];  //一字节一字节的拷贝
            while((length = input.read(buf))!=-1){

                output.write(buf,0,length);

            }
            System.out.println("字节数组读取的内容:"+ Arrays.toString(buf));
            //关闭资源原则:先开后关,后开先关
            output.close();
            input.close();
        }


}

经过验证拷贝图片是不行的。发现丢失了信息。

 

 

计算机中的所有信息都是以二进制形式进行的存储(1010)图片中的也都是二进制在读取文件的时候字符流自动对这些二进制按照码表进行了编码处理,但是图片本来就是二进制文件,不需要进行编码。有一些巧合在码表中有对应,就可以处理,并不是所有的二进制都可以找到对应的。信息就会丢失。所以字符流只能拷贝以字符为单位的文本文件(以ASCII码为例是127个,并不是所有的二进制都可以找到对应的ASCII,有些对不上的,就会丢失信息。

 

 

5.编码实战

将一个视频分成5兆5兆的每份。然后再合并。

 

/*

 需求: 把一首mp3先切割成n份,然后再把这些文件合并起来。

 */

public class cutmergeFile {

    public static void main(String[] args) throws IOException {
        //cutFile();
        mergeFile();

    }

    //合并
    public static void  mergeFile() throws IOException{
        //找到目标文件
        File dir = new File("D:\\cc\\target");
        //通过目标文件找到所有的MP3文件,然后把所有的MP3文件添加到Vector中。
        Vector<FileInputStream> vector = new Vector<FileInputStream>();
        File[] files = dir.listFiles();
        for(File file : files){
            if(file.getName().endsWith(".mp4")){
                vector.add(new FileInputStream(file));
            }
        }
        //通过Vector获取迭代器
        Enumeration e = vector.elements();
        //创建序列流
        SequenceInputStream inputStream = new SequenceInputStream(e);
        //建立文件的输出通道
        FileOutputStream output = new FileOutputStream("D:\\cc\\aa\\我可以.mp4");
        //建立缓冲数组读取文件
        int length = 0;
        byte[] buf = new byte[1024*5];
        while((length = inputStream.read(buf))!=-1){
            output.write(buf,0,length);
        }
        //关闭资源
        output.close();
        inputStream.close();

    }



    //切割
    public static void cutFile() throws IOException{
        File infile = new File("D:\\yuanpan\\MMMMMV\\我可以--音悦Tai.mp4");
        //目标文件夹
        File dir = new File("D:\\cc\\target");
        //建立数据的输入通道
        FileInputStream input = new FileInputStream(infile);
        //建立缓冲数组读取
        int length =0;
        byte[] buf = new byte[1024*1024*5];

        for(int i = 1; (length = input.read(buf))!=-1; i++ ){
            FileOutputStream fileoutputstream = new FileOutputStream(new File(dir,"vedio"+i+".mp4"));
            fileoutputstream.write(buf,0,length);
            fileoutputstream.close();
        }
        input.close();

    }



    //自己写的合并文件代码,有点冗长啊
    //我把里面的文件删了,想运行的话记得改路径
    public static void Test3() throws IOException{

        File file = new File("e:\\Test\\操你妈.mp3");
        File file1 = new File("D:\\cc\\byu\\01.mp3");
        File file2 = new File("D:\\cc\\byu\\02.mp3");
        File file3 = new File("D:\\cc\\byu\\03.mp3");
        File file4 = new File("D:\\cc\\byu\\04.mp3");
        File file5 = new File("D:\\cc\\byu\\05.mp3");

        FileOutputStream output = new FileOutputStream(file);
        FileInputStream input1 = new FileInputStream(file1);
        FileInputStream input2 = new FileInputStream(file2);
        FileInputStream input3 = new FileInputStream(file3);
        FileInputStream input4 = new FileInputStream(file4);
        FileInputStream input5 = new FileInputStream(file5);
        //其实下面可以直接遍历的
        Vector<FileInputStream> vector = new Vector();
        vector.add(input1);
        vector.add(input2);
        vector.add(input3);
        vector.add(input4);
        vector.add(input5);
        Enumeration<FileInputStream> e = vector.elements();

        SequenceInputStream sequenceinputstream = new  SequenceInputStream(e);
        int length = 0;
        byte[] buf = new byte[1024*1024];
        while((length = sequenceinputstream.read(buf))!=-1){
            output.write(buf,0,length);
        }
        output.close();
        sequenceinputstream.close();

    }

    //全靠自己写得到代码。分割文件.分割后我自己检查了下,文件并没有增多或减少。
    public static void Test1() throws IOException{

        File infile = new File("e:\\Test\\伍佰- 夏夜晚风.mp3");
        File[] outfile = {new File("D:\\cc\\byu\\01.mp3"),new File("D:\\cc\\byu\\02.mp3"),new File("D:\\cc\\byu\\03.mp3"),new File("D:\\cc\\byu\\04.mp3"),new File("D:\\cc\\byu\\05.mp3")};

        FileInputStream input = new FileInputStream(infile);
        FileOutputStream[] output = {new FileOutputStream(outfile[0]),new FileOutputStream(outfile[1]),new FileOutputStream(outfile[2]),new FileOutputStream(outfile[3]),new FileOutputStream(outfile[4])};

        int length = 0;
        int content = 0;
        byte[] buf = new byte[1024*1024];

        for(int i = 0;i<5; i++){
            length = input.read(buf);
            output[content].write(buf,0,length);
            output[content].close();
            content++;
        }
        input.close();
    }
}

复制图片,用字节流

 

 

public class CopyImage {

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

      Test();
   }
   public static void Test() throws IOException{

      File fileFrom = new File("D:\\yuanpan\\tuppppppp\\动漫里的风景也是风景\\030.jpg");
      File fileTo = new File("D:\\cc\\tupian\\result.jpg");
      //建立数据的输入输出通道
      FileInputStream input = new FileInputStream(fileFrom);

      //每新创建一个FileOutputStream的时候,默认情况下FileOutputStream 的指针是指向了文件的开始的位置。 每写出一次,指向都会出现相应移动。
      FileOutputStream output = new FileOutputStream(fileTo);

      //建立缓冲数据,边读边写
      //如果传入了缓冲数组,内容是存储到缓冲数组中,返回值是存储到缓冲数组中的字节个数。
      int length = 0;

      byte[] buf = new byte[1024*5];
      while((length = input.read(buf))!=-1){

         output.write(buf,0,length);

      }
      System.out.println("字节数组读取的内容:"+ Arrays.toString(buf));
      //关闭资源原则:先开后关,后开先关
      output.close();
      input.close();
   }

}

 

 

6.扩展思考

 

什么时候使用字节流,什么时候使用字符流?

只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

 

 

7.参考文献

参考一:https://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html java IO流的使用总结

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值