java-io流

1)IO流,什么是io?
I:Input
O:Output
通过IO可以完成硬盘文件的读和写

2)IO流的分类
一:按照流的方向进行分类
 以内存为参照物,
  往内存中去,叫输入(Input),或者叫读(Read)
  从内存中出来,叫输出(Output),或者叫写(Write)

二:按照读取数据方式不同进行分类
 第一种方式:有的流是按照字节的方式读取数据,一次读取一个字节byte(相当于一次读取8个二进制位)。这种流是万能的,什么类型的文件都可读取。
 第二种方式:有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本而存在,这种流不能读取:图片、声音、视频等文件。只能读取纯文本。
因此,流的分类为
  输入流、输出流
  字节流、字符流

注意
‘a’等字符在Windows系统中占用1个字节
‘啊’等中文字符在Windows系统中占用2个字节

3)IO流四大家族
四大家族的首领:
 java.io.InputStream 字节输入流
 java.io.OutputStream 字节输出流

 java.io.Reader 字符输入流
 java.io.Writer 字符输出流
四大家族的首领都是抽象类。(abstract class)

所有的流都实现了:
  java.io.Closeable接口,都是可关闭的,都有close( )方法。
  流毕竟是一个管道,是内存和硬盘之间的通道,用完之后一定要关闭,
  不然会耗费(占用)很多资源。所以用完流一定要关闭。

所有的输出流都实现了:
  java.io.Flushable接口,都是可刷新的,都有flush( )方法。
  输出流在最终输出之后,一定要记得flush( ),刷新一下
&emap;&emap;这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道)
  刷新的作用是清空管道。如果没有flush( )可能会丢失数据

注意:在Java中只要“类名”以Stream结尾的都是字节流;以“Reader/Writer”结尾的都是字符流

4)java.io包下需要掌握的流有16个:
4.1、文件专属:
 java.io.FileInputStream (掌握)
 java.io.FileOutputStream (掌握)
 java.io.FileReader
 java.io.FileWriter

