Java学习笔记-IO流

java的IO流学习笔记


1、异常处理
    java 2种异常处理:
        a:自己将该问题处理,然后继续运行(try catch)
            try{
                ...          //可能产生异常的地方
            }catch(Exception e){
                e.printStackTrace();
                ...          //出异常后,捕获异常进行处理,jvm默认就用这种方式处理异常
                return;
            }finally{
                ...          //释放资源,一定会执行,比如关闭已打开的io流。
            }
            
            注意:
            被finally控制的语句体一定会执行,特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
            return语句在执行之前,会检查有没有finally,如果有就将finally执行
            
        b:将异常抛出(throws):定义功能方法时,需要把出现的问题暴露出来让调用者去处理。
            public static void main(String[] args) throws Exception {
                Person p = new Person();
                p.setAge(-17);
                System.out.println(p.getAge());
            }
            
            throw的概述以及和throws的区别
                throws:用在方法声明后面,跟的是异常类名; 可以跟多个异常类名,用逗号隔开; 表示抛出异常,由该方法的调用者来处理
                throw:用在方法体内,跟的是异常对象名; 只能抛出一个异常对象名; 表示抛出异常,由方法体内的语句处理
            
            
        也可以自定义异常:
        class AgeOutOfBoundsException extends Exception {
            public AgeOutOfBoundsException() {//不带参数的构造函数
                super();
            }
            public AgeOutOfBoundsException(String message) {//带参数的构造函数
                super(message);
            }
        }
    
    final、finally、finalize区别
        final:可以修饰类,不能被继承 ; 修饰方法,不能被重写 ; 修饰变量,只能赋值一次
        finally:是try语句中的一个语句体,不能单独使用,用来释放资源
        finalize:是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
    
    如果catch里面有return语句,finally的代码会执行,但是在finally中定义的变量值不会改变,会使用return之前语句的变量值
        try {
x = 20;
System.out.println(1/0);
return x;
} catch (Exception e) {
x = 30;
return x;
} finally {
x = 40;
//return x; 千万不要在finally里面写返回语句
}
        //结果会返回x=30
            
    
