• Java IO(二)


       字节流

       字符流:

    1. FileReader
    2. FileWriter
    3. BufferedReader
    4. BufferedWriter

       字节流:

    1. FileInputStream 
    2. FileOutputStream
    3. BufferedInputStream 
    4. BufferedOutputStream

       想要操作图片数据,这时就要用到字节流。

       示例代码如下:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class FileOutputStreamDemo0 {
    
        public static void main(String[] args) throws IOException {
            //writeFile();
            //readFile();
            
            //readFile_2();
            
            readFile_3();
        }
        
        public static void readFile_3() throws IOException {
            FileInputStream fis = new FileInputStream("fos.txt");
            
            //int num = fis.available();
            
            byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区,不用在循环了。不过慎用!!!
            
            fis.read(buf);
            
            //System.out.println("num = " + num);
            System.out.println(new String(buf));
            
            fis.close();
        }
        
        public static void readFile_2() throws IOException {
            FileInputStream fis = new FileInputStream("fos.txt");
            
            byte[] buf = new byte[1024];//还是建议使用1024的整数倍开辟字节数组
            
            int len = 0;
            
            while((len = fis.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len));
            }
            
            fis.close();
        }
        
        public static void readFile() throws IOException {
            FileInputStream fis = new FileInputStream("fos.txt");
            
            int ch = 0;
            
            while((ch = fis.read()) != -1) {
                System.out.println((char) ch);
            }
            
            fis.close();
        }
        
        public static void writeFile() throws IOException {
            FileOutputStream fos = new FileOutputStream("fos.txt");
            
            fos.write("abcde".getBytes());
            
            fos.close();
        }
    
    }

       练习1:复制一个图片。

       思路:

    1. 用字节读取流对象和图片关联。
    2. 用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
    3. 通过循环读写,完成数据的存储。
    4. 关闭资源。

       代码:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class CopyPic {
    
        public static void main(String[] args) {
            FileOutputStream fos = null;
            FileInputStream fis = null;
            
            try {
                fos = new FileOutputStream("E:\MyJava\workspace\IO_Project\Krystal.jpg");
                fis = new FileInputStream("D:\Krystal.jpg");
                
                byte[] buf = new byte[1024];
                
                int len = 0;
                
                while((len = fis.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
            } catch (IOException 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("写入关闭失败!");
                }
            }
        }
    
    }

       练习2:复制一个MP3文件。

       通过缓冲区(BufferedOutputStream/BufferedInputStream),演示MP3的复制。

       代码:

    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class CopyMp3 {
    
        public static void main(String[] args) throws IOException {
            long start = System.currentTimeMillis();
            copy_2();
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "毫秒");
        }
        /*
         * 通过字节流的缓冲区完成复制
         */
        public static void copy_1() throws IOException {
            BufferedInputStream bufis = new BufferedInputStream(
                    new FileInputStream("E:\KuGou\Temp\滨琦步 - 犬夜叉主题曲.mp3"));
            
            BufferedOutputStream bufos = new BufferedOutputStream(
                    new FileOutputStream("E:\MyJava\workspace\IO_Project\滨琦步 - 犬夜叉主题曲.mp3"));
            
            int by = 0;
            
            while((by = bufis.read()) != -1) {
                bufos.write(by);
            }
            
            bufis.close();
            bufos.close();
        }
        
    }

       练习3:自定义一个类模拟BufferedInputStream,完成一个MP3文件的复制。

       分析:

    mp3是由二进制数据组成的:
    11111111-1110000000000000000000101010110111010111010010110001
    
    问题:自定义的myRead()函数为什么会返回int类型,而不直接返回byte类型呢?
    分析:
    byte: -1  ----> int: -1
    
    11111111(-1)提升为11111111 11111111 11111111 11111111(-1)
    11111111(-1)--->提升为一个int类型,那还不是-1吗?是-1的原因是因为在8个1前面补的都是1导致的。
    那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。
    怎么补0呢?
        11111111 11111111 11111111 11111111
    &   00000000 00000000 00000000 11111111
    ------------------------------------------
        00000000 00000000 00000000 11111111
        
    所以应把11111111(-1)提升为00000000 00000000 00000000 11111111(255),避免返回-1这种情况

       代码:

    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    class MyBufferedInputStream {
        private InputStream in;
        private byte[] buf = new byte[1024 * 4];
        private int pos = 0, count = 0;
        
        MyBufferedInputStream(InputStream in) {
            this.in = in;
        }
          
        /*
         * 一次读一个字节,从缓冲区(字节数组)获取。
         */
        public int myRead() throws IOException {
            /*
             * 通过in对象读取硬盘上数据,并存储到buf中。
             */
            if(count == 0) {
                count = in.read(buf);
                if(count < 0)
                    return -1;
                pos = 0;
                byte b = buf[pos];
                count--;
                pos++;
                return b & 255;
            } else if(count > 0) {
                byte b = buf[pos];
                count--;
                pos++;
                return b & 0xff;
            }
            return -1;
        }
        
        public void myClose() throws IOException {
            in.close();
        }
    }
    public class MyBufferedInputStreamDemo {
    
        public static void main(String[] args) throws IOException {
            long start = System.currentTimeMillis();
            copy_2();
            long end = System.currentTimeMillis();
            System.out.println((end - start) + "毫秒");
        }
        
        public static void copy_2() throws IOException {
            MyBufferedInputStream bufis = new MyBufferedInputStream(
                    new FileInputStream("E:\KuGou\Temp\滨琦步 - 犬夜叉主题曲.mp3"));
            
            BufferedOutputStream bufos = new BufferedOutputStream(
                    new FileOutputStream("E:\MyJava\workspace\IO_Project\滨琦步 - 犬夜叉主题曲_2.mp3"));
            
            int by = 0;
            
            //System.out.println("第一个字节:" + bufis.myRead());//第一个字节:-1,因为读到了连续的11111111
            
            while((by = bufis.myRead()) != -1) {
                bufos.write(by);
            }
            
            bufis.myClose();
            bufos.close();
        }
    
    }

       System类对IO的支持

       读取键盘录入。

       System.out:对应的是标准输出设备,控制台。

       System.in:对应的是标准输入设备,键盘。

       例,需求:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么录入停止。

       代码:

    import java.io.IOException;
    import java.io.InputStream;
    
    public class ReadIn {
    
        public static void main(String[] args) throws IOException {
            InputStream in = System.in;
            StringBuilder sb = new StringBuilder();
            while(true) {
                int ch = in.read();
                if(ch == '
    ')
                    continue;
                if(ch == '
    ') {
                    String s = sb.toString();
                    if("over".equals(s))
                        break;
                    System.out.println(s.toUpperCase());
                    sb.delete(0, sb.length());//清空缓冲区
                } else {
                    sb.append((char) ch);
                }
                
            }
            
            //System.out.println('
    ' + 0);//13
            //System.out.println('
    ' + 0);//10
            /*
            int by = in.read();
            int by1 = in.read();
            int by2 = in.read();
            
            System.out.println(by);
            System.out.println(by1);
            System.out.println(by2);
            */
        }
    }

       通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就是readLine()方法。

       能不能直接使用readLine()方法来完成键盘录入的一行数据的读取呢?

       readLine()方法是字符流BufferedReader类中的方法,而键盘录入的read()方法是字节流InputStream的方法,那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine()方法呢?

       此时就需要用到转换流。

       转换流:

    1. InputStreamReader字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集(GBK)
    2. OutputStreamWriter字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。 

       上例优化之后的代码为:

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    
    public class TransStreamDemo0 {
    
        public static void main(String[] args) throws IOException {
            /*
             * 获取键盘录入对象。
             */
            //InputStream in = System.in;
            
            /*
             * 将字节流对象转成字符流对象,使用转换流——InputStreamReader
             */
            //InputStreamReader isr = new InputStreamReader(in);
            
            /*
             * 为了提高效率,将字符流进行缓冲区技术高效操作,使用BufferedReader
             */
            //BufferedReader bufr = new BufferedReader(isr);
            /*
             * 简写格式,键盘录入最常见写法
             */
            BufferedReader bufr = 
                    new BufferedReader(new InputStreamReader(System.in));
            
            //OutputStream out = System.out;//屏幕输出
            /*
             * 字符流输出对象转换成字节流输出对象
             */
            //OutputStreamWriter osw = new OutputStreamWriter(out);
            
            //BufferedWriter bufw = new BufferedWriter(osw);
            /*
             * 简写格式
             */
            BufferedWriter bufw = 
                    new BufferedWriter(new OutputStreamWriter(System.out));
            
            String str = null;
            while((str = bufr.readLine()) != null) {
                if("over".equals(str))
                    break;
                //System.out.println(str.toUpperCase());
                bufw.write(str.toUpperCase());
                bufw.newLine();
                bufw.flush();
            }
            bufw.close();//并没有写bufr.close();是因为此程序一结束掉,就给关闭了。
        }
    
    }

       

       流操作的基本规律

       最痛苦的就是流对象有很多,不知道该用哪一个。

       通过三个明确来完成:

      1、明确源和目的。

        源:输入流。InputStream Reader

        目的:输出流。OutputStream Writer

      2、操作的数据是否是纯文本。

        是:字符流。

        不是:字节流。

      3、当体系明确后,在明确要使用哪个具体的对象。

        通过设备来进行区分:

        源设备:内存、硬盘、键盘。

        目的设备:内存、硬盘、控制台。

       例1、需求:将一个文本文件中的数据存储到另一个文件中。(复制文件)

      分析:

        源:因为是源,所以使用读取流。InputStream Reader

        是不是操作文本文件?

        是!这时就可以选择Reader,这样体系就明确了。

        接下来要明确要使用该体系中的那个对象?

        明确设备:硬盘上的一个文件。Reader体系中可以操作文件的对象是FileReader。

        是否需要提高效率?是!加入Reader体系中的缓冲区BufferedReader。

    FileReader fr = new FileReader("a.txt");
    BufferedReader bufr = new BufferedReader(fr);
    

        目的:OutputStream Writer

        目的是否是纯文本?是!Writer。

        设备:硬盘上的一个文件。

        Writer体系中可以操作文件的对象是FileWriter。

        是否需要提高效率?是!加入Reader体系中的缓冲区BufferedWriter。

    FileWriter fw = new FileWriter("b.txt");
    BufferedWriter bufw = new BufferedWriter(fr);
    

       练习:将一个图片文件中的数据存储到另一个文件中。(复制文件)

       代码:

    /*
     * 练习:将一个图片文件中的数据存储到另一个文件中。(复制文件)
     */
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class test0 {
    
        public static void main(String[] args) {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            byte[] by = new byte[1024];
            int len = 0;
            try {
                fis = new FileInputStream("d:\Krystal.jpg");
                bis = new BufferedInputStream(fis);
                
                fos = new FileOutputStream("d:\java\io123\Krystal.jpg");
                bos = new BufferedOutputStream(fos);
                
                while((len = bis.read(by)) != -1) {
                    bos.write(by, 0, len);
                }
            }  catch (IOException e) {
                throw new RuntimeException("图片复制失败!");
            } finally {
                try {
                    if(bis != null) 
                        bis.close();
                } catch (IOException e) {
                    throw new RuntimeException("关闭读取流失败!");
                }
                try {
                    if(bos != null) 
                        bos.close();
                } catch (IOException e) {
                    throw new RuntimeException("关闭写入流失败!");
                }
            }
        }
    
    }

       例2、需求:将键盘录入的数据保存到一个文件中。

      分析:

        这个需求中有源和目的都存在。那么分别分析

        源:InputStream Reader

        是不是纯文本?是!Reader

        设备:键盘。对应的对象是System.in。

        不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,转成字符流,按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成字符流Reader。用到了Reader体系中的转换流,InputStreamReader

    InputStreamReader isr = new InputStreamReader(System.in);
    

        需要提高效率吗?需要!BufferedReader 

    BufferedReader bufr = new BufferedReader(isr);
    

        目的:OutputStream Writer

        是不是纯文本?是!Writer

        设备:硬盘上的一个文件。使用FileWriter。

    FileWriter fw = new FileWriter("c.txt");
    

        需要提高效率吗?需要!BufferedWriter

    BufferedWriter bufw = new BufferedWriter(fw);
    

      扩展一下,想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中,怎么办呢?

      分析:

        目的:OutputStream Writer

        是不是纯文本?是!Writer

        设备:硬盘上的一个文件。使用FileWriter。但是FileWriter是使用的默认编码表(GBK)

        但是存储时,需要加入指定的编码表(UTF-8),而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter。而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流,FileOutputStream。

    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"), "UTF-8");
    

        需要提高效率吗?需要!BufferedWriter

    BufferedWriter bufw = new BufferedWriter(osw);
    

      所以,记住,转换流什么时候使用?字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流

       练习:将一个文本数据打印在控制台上。

       代码:

    /*
     * 练习:将一个文本数据打印在控制台上。
     */
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    
    public class test1 {
    
        public static void main(String[] args) {
            BufferedReader br = null;
            BufferedWriter bw = null;
            String line = null;
                    
            try {
                br = new BufferedReader(new FileReader("d:\java\ArrayTool.java"));
                bw = new BufferedWriter(new OutputStreamWriter(System.out));
    
                while((line = br.readLine()) != null) {
                    bw.write(line);
                    bw.newLine();
                    bw.flush();
                }
            } catch (IOException e) {
                throw new RuntimeException("读取文件失败");
            } finally {
                try {
                    if(br != null) 
                        br.close();
                } catch (IOException e) {
                    throw new RuntimeException("读取流关闭失败");
                }
                try {
                    if(bw != null)
                        bw.close();
                } catch (IOException e) {
                    throw new RuntimeException("写入流关闭失败");
                }
            }
            
        }
    
    }

       异常的日志信息

     log4j:记录日志信息的一个工具。

       示例代码如下:

    import java.io.FileNotFoundException;
    import java.io.PrintStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ExceptionInfo {
    
        public static void main(String[] args) {
            
            try {
                int[] arr = new int[2];
                System.out.println(arr[3]);
            } catch (Exception e) {
                try {
                    Date d = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String s = sdf.format(d);
                    PrintStream ps = new PrintStream("exception.log");
                    //ps.write(d.toString().getBytes());
                    ps.println(s);
                    System.setOut(ps);
                } catch (FileNotFoundException e1) {
                    throw new RuntimeException("日志文件创建失败!");
                }
                e.printStackTrace(System.out);
                //e.printStackTrace(new PrintStream("ex.txt"));
            }
        }
    
    }

       系统信息

       示例代码如下:

    import java.io.FileNotFoundException;
    import java.io.PrintStream;
    import java.util.Properties;
    
    public class SystemInfo {
    
        public static void main(String[] args) throws FileNotFoundException {
            Properties pro = System.getProperties();
            //System.out.println(pro);
            pro.list(new PrintStream("sysinfo.txt"));
        }
    
    }

       通过sysinfo.txt文本文件可以知道平台默认的字符集,即默认字符编码是GBK

       

  • 相关阅读:
    配置管理-SVN使用指南-Linux
    配置管理-SVN权限详解
    配置管理-SVN使用指南
    Unity3d之Mecanim(新版动画系统)
    Unity3d之Animation(动画系统)
    iTween基础之iTweenPath(自定义路径移动)
    iTween基础之Color(变换颜色)
    unity工具IGamesTools之批量生成帧动画
    unity2d之2d帧动画创建
    iTween基础之Fade(淡入淡出)
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5269424.html
Copyright © 2020-2023  润新知