字节流

首先要知道:这四个类是抽象类,是一切字符字节输入输出流的父类,因为是抽象类,所以要通过子类来实例化,不能直接实例化;

public abstract class InputStream implements Closeable;
public abstract class OutputStream implements Closeable, Flushable;
public abstract class Reader implements Readable, Closeable;
public abstract class Writer implements Appendable, Closeable, Flushable;

 1)FileInputStream:

    public static void demo1() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("xxx.txt");    //创建流对象,个人认为,相当于一根管道
        int x = fis.read();            //从硬盘上读取一个字节,硬盘上都是以二进制的形式存储
        System.out.println(x);
        int y = fis.read();
        System.out.println(y);
        int z = fis.read();
        System.out.println(z);
        int a = fis.read();
        System.out.println(a);//文件的结束标志:-1
        int b = fis.read();
        System.out.println(b);
        fis.close();                                            //关流释放资源
    }

打印的结果为:97、98、99、-1、-1

    /**
     * Reads a byte of data from this input stream. This method blocks
     * if no input is yet available.
   * * *
@return the next byte of data, or <code>-1</code> if the end of the file is reached. * 返回值为0到255的int类型的值,返回值为字符的ACSII值(如a就返回97,n就返回110). * @exception IOException if an I/O error occurs. */ public native int read() throws IOException; //空参构造,返回读到的内容(第五点阐述有参构造)

 从最基本的开始,假如说相关路径下有文件"xxx.txt",文件上面有abc三个字母,从上面源码可以看出,调用一次read()方法,就读一个字母,返回下一个。结束的时候,就返回-1。

所以可以利用循环来判断:

    private static void demo2() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("xxx.txt");    //创建流对象
        int b;
        //文件的结束标志:-1,所以定义-1就结束了
        while((b = fis.read()) != -1) {
            System.out.println(b);
        }
        fis.close();
    }

read()方法读取的是一个字节,为什么返回是int,而不是byte(复制的,其实我看不懂)

  因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,

那么这11111111byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上,

240凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型。

2)FileOutputStream:

    public static void demo1() throws FileNotFoundException, IOException {
        //创建字节输出流对象,如果没有就自动创建一个
        FileOutputStream fos = new FileOutputStream("yyy.txt");        
        fos.write(97);    //虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
        fos.write(98);
        fos.write(99);
        fos.close();
    }

 相关路径的文件"yyy.txt"就在里面写出了一个abc内容。

如果继续在上面写一个,如下:

    public static void demo1() throws FileNotFoundException, IOException {
        //创建字节输出流对象,如果没有就自动创建一个
        FileOutputStream fos = new FileOutputStream("yyy.txt");        
//        fos.write(97);    //虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
//        fos.write(98);
//        fos.write(99);
        fos.write(100);
        fos.close();
    }

 则文件"yyy.txt"上面只会显示d内容,因为其会在原来的文件上面进行清空,再重新写。

******在创建对象的时候是如果没有这个文件会帮我创建出来

******如果有这个文件就会先将文件清空,是将里面的内容清空,再写入

*****如果不想文件清空,想续写,则在后面加一个布尔值就可以了。

    private static void demo2() throws FileNotFoundException, IOException {
        FileOutputStream fos = new FileOutputStream("yyy.txt",true);    //如果想续写就在第二个参数传true
        fos.write(97);
        fos.write(98);
        fos.close();
    }

 3)拷贝:核心代码就是下面几行

    /*
     * 复制文件,图片,读一次一个字节,写一次一个字节
     */
    public static void demo1() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("双元.jpg");        //创建输入流对象,关联双元.jpg
        FileOutputStream fos = new FileOutputStream("copy.jpg");    //创建输出流对象,关联copy.jpg
        int b;
        while((b = fis.read()) != -1) {                                //在不断的读取每一个字节
            fos.write(b);                                            //将每一个字节写出
        }
        fis.close();                                                //关流释放资源
        fos.close();
    }

 一个一个字节去读,去写(去拷贝),所以这种方法特别耗时。读一次写一次,一共要读写900多万次,所以特别耗时。