2、File类:文件和目录路径名的抽象表示形式
    构造方法:
        File(String pathname)       //根据一个路径得到File对象,pathname是个绝对路径"C:\\Users\\user\\Desktop\\java\\test.txt"
        File(String parent, String child) //parent目录  child目录或文件名称
        File(File parent, String child)   //parent 是File对象(目录的File对象),child 文件名称或者目录
    
    基本的方法:
        File file = new File("a.txt");
        file.createNewFile();              //如果没有就创建,返回true
        file.mkdir();                      //创建文件夹 如果存在这样的文件夹,就不创建了
        file.mkdirs("aa\\bb");                     //创建文件夹,如果父文件夹不存在,会帮你创建出来,创建2个层级目录
        
        boolean isDirectory() //判断是否是目录
        boolean isFile()      //判断是否是文件
        boolean exists()      //判断是否存在
        boolean canRead()     //判断是否可读
        boolean canWrite()    //判断是否可写
        boolean isHidden()    //判断是否隐藏
    boolean getAbsolutePath()    //获取绝对路径
        String getPath()             //获取路径
        String getName()             //获取名称
        long length()                //获取长度。字节数
        long lastModified()          //获取最后一次的修改时间,毫秒值
        
    练习:获取d盘目录下所有的txt文件
        File dir = new File("E:\\");
        String[] arr = dir.list(); //获取d盘下所有的文件或文件夹
        for (String string : arr) {
if(string.endsWith(".txt")) {           //endsWith 判断是否以.txt结尾
System.out.println(string);
}
        
        
3、IO流:IO流用来处理设备之间的数据传输,Java用于操作流的类都在IO包中。
    流按流向分为两种:输入流,输出流。
    流按操作类型分为两种:
        字节流 (Byte:8位0/1): 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
            字节流的抽象父类:
            InputStream 
            OutputStream
字符流 (char:具体的大小由编码表决定): 字符流只能操作纯字符数据,比较方便。
            字符流的抽象父类:
            Reader 
            Writer
    
    
    字节流使用:
        a、FileInputStream基本用法:
            FileInputStream fis = new FileInputStream("a.txt");    //创建流对象
            int b; //定义变量,记录每次读到的字节,注意使用的是int类型接受
            while((b = fis.read()) != -1) { //将每次读到的字节赋值给b并判断是否是-1
                System.out.println(b); //打印每一个字节
            }
            fis.close(); //关闭流释放资源
        
            注意:
            read()方法读取的是一个字节,为什么返回是int,而不是byte?
                因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
                那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
                24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型。
        
        b、FileOutputStream基本用法:
            FileInputStream fis = new FileInputStream("a.txt");    //创建流对象
            FileOutputStream fos = new FileOutputStream("b.txt");   //创建输出流对象,关联b.txt
            int b;
            while((b = fis.read()) != -1) {
                fos.write(b);
            }
            fos.close();
            
        c、使用FileInputStream,FileOutputStream每次读取一个byte和写出一个byte效率太低了!!!
        解决办法可以定义一个小数组接受
            FileInputStream fis = new FileInputStream("a.txt");
            FileOutputStream fos = new FileOutputStream("b.txt");
            int len;
            byte[] arr = new byte[1024 * 8]; //自定义字节数组,默认缓冲的大小也是1024*8 byte
            
            while((len = fis.read(arr)) != -1) {
                //fos.write(arr);                               //如果这样写了,就会多些数据,因为读到末尾的时候不一定就是1024*8个字节
                fos.write(arr, 0, len); //写出字节数组写出有效个字节个数
            }
            fis.close();
            fos.close();
        
        d、java也考虑到了读取效率低的问题,所以封装了一个BufferedInputStream和BufferedOutputStream类来使用。
            BufferedInputStream 会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个int长度;程序再次读取时, 就不用找文件了, 直接从缓冲区中获取,直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个byte。
            BufferedOutputStream 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中,直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
            
            因为使用buffer操作的是内存,比直接操作硬盘效率要高很多。
            
            FileInputStream fis = new FileInputStream("a.mp3");            //创建文件输入流对象,关联a.mp3
            BufferedInputStream bis = new BufferedInputStream(fis); //创建缓冲区对fis装饰
            FileOutputStream fos = new FileOutputStream("b.mp3");    //创建输出流对象,关联b.mp3
            BufferedOutputStream bos = new BufferedOutputStream(fos); //创建缓冲区对fos装饰
            
            int b;                              //读取的有效长度
            while((b = bis.read()) != -1) { //从硬盘中读取1024*8 byte
                bos.write(b);
            }
            
            bis.close(); //只关装饰后的对象即可
            bos.close();
    
        小数组的读写和带Buffered的读取哪个更快?
            定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组。
        
        flush和close方法的区别
            用来刷新缓冲区的,刷新后可以再次写出,例如qq聊天的窗口
            用来关闭流释放资源的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出
          
        字节流读写中文问题:
            读中文的时候有可能会出现乱码,因为一个中文2个字符。假设文件全是中文且没有标点,字母等字符,设置arr为2的整数倍读取没有问题
            只要有标点或字母,读取的时候就可能出现读到半个中文,码表找不到的中文会用?代替。
            
            字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组,例如写出回车换行 
            write("\r\n".getBytes());
            
        e、流的标准处理异常代码1.6版本及其以前
        FileInputStream fis = null;
            FileOutputStream fos = null;
            try {
                fis = new FileInputStream("a.txt");
                fos = new FileOutputStream("b.txt");
                int b;
                while((b = fis.read()) != -1) {
                    fos.write(b);
                }
            } finally {
                try {
                    if(fis != null)
                        fis.close();
                }finally {
                    if(fos != null)
                        fos.close();
                }
            }
            
            
        f、给数据加密(原理是数据异或两次后就是自己)
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg"));    //可以不用分开写
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg")); //可以不用分开写
            
            int b;
            while((b = bis.read()) != -1) {
                bos.write(b ^ 123);
            }
            
            bis.close();
            bos.close();
        
        
    字符流使用:字符流是可以直接读写字符的IO流
        字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要写出字符, 需要把字符转为字节再写出。
        
        a、FileReader基本用法:
            FileReader类的read()方法可以按照字符大小读取
            FileReader fr = new FileReader("a.txt"); //创建输入流对象,关联aaa.txt
            int ch;                                                 //文件是用二进制数据存储的,读取的时候会使用int类型接受,
                                                                    //字符大小根据码表不同而定 GBK一个中文2个字符
            while((ch = fr.read()) != -1) { //将读到的字符赋值给ch
                System.out.println((char)ch); //将读到的字符强转后打印
            }
            
            fr.close(); //关流 
            
        
        b、FileWriter基本用法:
            FileWriter fw = new FileWriter("b.txt");
            fw.write("aaa");
            fw.close();
            
            
        c、字符流的拷贝:
            FileReader fr = new FileReader("a.txt");
            FileWriter fw = new FileWriter("b.txt");
            
            int ch;
            while((ch = fr.read()) != -1) {
                fw.write(ch);
            }

            fr.close();
            fw.close();
        d、什么情况下使用字符流?
            字符流也可以拷贝文本文件, 但不推荐使用. 因为读取时会把字节转为字符, 写出时还要把字符转回字节;
            程序需要读取一段文本, 或者需要写出一段文本的时候可以使用字符流;
            读取的时候是按照字符的大小读取的,不会出现半个中文;
            写出的时候可以直接将字符串写出,不用转换为字节数组。
            
            注意:
            字符流是不可以拷贝非纯文本的文件,因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替。
            
        e、自定义字符数组的拷贝:
        FileReader fr = new FileReader("a.txt"); //创建字符输入流,关联a.txt
            FileWriter fw = new FileWriter("b.txt"); //创建字符输出流,关联b.txt
            
            int len;
            char[] arr = new char[1024*8]; //创建字符数组
            while((len = fr.read(arr)) != -1) { //将数据读到字符数组中
                fw.write(arr, 0, len); //从字符数组将数据写到文件上
            }
            
            fr.close(); //关流释放资源
            fw.close();
        
        f、带缓冲的字符流:
        BufferedReader br = new BufferedReader(new FileReader("a.txt")); //创建字符输入流对象,关联a.txt
            BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); //创建字符输出流对象,关联b.txt
            
            int ch;
            while((ch = br.read()) != -1) { //read一次,会先将缓冲区读满,从缓冲去中一个一个的返给临时变量ch
                bw.write(ch); //write一次,是将数据装到字符数组,装满后再一起写出去
            }
            
            br.close(); //关流
            bw.close();  
        
        g、readLine()和newLine()方法
            BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
            BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"
            
            例如:
            BufferedReader br = new BufferedReader(new FileReader("a.txt"));
            BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
            String line;
            while((line = br.readLine()) != null) {
                bw.write(line);
                //bw.write("\r\n"); //只支持windows系统
                bw.newLine(); //跨平台的
            }
            
            br.close();
            bw.close(); 
        
        h、使用指定的码表读写字符
        BufferedReader br = //高效的用指定的编码表读
new BufferedReader(new InputStreamReader(new FileInputStream("UTF-8.txt"), "UTF-8"));
            BufferedWriter bw = //高效的用指定的编码表写
                    new BufferedWriter(new OutputStreamWriter(new FileOutputStream("GBK.txt"), "GBK"));
            int ch;
            while((ch = br.read()) != -1) {
                bw.write(ch);
            }
            
            br.close();
            bw.close();
        
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值