FileInputStream

    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            //路径可以写相对路径,也可以绝对路径
            fis = new FileInputStream("tempfile"); //创建流对象
            int temp;
            //该方法没有参数传进时,则一次只读取一个字节,效率较低
            //由于内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面了
            //temp=fis.read();  // 返回值是:读取到的“字节”本身。
            //System.out.println(temp);
            
            byte[] arr=new byte[1024*1024];
            //一次最多读取 arr.length 个字节。1个字节都没有读取到返回-1
            //temp=fis.read(arr);  //返回值是:读取到的字节数量。(不是字节本身)

            while((temp=fis.read(arr))!=-1){
                //把byte数组转换成字符串,读到多少个转换多少个。
                System.out.println(new String(arr,0,temp));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            //在finally语句中确保流一定关闭
            if(fis!=null){//避免空指针异常
                // 关闭流的前提是:流不是空。流是null的时候没必要关闭。
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
/*
FileInputStream类的其它常用方法:
    int available():返回流当中剩余的没有读到的字节数量
    long skip(long n):跳过几个字节不读。
 */

FileOutputStream

    public static void main(String[] args) {
        FileOutputStream fos=null;
        try {
            //文件输出流如果指向的文件不存在,会自动创建
            //true 表示以追加的方式在文件末尾写入。不会清空原文件内容
            fos=new FileOutputStream("E:\\JAVA\\tempfile",true);
            String s="HelloWorld";
            //将字符串转为数组,全部在写入文件中
            fos.write(s.getBytes());

            byte[] bytes={97,98,99,100};
            //将byte数组一部分写出
            fos.write(bytes,0,2);

            //写完之后,一定要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

使用FileReader + FileWriter 完成文本拷贝
拷贝过程是:一边读一边写

    public static void main(String[] args) {
        FileReader fr=null;
        FileWriter fw=null;
        try {
            //创建一个输入流对象
            fr=new FileReader("E:\\JAVA\\tempfile");
            //创建一个输出流对象
            fw=new FileWriter("E:\\JAVA\\tempfile",true);

            //一边读,一边写
            char[] chars=new char[512*1024]; //每次读取1MB
            int readCount=0;
            //read( )是按一个字符字符来读
            while((readCount=fr.read(chars))!=-1){
                fw.write(chars,0,readCount);
            }

            //刷新
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //要分开try
            //一起try时,其中一个出现异常,可能会影响到另外一个流的关闭
            if(fr!=null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fw!=null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

4.2、转换流:(将字节流转换成字符流)
  java.io.InputStreamReader
  java.io.OutputStreamWriter

4.3、缓冲流专属
  java.io.BufferdReader
  java.io.BufferedWriter
上面两个缓冲流的构造方法中,需要传字符流。
也可以用字节流通过转换流变成字符流,再传进构造方法中

  java.io.BufferedInputStream
  java.io.BufferedOutputStream
上面两个缓冲流的构造方法中,需要传字节流
注意:
使用带有缓冲区的流不需要自定义char数组,或者不需要自定义byte数组。自带缓冲

BufferedReader的使用

    public static void main(String[] args){
        BufferedReader br=null;
        FileReader fr= null;
        try {
            fr = new FileReader("E:\\JAVA\\filetemp");
            //当一个流的构造方法中需要一个流时,这个被传进来的流叫做:节点流
            //外部负责包装的这个流,叫做:包装流,又称:处理流
            //当前程序中,FileReader就是节点流,BufferedReader为包装流/处理流
            br=new BufferedReader(fr);
            String s=null;
            //br.readLine( )方法读取一个文本行,但不带换行符
            while((s=br.readLine())!=null){
                System.out.println(s);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            //对于包装流来说,只需要关闭最外层流就行,里面的节流会自动关闭(看源代码)
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

BufferedWriter的使用

   public static void main(String[] args) throws Exception{
       BufferedWriter bw=null;
//       FileOutputStream fis=new FileOutputStream("E:\\JAVA\\filetemp");
//       OutputStreamWriter osw=new OutputStreamWriter(fis);
//       bw=new BufferedWriter(osw);

       //以上合再一起写
       bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:/JAVA/filetemp",true)));

        String s="你好 世界";
        bw.write(49);  //写入文本的是,对应的ASCII码
        bw.newLine();//换行
        bw.write(s);
        bw.write("\n"); //换行
        bw.write(97);

        bw.flush();  //刷新
        bw.close();
    }

4.4、数据流:(包装流)
  java.io.DataInputStream
  java.io.DataOutputStream

DataOutputStream这个流可以将数据连同数据的类型一起写入文件
注意:这个文件不是普通文本文档。(记事本打不开)

DataOutputStream写的文件,只能使用DataInputStream去读。
并且读的时候需要提前知道写入的顺序。读的顺序需要写的顺序一致,才可以正常取出数据。

4.5、标准输出流:
  java.io.PrintWriter
  java.io.PrintStream (掌握)

PrintStream:
1.标准的字节输出流,默认输出到控制台
2.标准输出流不需要手动close( )关闭

 public static void main(String[] args) throws Exception{
        System.out.println("Hello");

        //分开写
        PrintStream ps=System.out;
        ps.println("你好");

        // 标准输出流不再指向控制台,指向“tempfile”文件。
        PrintStream out=new PrintStream(new FileOutputStream("E:\\JAVA\\tempfile",true));

        //写日志信息有用
        System.setOut(out);// 修改输出方向,将输出方向修改到"tempfile"文件。

        out.println("HelloWorld");

    }

4.6、对象流:
  java.io.ObjectInputStream (掌握)
  java.io.ObjectOutputStream (掌握)

4.6.1、对象的序列化与对象的反序列化
对象的序列化(Serialize)指Java对象的存储到文件中。将Java对象的状态保存下来的过程;
对象的反序列化(Deserialize)指将硬盘上的数据重新恢复到内存中,恢复成Java对象。
注意

  • 参与序列化和反序列化的对象,必须实现Serializable接口。
  • 并建议将序列化版本号写出来:
      private static final long serialVersionUID = 1L;
  • transient关键字表示游离的,不参与序列化。在反序列化恢复该Java对象时,无法获得该属性值

4.6.2、Java语言是采用什么机制来区分类的?
第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
第二:如果类名一样,靠序列化版本号进行区分。

4.6.3、为什么建议自定序列化版本号?
Java虚拟机看到一个类实现了Serializable接口后,会为该类自动生成一个序列化版本号。
一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。(这样不好)

序列化对象

//注意:
//    参与序列化的ArrayList集合以及集合中的元素User都需要实现 java.io.Serializable接口。
public class test {
    public static void main(String[] args) throws Exception{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("users"));
        List<User> list=new ArrayList<>();
        list.add(new User(1,"zhangsan"));
        list.add(new User(2, "lisi"));
        list.add(new User(3, "wangwu"));
        User u=new User(4,"zhaoliu");

        // 一次序列化一个对象
        oos.writeObject(u);

        // 序列化一个集合,相当于一次序列化多个对象
        oos.writeObject(list);

        oos.flush();
        oos.close();
    }
}

反序列化对象

      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("users"));
      List<User> list=new ArrayList<>();

      //反序列化一个集合对象
      list=(List<User>)ois.readObject();
      for(User user:list){
          System.out.println(user);
      }

        ois.close();

5)java.io.File类

  • File类不能完成文件的读和写
  • 一个File对象有可能对应的是目录,也可能是文件
  • File只是一个路径名的抽象表示形式

6)IO和Properties的联合使用
6.1、设计理念:
  经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,Java代码不需要改动,不需要重新编译,服务器也不需要重启,就能拿到动态的信息。
这种文件被称为配置文件
当配置文件的内容格式是:
  key1=value
  key2=value
这样时,把这种配置文件叫做属性配置文件

6.2、以 .properties结尾的文件在java中被称为:属性配置文件。
   其中Properties是专门存放属性配置文件内容的一个类。
注意:属性配置文件的key重复的话,value会自动覆盖
  在属性配置文件中井号是注释

        /*
        Properties是一个Map集合,key和value都是String类型。
        将tempfile文件中的数据加载到Properties对象当中。
         */
        // 新建一个输入流对象
        FileReader reader = new FileReader("tempfile");

        // 新建一个Map集合
        Properties pro = new Properties();

        // 调用Properties对象的load方法将文件中的数据加载到Map集合中。
        pro.load(reader); // 文件中的数据顺着管道加载到Map集合中,其中等号=左边作key,右边作value

        // 通过key来获取value
        String username = pro.getProperty("username");
        System.out.println(username);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值