4)fis.available()  得到输入流文件的全部字节数

   /*
     * 不推荐使用,因为有可能会导致内存溢出
     */
    public static void demo3() throws FileNotFoundException, IOException {
        
        FileInputStream fis = new FileInputStream("致青春.mp3");
        FileOutputStream fos = new FileOutputStream("copy.mp3");
        
        byte[] arr = new byte[fis.available()];                    
        fis.read(arr);                                            
        fos.write(arr);                                            
        
        fis.close();
        fos.close();
        
    }

5)

private native int readBytes(byte b[], int off, int len) throws IOException;

//这个方法使用一个byte的数组作为一个缓冲区,每次从数据源中读取和缓冲区大小(二进制位)相同的数据并将其存在缓冲区中。
//定义的数组长度为10,每次写进去的也是10
/*
 * 1.从读取流读取一定数量的字节,如果比如文件总共是102个字节
 * 2.我们定义的数组长度是10,那么默认前面10次都是读取10个长度
 * 3.最后一次不够十个,那么读取的是2个
 * 4.这十一次,每次都是放入10个长度的数组.
 */
public int read(byte b[]) throws IOException {   
     return readBytes(b, 0, b.length);
}

/*
 * 1.从读取流读取一定数量的字节,如果比如文件总共是102个字节
 * 2.我们定义的数组长度是10,但是这里我们写read(bytes,0,9)那么每次往里面添加的(将只会是9个长度),就要读12次,最后一次放入3个.
 * 3.所以一般读取流都不用这个而是用上一个方法:read(byte[]);
 */
public int read(byte b[], int off, int len) throws IOException {   
     return readBytes(b, off, len);
}

注意:空参构造和有参构造返回的值内容是不一样

 关于read(byte[] buffer,int off, int len):可以看出:参数buffer表示建了多大长度的缓冲区;off表示把东东往第几个缓冲区放,所以就一般为0,要知道,为什么不在第0个放,而要浪费第0个的位置呢;len就表示每次往缓冲区放多少个东东;

public static void main(String[] args) throws Exception {         
    InputStream is = null;                                        
    byte[] buffer = new byte[5];                                  
    char c;                                                       
                                                                  
    try {                                                         
        is = new FileInputStream("test.txt");// 里面的内容为:ABCDEFGHI  
        is.read(buffer, 1, 2);                                    
        for (byte b : buffer) {                                   
            if (b == 0) {                                         
                c = '-';                                          
            } else {                                              
                c = (char) b;                                     
            }                                                     
            System.out.print(c);                                  
        }                                                         
        System.out.println();                                     
        is.read(buffer, 1, 3);                                    
        for (byte b : buffer) {                                   
            if (b == 0) {                                         
                c = '-';                                          
            } else {                                              
                c = (char) b;                                     
            }                                                     
            System.out.print(c);                                  
        }                                                         
    } catch (Exception e) {                                       
        e.printStackTrace();                                      
    } finally {                                                   
        if (is != null)                                           
            is.close();                                           
    }                                                             
}                                                                 

 

输出:

-AB--
-CDE-

    public static void demo1() throws FileNotFoundException, IOException {
        //xxx.txt   文件内容上面为  97,98,99
        FileInputStream fis = new FileInputStream("xxx.txt");
        byte[] arr = new byte[2];
        int a = fis.read(arr);    //将文件上的字节读取到字节数组中,
                                //返回的是读到的数组的长度,也就是读到的字节的个数
        System.out.println("a:"+a);                        //读到的有效字节个数
        for (byte b : arr) {                        //第一次获取到文件上的a和b
            System.out.println(b);
        }
        
        int c = fis.read(arr);
        System.out.println(c);
        for (byte b : arr) {
            System.out.println(b);
        }
        fis.close();
    }

 打印出:

2、97、98
1、99、98

