`
huihui920823
  • 浏览: 36926 次
  • 性别: Icon_minigender_1
  • 来自: 济南
文章分类
社区版块
存档分类
最新评论

字节流--IO学习笔记(二)

 
阅读更多

IO流:
包括字节流和字符流。

在这里解释一下我对于流的理解,其实流就相当于一个用来运输字节或者字符的管道,一开始会把所有的数据存放到流中,然后我们再从流中取出数据(进行读取或者写出操作),每读或者写一次就会从管道中把读或者写的数据取出来,管道中就没有了你刚才读到或者写出的数据了。比如:
FileInputStream fis = new FileInputStream(String filename);
就会把文件名为filename的文件内容全部存放到管道中去,然后我们进行fis.read(),就会从管道中读取出内容,读到的内容就会从管道中消失。

字节流:

(1)InputStream:抽象了应用程序读取数据的方式
OutputStream : 抽象了应用程序写出数据的方式
(2)输入流的基本方法:
InputStream in = new InputStream();
int b = in.read();
读取一个字节无符号填充到int的最后8位,返回的是读到的字节(转换成int类型的值的)内容,当读到-1时,标识读取到最后结束了。
in.read(byte[] buf):读取的数据填充到字节数组buf中,返回的是读到的字节的个数。
in.read(byte[] buf,int start ,int size):读取数据到字节数组buf,并且是从buf的start位置开始,最多存放size长度的数据,返回的是读到的字节的个数。
(3)输出流的基本方法:
OutputStream out = new OutputStream();
out.write(int b):写出一个字节到流,写的是int的最后的8位
out.write(byte[] buf):将buf字节数组都写入到流
out.write(byte[] buf,int start,int size):字节数组buf从start位置开始写size长度的字节到流

下面介绍字节流基本的读取方法的使用(注意:FileInputStream继承了InputStream)

package com.test.FileInputStream;

import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamTest {
    public static void main(String[] args) {
        try {
            System.out.println("方式一:字节数组的长度足够存储读取的内容");
            ReadFile1("C:\\Users\\Administrator\\Desktop\\javaIO\\读取的测试文件.txt");
            System.out.println();
            System.out.println("方式二:字节数组的长度不足以存储读取的内容");
            ReadFile2("C:\\Users\\Administrator\\Desktop\\javaIO\\读取的测试文件.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 当字节数组的大小足够存储读取的内容的时候
     * 只读取一次,然后打印出来就可以了
     */
    public static void ReadFile1(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];
        //从fis中批量读取字节,放入到buf这个字节数组中, 
        //从第0个位置开始放,最多放buf.length个 
        //返回的是读到的字节的个数
        int bytes = fis.read(buf, 0, buf.length);
        int j = 1;
        for(int i=0;i<bytes;i++){
        //byte类型8位,int类型32位,为了避免数据转换错误,通过&0xff将高24位清零
            System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
            if(j++%10==0){//每读取10个字节就换行
                System.out.println();
            }
        }
        fis.close();
    }

    /**
     * 当数组的大小没法存储读取的全部的字节的时候,
     * 就要对该字节数组进行重复利用,
     * 每读取字节数组的长度的内容的时候就打印出来,
     * 然后再次读取该字节数组长度的内容,
     * 直到把所有的内容读取出来
     */
    public static void ReadFile2(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];

        int bytes = 0;
        int j = 1;
        while((bytes = fis.read(buf, 0, buf.length))!=-1){//如果数组不是足够大,要进行多次的读取操作
            for(int i = 0;i<bytes;i++){
                System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
                    System.out.println();
                }
            }
        }
        fis.close();

    }
}

读取的文件内容:
这里写图片描述
读取结果截图:
这里写图片描述
下面对比下单字节读取与批量读取文件的效率:

package com.test.FileInputStream;

import java.io.FileInputStream;
import java.io.IOException;
/**
 * 对比单字节读取与批量读取同样的文件的所用的时间
 * 2015年8月8日 下午9:24:31
 *
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) {
        try {
            ReadFile1("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile2("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 单字节读取文件的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile1(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        int b;
        int i = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read())!=-1){
//          System.out.print(Integer.toHexString(b&0xff)+" ");
            if(i++%10==0){
//              System.out.println();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("单字节读取所用的时间:"+(end-start));
        fis.close();
    }

    /**
     * 批量字节读取的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile2(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];
        int b;
        int j = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read(buf, 0, buf.length))!=-1){
            for(int i = 0;i<b;i++){
//              System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批量读取所用的时间:"+(end-start));
        fis.close();
    }
}

这里写图片描述
所以,批量读取,对于大文件而言效率高,也是我们最常见的读文件的方式。单字节读取不适合大文件,大文件读取的效率很低。

下面介绍字节流基本的写出方法的使用(注意:FileOutputStream继承了OutputStream,实现了向文件中写出byte数据的方法)

package com.test.FileOutputStream;

import java.io.FileOutputStream;
import java.io.IOException;


public class FileOutputStreamTest {

    public static void main(String[] args) {
        try {
            WriteFile("C:\\Users\\Administrator\\Desktop\\javaIO\\写入测试文件.txt");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void WriteFile(String filename) throws IOException{
        //如果该文件不存在,则直接创建,如果存在,删除后创建
        FileOutputStream fos = new FileOutputStream(filename);
//      //如果该文件不存在,则直接创建,如果存在,直接在文件中追加内容
//      FileOutputStream fos = new FileOutputStream(filename,true);
        /*
         * 写一个字符的方法(可以写一个字符)
         */
        fos.write('A');//写出了‘A’的字节所占位的最后八位
        fos.write('B');
        /*
         * 写一个整数的方法
         */
        int i = 10;//write()方法只能写八位,那么写一个int需要写4次,每次8位
        fos.write(i>>>24);
        fos.write(i>>>16);
        fos.write(i>>>8);
        fos.write(i);

        /*
         *写一个字节数组的方法 (可以直接写一个字节数组)
         */
        byte[] gbk = "小灰灰".getBytes("gbk");
        fos.write(gbk);



        fos.close();

    }

}

基本的字节输入流和字节输出流的整合运用:(以Copy文件为例)

package com.test.FileOutputStream;

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

public class CopyFile {

    public static void main(String[] args) {
        File srcFile = new File("C:\\Users\\Administrator\\Desktop\\javaIO\\被copy的文件.txt");
        File destFile = new File("C:\\Users\\Administrator\\Desktop\\javaIO\\copy的文件.txt");
        try {
            copyFile(srcFile, destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void copyFile(File srcFile,File destFile) throws IOException{
        if(!srcFile.exists()){
            throw new IllegalArgumentException("文件:"+srcFile+"不存在");
        }
        if(!srcFile.isFile()){
            throw new IllegalArgumentException(srcFile+"不是文件");
        }
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        byte[] buf = new byte[3*1024];
        int i;
        while((i = fis.read(buf,0,buf.length))!=-1){
            fos.write(buf, 0, i);
            fos.flush();
        }
        fis.close();
        fos.close();
    }

}

DataOutputStream/DataInputStream的使用:
作用:
对“流”功能的扩展,可以更加方便的读取int,long,字符等基本类型的数据。

构造方法:
DataOutputStream dos = new DataOutputStream(OutputStream out);
DataInputStream dis = new DataInputStream(InputStream in);
从构造方法中可以看到这两种流就是对普通流进行了包装,方便读取基本类型的数据。

DataOutputStream多出来的写出的方法:
writeInt()
writeDouble()
writeLong()
writeChars()//采用UTF-16BE编码写出
writeUTF()//采用UTF-8编码写出
……

writeInt():
write()方法一次只可以写出最后的8位,但是int类型的数据是32位(4个字节),所以要write()四次才能写出一个int类型的数据。

int i = 10;//write()方法只能写八位,那么写一个int需要写4次,每次8位
        fos.write(i>>>24);
        fos.write(i>>>16);
        fos.write(i>>>8);
        fos.write(i);

这是我们写一个int类型数据的方法。
writeInt()方法可以只写一次就可以写出一个int类型的数据,其实查看源码可以知道其实也是write()了四次。
writeInt()方法的源码:

 public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }

writeLong(),writeDouble()……也是这样的原理。
所以可以看出DataOutputStream就是对基本类型的数据的写出方法进行了包装,方便我们写出基本类型的数据。

BufferedInputStream/BufferedOutputStream的使用:
这两个流为IO提供了带缓冲区的操作,一般打开文件进行写入或者读取操作时,都会加上缓冲,这种流模式提高了IO的性能。
解释:
从应用程序中把数据放入文件,相当于将一缸水倒入另一个缸中。
FileOutputStream—–>write()方法相当于一滴水一滴水的把水转过去
DataOutputStream—>writeXxx()方法会方便一些,相当于一瓢一瓢的转移过去
BufferedOutputStream—>write()方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入到另个缸中,性能提高了。
注意:当使用BufferedOutputStream的时候,当写完一次后要进行冲刷缓冲区(flush()),否则下次进行写入的时候就没法向缓冲区中存放了。
下面比较一下这些流读取和写入操作的效率:

package com.test.FileInputStream;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
/**
 * 对比单字节读取与批量读取同样的文件的所用的时间
 * 2015年8月8日 下午9:24:31
 *
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) {
        try {
            ReadFile1("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile2("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile3("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
            ReadFile4("C:\\Users\\Administrator\\Desktop\\javaIO\\问尘 - 洛天依.mp3");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 单字节读取文件的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile1(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        int b;
        int i = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read())!=-1){
//          System.out.print(Integer.toHexString(b&0xff)+" ");
            if(i++%10==0){
//              System.out.println();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("单字节读取所用的时间:"+(end-start));
        fis.close();
    }

    /**
     * 批量字节读取的方式
     * @param filename
     * @throws IOException
     */
    public static void ReadFile2(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] buf = new byte[1024];
        int b;
        int j = 1;
        long start = System.currentTimeMillis();
        while((b = fis.read(buf, 0, buf.length))!=-1){
            for(int i = 0;i<b;i++){
//              System.out.print(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批量读取所用的时间:"+(end-start));
        fis.close();
    }

    /**
     * 字节缓冲流读取文件
     * @param filename
     * @throws IOException
     */
    public static void ReadFile3(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        BufferedInputStream bis = new BufferedInputStream(fis);
        long start = System.currentTimeMillis();
        int b;
        int j = 1;
        while((b=bis.read())!=-1){
            for(int i=0;i<b;i++){
//              System.out.println(Integer.toHexString(b&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("字节缓冲流读取所用的时间:"+(end-start));
        bis.close();
    }
    /**
     * 字节缓冲流批量读取文件
     * @param filename
     * @throws IOException
     */
    public static void ReadFile4(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] buf = new byte[1024*3];
        long start = System.currentTimeMillis();
        int b;
        int j = 1;
        while((b= bis.read(buf, 0, buf.length))!=-1){
            for(int i = 1;i<b;i++){
//              System.out.println(Integer.toHexString(buf[i]&0xff)+" ");
                if(j++%10==0){
//                  System.out.println();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("字节缓冲流批量读取所用的时间"+(end-start));
        bis.close();
    }
}

所用时间结果截图:
这里写图片描述
由此可以看出:
批量读取文件的效率>字符缓冲流读取文件的效率>单字节读取文件的效率

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics