zoukankan      html  css  js  c++  java
  • 毕向东_Java基础视频教程第19天_IO流(11~14)

    第19天-11-IO流(字节流File读写操作)

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
    字符流
    Reader/Writer
    FileReader/FileWriter
    BufferedReader/BufferedWriter
    
    字节流:
    InputStream/OutputStream
    FileInputStream/FileOutputStream
    需求:想要操作图片数据,这时就要用到字节流
    */
    public class FileStream {
        public static void main(String[] args) throws IOException {
            // writeFile();
            readFile_2();
        }
    
        public static void writeFile() throws IOException {
            FileOutputStream fos = new FileOutputStream("fos.txt");
            fos.write("abc厉害".getBytes());
            // 写需要close无需flush -- 字符流底层也是一个字节一个字节进行操作,但是需要读取若干个字节,然后查码表输出字符,所以涉及缓存和flush.而字节流就不需要缓存也就无需flush
            fos.close();
        }
    
        public static void readFile_0() throws IOException {
            FileInputStream fis = new FileInputStream("fos.txt");
            // 一个字节一个字节读
            int ch;
            while ((ch = fis.read()) != -1) {
                System.out.println((char) ch);
            }
            fis.close();
        }
    
        public static void readFile_1() throws IOException {
            FileInputStream fis = new FileInputStream("fos.txt");
            byte[] buf = new byte[1024];// 1024*N 是字节数组合适的大小
            int len;
            while ((len = fis.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len, "utf-8"));
                System.out.println(new String(buf, 0, len));
            }
            fis.close();
        }
    
        // 字节流特有的available()方法
        public static void readFile_2() throws IOException {
            FileInputStream fis = new FileInputStream("fos.txt");
            // int available() 返回下一次对此输入流调用的方法"可以不受阻塞地从'此输入流'读取(或跳过)的估计剩余字节数"(含换行符)
            // 如果new一个容量大小恰好为剩余文件字节数的byte[fis.available()],就无需循环而一次读完.但文件体积很大的情况下byte[]申请内存会失败
            byte[] buf = new byte[fis.available()];
            fis.read(buf);
            System.out.println(new String(buf));
            fis.close();
        }
    }

    第19天-12-IO流(拷贝图片)

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
    拷贝一个图片,思路:
    1.用字节读取流对象和源图片关联
    2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据.
    3.通过循环读写,完成数据的存储
    4.关闭资源
     */
    public class CopyPic {
        public static void main(String[] args) {
            FileOutputStream fos = null;
            FileInputStream fis = null;
            try {
                fos = new FileOutputStream("2.png");
                fis = new FileInputStream("1.png");
                byte[] buf = new byte[1024];
                int len;
                while ((len = fis.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
            } catch (Exception e) {
                throw new RuntimeException("复制文件失败");
            } finally {
                try {
                    if (fis != null) fis.close();
                } catch (IOException e) {
                    throw new RuntimeException("读取流关闭失败");
                }
                try {
                    if (fos != null) fos.close();
                } catch (IOException e) {
                    throw new RuntimeException("输出流关闭失败");
                }
            }
        }
    }

    Q:字符流可以用于图片复制吗?

    A:不可以,字符流读到的数据,如果在码表里找不到对应的数,则返回一个未知字符对应的数字,未知字符占一个字节。同理,字节流如果错误地截断字符,也会导致乱码。

    第19天-13-IO流(字节流的缓冲区)

    import java.io.*;
    
    /*
    演示mp3的复制(现在都不听mp3了,用图片代替),使用缓冲区.
    BufferedInputStream/BufferedOutputStream
    */
    public class CopyMp3 {
        public static void main(String[] args) throws IOException {
            long start = System.currentTimeMillis();
            copy_1();
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "ms");
        }
    
        public static void copy_1() throws IOException {
            BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("1.png"));
            BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("3.png"));
            int by;
            while ((by = bufis.read()) != -1) {
                bufos.write(by);
            }
            bufis.close();
            bufos.close();
        }
    }

    第19天-14-IO流(自定义字节流的缓冲区-read和write的特点)

    import java.io.*;
    
    public class MyBufferedInputStream {
    
        private byte[] buf = new byte[1024];
        private int pos, count;
        private InputStream in;
    
        public MyBufferedInputStream(InputStream in) {
            this.in = in;
        }
    
        // 一次读一个字节,从缓冲区(字节数组)获取
        public int myRead() throws IOException {
            if (count == 0) {           // count == 0表示数组中的元素已经被全部取走,需要再次进行read(buf)
                if ((count = in.read(buf)) < 0) return -1;
                //通过in对象读取硬盘上的数据,并存储至buf中,count也被重置为数组被填充的长度;如果in.read(buf)返回-1,表示in对象已经读取完毕
                pos = 0;                // 重置数组指针到0,开始重新读取
                byte b = buf[pos];
                count--;
                pos++;
                return b & 0xff;         // 读取的类型byte b,返回值向上转换为int b
            } else if (count > 0) {
                byte b = buf[pos];
                count--;
                pos++;
                return b & 0xff;
            }
            return -1;
        }
    
        public void myClose() throws IOException {
            in.close();
        }
    
        public static void copy() throws IOException {
            MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("1.png"));
            BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("3.png"));
            int by;
            while ((by = bufis.myRead()) != -1) {
                bufos.write(by);        // 传入的类型为int,实际上写入的是byte,多余的高位被截去
            }
            bufos.close();
            bufis.myClose();
        }
    
        public static void main(String[] args) throws IOException {
            long start = System.currentTimeMillis();
            copy();
            long end = System.currentTimeMillis();
            System.out.println(end - start + "ms");
        }
    }

    Q:为什么copy()方法中返回数组元素byte b需要进行 b & 0xff 操作?

    A:因为b为byte类型,copy()方法返回值为int类型,问题就是在byte强制类型转换为int过程中发生的。当byte b = buf[pos]返回二进制为1111-1111时,代表的整数值为-1(1的二进制补码等于反码+1,为1111-1111);向上类型转换为int时,就成了4个字节的int值-1(1111-1111-1111-1111-1111-1111-1111-1111)。myReader()方法返回-1表示读取内容完毕,读取就终止了。因此问题变成了:如果正确返回1111-1111,使之不被当作-1?

      11111111 11111111 11111111 11111111  b

    &00000000 00000000 00000000 11111111  & 255

    ---------------------------------------------------

      00000000 00000000 00000000 11111111  --> b & 0xff    (0&0=0;1&0=0;0&1=0;1&1=1,所以 b&255 的低8位是不会变的)

    Q:为什么“字节流”读一个字节的方法是int read(),返回类型是int;写一个字节的方法void write(int b),传入类型是int?

    A:int read()读取一个字节,返回值被强制向上转换为int;void write(int b)传入一个int值,强制截去高位,只写入低8位(1个字节)

  • 相关阅读:
    站立会议(二)
    站立会议(一)
    电梯演讲 作业派
    《你的灯亮着么》三四篇
    《你的灯亮着么》一二篇
    找一
    水王2
    搜狗输入法使用评价
    找水王问题
    典型用户及用户场景分析
  • 原文地址:https://www.cnblogs.com/echo1937/p/6266809.html
Copyright © 2011-2022 走看看