标准代码:

    public static void demo2() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("xxx.txt");
        FileOutputStream fos = new FileOutputStream("yyy.txt");
        
        byte[] arr = new byte[2];
        int len;
        while((len = fis.read(arr)) != -1) {   //结合上面的,其实第二次返回的长度等于1了
            fos.write(arr,0,len);              //这次每两个字节两个字节地读,比一开始一个个字节读快多了
        }                                      //但是在实际中,字节数组长度设置得更大
        
        fis.close();
        fos.close();
    }

 

 我们设置数组长度,就等于我们自己拿着篮子去买菜了,但是实际上在java中,java已经帮我们备好篮子了

private static int defaultBufferSize = 8192;   //每次读取8192个字节

public BufferedInputStream(InputStream in) {  //包装,装饰者模式
    this(in, defaultBufferSize);            
}                                           

public BufferedInputStream(InputStream in, int size) {         
    super(in);                                                 
    if (size <= 0) {                                           
        throw new IllegalArgumentException("Buffer size <= 0");
    }                                                          
    buf = new byte[size];                                      
}                                                              

* E.小数组的读写和带Buffered的读取哪个更快?

* 定义小数组如果是8192个字节大小和Buffered比较的话

* 定义小数组会略胜一筹,因为读和写操作的是同一个数组

* Buffered操作的是两个数组

     * close方法
     * 具备刷新的功能,在关闭流之前,就会先刷新一次缓冲区,将缓冲区的字节全都刷新到文件上,再关闭,
     * close方法刷完之后就能写了
     * 只有满了才刷新,有点不厚道
     *
     * flush方法?
     * 具备刷新的功能,刷完之后还可以继续写,自动刷新啊 。。用户体验

 字节数组处理中文:

public static void demo1() throws FileNotFoundException, IOException {
    FileInputStream fis = new FileInputStream("yyy.txt");             
    byte[] arr = new byte[4];                                         
    int len;                                                          
    while((len = fis.read(arr)) != -1) {    //写中文随时出现乱码                             
        System.out.println(new String(arr,0,len));//码表转中文,string的构造方法                   
    }                                                                                                                                       
    fis.close();                                                      
}                                                                     
public static void main(String[] args) throws IOException {
    //demo1();                                             
    FileOutputStream fos = new FileOutputStream("zzz.txt");
    fos.write("我读书少,你不要骗我".getBytes()); //字节流写出中文,要转换                   
    fos.write("\r\n".getBytes());  //换行                        
    fos.close();                                           
}                                                          

 

 标准代码:但是实际上一般都不会写得那么麻烦(1.6版本)

public static void demo1() throws FileNotFoundException, IOException {
    FileInputStream fis = null;  //作用域问题,所以要放在外面                      
    FileOutputStream fos = null;  //如果下面两两端代码初始化失败                    
    try {                                                             
        fis = new FileInputStream("xxx.txt");                         
        fos = new FileOutputStream("yyy.txt");                        
                                                                      
        int b;                                                        
        while((b = fis.read()) != -1) {                               
            fos.write(b);                                             
        }                                                             
    }finally {   //一定要关流,所以finally                                    
        try{    //如果初始化失败,没有开启,则不用关闭                                  
            if(fis != null)                                           
                fis.close();                                          
        }finally {            //try fianlly的嵌套目的是能关一个尽量关一个              
            if(fos != null)                                           
                fos.close();                                          
        }                                                             
    }                                                                 
}                                                                     

 

1.7 版本之后流自动关闭,全实现了AutoCloseable接口,自动调用里面的close方法(这种方式开发中用得比较少)

//当把流写在小括号里面,流就会自动关闭,为什么请见下面
public
static void main(String[] args) throws IOException { try( FileInputStream fis = new FileInputStream("xxx.txt"); FileOutputStream fos = new FileOutputStream("yyy.txt"); ){ int b; while((b = fis.read()) != -1) { fos.write(b); } } }
public class FileInputStream extends InputStream;

public abstract class InputStream implements Closeable;

public interface Closeable extends AutoCloseable;

/**
 * A resource that must be closed when it is no longer needed.
 *
 * @author Josh Bloch
 * @since 1.7
 */
public interface AutoCloseable;

 

 

 

 

 

END!

 

 

 

END!

posted @ 2017-12-23 15:43  天马行空郭  阅读(1432)  评论(0编辑  收藏  举报