JAVA-14.1-IO流之知识点补充

IO流主要内容已经基本学习完了,这里还有一些边边角角的小知识点,需要进一步学习。
这里写图片描述
1. LineNumberReader:继承自BufferedReader
  特有方法:
    public int getLineNumber():获取行号
    public void setLineNumber(int lineNumber):设置起始行号
    String readLine():读取一行
案例:读取文件,每次读取一行打印并且加上行号

package com.edu_01;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

/**
 * LineNumberReader:
 * public int getLineNumber():获取行号
 * public void setLineNumber(int lineNumber):设置起始行号
   String readLine():读取一行
 *
 */
public class LineNumberReaderDemo {
    public static void main(String[] args) throws IOException {
        //创建LineNumberReader对象
        //public LineNumberReader(Reader in)
        LineNumberReader lnr = new LineNumberReader(new FileReader("a.txt"));

        //默认起始行号从0开始
        //设置其实行号为从10开始
        lnr.setLineNumber(10);

        //一次读取一行
        String line;
        while ((line = lnr.readLine())!=null) {
            //打印每一行的行号和内容
            System.out.println(lnr.getLineNumber()+":"+line);
        }

        //关流
        lnr.close();
    }
}

2. 操作基本数据类型的流 可以操作基本类型的流对象。
  DataInputStream:读数据,继承自FilterInputStream
  DataOutputStream:写数据,继承自FilterOutputStream

案例:给流中写基本类型的数据,并且读取
  注意:读写顺序必须一致,否则数据有问题。

package com.edu_02;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * 读写顺序必须一致,否则数据有问题。
 */
public class DataOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //写数据
        write();
        read();
    }

    private static void read() throws IOException {
        //DataInputStream:读数据
        //创建对象:public DataInputStream(InputStream in)
        DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt"));

        //读数据了,按什么顺序写入就必须按照什么顺序读出来
        System.out.println(dis.readByte());
        System.out.println(dis.readShort());
        System.out.println(dis.readInt());
        System.out.println(dis.readLong());
        System.out.println(dis.readChar());
        System.out.println(dis.readFloat());
        System.out.println(dis.readDouble());
        System.out.println(dis.readBoolean());

        //关流
        dis.close();
    }

    private static void write() throws IOException {
        //public DataOutputStream(OutputStream out)
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));

        //给流关联的文件中写入基本类型的数据
        dos.writeByte(20);
        dos.writeShort(200);
        dos.writeInt(2000);
        dos.writeLong(20000L);

        dos.writeChar(97);
        dos.writeFloat(12.34F);
        dos.writeDouble(23.34);
        dos.writeBoolean(true);

        //关流
        dos.close();
    }
}

3. 内存操作流:解决临时数据存储的问题。
  操作字节数组
    ByteArrayInputStream继承自InputStream
    ByteArrayOutputStream继承自OutputStream
    方法byte[] toByteArray() 将之前写入内存的流转换成字节数组

  操作字符数组
    CharArrayReader继承自Reader
    CharArrayWriter继承自Writer

  操作字符串
    StringReader继承自Reader
    StringWriter继承自Writer

案例:演示操作字节数组
ByteArrayInputStream,ByteArrayOutputStream将数据写到流中保存在内存,并且读取。

package com.edu_03;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //给内存中写数据public ByteArrayOutputStream()
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //给内存中调用方法写数据
        baos.write("hello".getBytes());
        //将写入内存中的数据读取出来
        byte[] buf = baos.toByteArray();//调用这个方法,将之前写入内存中的数据存储到字节数组中
        ByteArrayInputStream bais = new ByteArrayInputStream(buf);//将刚才存储到字节数组中的内容关联上bais

        //只有这样之后,我们才可以直接从bais中读取我们想要的内容
        //一次读取一个字节
        int by;
        while ((by=bais.read())!=-1) {
            System.out.print((char)by);
        }
        //关流
        bais.close();
        baos.close();
    }
}

4. 打印流:
  字节打印流 PrintStream继承自FilterOutputStream
  字符打印流 PrintWriter继承自Writer
特点:
  A:只能操作目的地,不能操作数据源
  B:可以操作任意类型的数据
  C:如果启动了自动刷新,能够自动刷新
  D:可以操作文件的流
注意:什么流可以直接操作文件?
  看流对象的API,如果其构造方法同时有File和String类型的参数,就可以直接操作文件。
案例1:利用字符打印流给文件中书写数据(String类型),需要手动刷新

package com.edu_04;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriterDemo2 {
    public static void main(String[] args) throws IOException {
        //创建字符打印流对象,并开启自动刷新
        //public PrintWriter(Writer out,boolean autoFlush)
        PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

        //给流中写数据
        //pw.write("hello");
        //pw.write("java");

        //注意:如果已经开启了自动刷新功能,必须调用则 println、printf 或 format的时候,才可以实现自动刷新
        pw.println("hello");
        pw.println("java");
        pw.println("world");//调用println这个方法给文件中写数据,1.写数据  2.换行  3.刷新

        //可以操作任意类型的数据
        pw.println(true);
        pw.println(12.34);

        //关流
        pw.close();
    }
}

操作任意类型的数据呢?
  print()
  println():如果启动了自动刷新,能够实现刷新,而且还实现了自动换行。
  如何启动自动刷新?利用构造
    PrintWriter(OutputStream out, boolean autoFlush)
    PrintWriter(Writer out, boolean autoFlush)
  如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作
案例3:利用字符打印流复制java文件(BufferedReader+PrintWriter)

package com.edu_04;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWriterDemo3 {
    public static void main(String[] args) throws IOException {
        /**
         * 案例3:利用字符打印流复制java文件(BufferedReader+PrintWriter)
         */
        //数据源
        BufferedReader br = new BufferedReader(new FileReader("PrintWriterDemo.java"));
        //目的地
        //PrintWriter(Writer out, boolean autoFlush) 
        PrintWriter pw = new PrintWriter(new FileWriter("copy.java"),true);

        //读一行写一行
        String line;
        while ((line=br.readLine())!=null) {
            pw.println(line);//1.写数据  2.换行  3.刷新
        }

        //关流
        pw.close();
        br.close();
    }
}

5. 标准输入输出流
* System类(直接继承自Object)下有这样的两个成员变量:
①标准输入流: public static final InputStream in
案例1:利用标准输入流进行键盘录入,录入后读取流并打印在控制台

package com.edu_05;
import java.io.IOException;
import java.io.InputStream;
public class SystemIn {
    public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        //将键盘录入的数据从输入流中读取出来
        int by;
        while ((by=is.read())!=-1) {
            System.out.print((char)by);
        }
        //关流
        is.close();
    }
}

案例2:用IO流实现键盘录入,一次读取一行数据
分析:
InputStream is = System.in;
BufferedReader是字符缓冲流,是对字符流进行高效操作的
所以,参数必须是字符类型
而我们现在有的是字节类型的流
请问:怎么办呢?  使用转换流

package com.edu_05;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class SystemIn2 {
    public static void main(String[] args) throws IOException {
        /**
         * 案例2:用IO流实现键盘录入,一次读取一行数据
         * InputStream is = System.in;
         * InputSreamReader isr = new InputStreamReader(is)
         * BufferedReader br = new BufferedReader(isr); 
         */
        //将上面的分析写为一部
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        //一次读取一行数据
        System.out.println("请输入你的姓名");
        String name = br.readLine();
        System.out.println("请输入你的年龄");
        String age = br.readLine();

        System.out.println(name+":"+age);
    }
}

②标准输出流: public static final PrintStream out
案例:解析输出语句System.out.println(“helloworld”);

package com.edu_05;
import java.io.PrintStream;
public class SystemOut {
    public static void main(String[] args) {
//      PrintStream ps = System.out;
//      ps.println(true);

        //上面两行合并为一行,底层调用的字节打印流中的方法
        System.out.println(true);
    }
}

6.合并流:
SequenceInputStream类 继承自InputStream,可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
构造:
  SequenceInputStream(InputStream s1, InputStream s2) :将s1和s2合并成一个输入流,先读取s1后读取s2
案例1:把文件DataStreamDemo.java和文件ByteArrayStreamDemo.java写到一个文件Copy.java

package com.edu_06;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;

public class SequenceInputStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建合并流对象
        //SequenceInputStream(InputStream s1, InputStream s2) :将s1和s2合并成一个输入流,先读取s1后读取s2
        //将两个数据源合而为一
        SequenceInputStream sis = new SequenceInputStream(new FileInputStream("PrintWriterDemo.java"), new FileInputStream("SystemIn2.java"));
        //封装目的地
        FileOutputStream fos = new FileOutputStream("copy2.java");

        //一次读写一个字节数组
        byte[] buf = new byte[1024];
        int len;
        while ((len=sis.read(buf))!=-1) {
            //读多少写多少
            fos.write(buf, 0, len);
        }

        //关流
        fos.close();
        sis.close();    
    }
}

7.  对象的序列化和反序列化
  首先应该注意一点:如果一个类不是实现Serializable接口无法把实例化,会报异常java.io.NotSerializableException
  类必须通过实现 java.io.Serializable 接口才能启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
  如何实现序列化?—-让对象所属类的实现序列化接口。
序列化流:把对象按照流一样的方式写到文件或者在网络中传输。
反序列化流:把文件或者网络中的流对象数据还原对象。
  ①ObjectOutputStream:序列化流,继承自OutputStream
  其中的方法writeObject(Object obj) 将指定的对象写入ObjectOutputStream。
  ②ObjectInputStream:反序列化流继承自InputStream
  其中的方法Object readObject() 从 ObjectInputStream 读取对象。
举例:

package com.edu_07;
//创建学生类
import java.io.Serializable;

public class Studnet implements Serializable{
    //实现这个接口不需要实现任何方法,这个接口就是仅仅给Student类,打上了一个可以被序列化的标示
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Studnet(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Studnet() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Studnet [name=" + name + ", age=" + age + "]";
    }
}
package com.edu_07;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建序列化流对象
        //public ObjectOutputStream(OutputStream out)
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));

        //创建一个学生对象,将学生对象写入文件中
        Studnet s = new Studnet("张三", 50);
        oos.writeObject(s);
        // java.io.NotSerializableException
        //类通过实现 java.io.Serializable 接口以启用其序列化功能

        //关流
        oos.close();    
    }
}

此时打开文件oos.txt发现里面的东西看不懂,因为已将对象序列化,需要反序列化才能在控制台看到我们的对象

package com.edu_07;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * 注意:如果一个类不实现Serializable接口无法把实例化,会报异常java.io.NotSerializableException
 * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
 */
public class ObjectInputStreamDemo {
    public static void main(String[] args) throws Exception {
        //创建反序列化流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));

        //读取文件中存储的对象,以实现反序列化
        //readObject()
        Object object = ois.readObject();
        System.out.println(object);

        //关流
        ois.close();

    }
}
//Studnet [name=张三, age=50]

8. Properties(继承自Hashtable,实现map接口,Properties本质是一个map集合)
8.1 Properties 类表示了一个持久的属性集。属性列表中每个键及其对应值都是一个字符串。特点:Properties 可保存在流中或从流中加载。
8.2 Properties的特有功能:
  A:添加元素
    public Object setProperty(String key,String value)给集合添加元素
  B:获取元素
    public String getProperty(String key)根据键获取值
    public Set< String > stringPropertyNames()获取所有的键的集合
8.3 可以和IO流进行结合使用:
  ①把文件中的数据加载到集合中。注意:文件中的数据必须是键值对象形式的且最好是英文(例如:zhangsan=cuihua)。
    public void load(InputStream inStream)加载文件
    public void load(Reader reader)加载文件
  ②把集合中的数据存储到文本文件中,并且是按照键值对形式存储的。
    public void store(OutputStream out,String comments)存储为文件
    public void store(Writer writer,String comments)存储为文件
案例:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”

package com.edu_09;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class PropTest {
    public static void main(String[] args) throws IOException {
        /**
         * 案例:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100” 

          文件中数据是:                       
           zhangsan=3
           lisi=4
           wangwu=5

           分析
           1.创建集合对象
           2.将文件中的键值对加载到集合中
           3.获取多有的键的集合,遍历,判断
           4.如果存在lisi,的话,给集合中重新存储键值对lisi=100
           5.将集合中的数据存储到文件中
         */
        //1.创建集合对象
        Properties prop = new Properties();

        // 2.将文件中的键值对加载到集合中
        prop.load(new FileReader("prop3.txt"));

        //3.获取多有的键的集合,遍历,判断
        Set<String> keys = prop.stringPropertyNames();

        // 4.如果存在lisi,的话,给集合中重新存储键值对lisi=100
        for (String key : keys) {
            if ("lisi".equals(key)) {
                prop.setProperty(key, "100");
                //Map集合特性:如果后来的键值对元素中的键与之前的键值对元素中的键相同,则将之前的值用新来的值覆盖掉
            }
        }

        //5.将集合中的数据存储到文件中
        prop.store(new FileWriter("prop3.txt"), null);
    }
}

案例:我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。
先写一个猜数字小游戏:

package com.edu_10;
import java.util.Random;
import java.util.Scanner;

public class GuessNumber {
    private GuessNumber(){}

    public static void startGame(){
        //生成随机数
        Random random = new Random();
        int number = random.nextInt(100)+1;
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入你猜测的数字");
            int guessNumber = sc.nextInt();
            if (number<guessNumber) {
                System.out.println("大了");
            }else if (number>guessNumber) {
                System.out.println("小了");
            }else {
                System.out.println("恭喜答对了");
                break;
            }
        }
    }
}

编写程序:

package com.edu_10;

import java.io.FileReader;
import java.io.FileWriter;
import java.util.Properties;

public class PropertiesTest {
    public static void main(String[] args) throws Exception {
        //将次数存储到文件中,如果次数大于5次则应该付费玩耍
        //将文件中的键值对加载到集合中
        Properties prop  =new Properties();
        FileReader fr = new FileReader("count.txt");
        prop.load(fr);

        //获取集合中的次数
        String stringcount = prop.getProperty("count");
        int numberCount = Integer.parseInt(stringcount);

        //判断次数
        if (numberCount>5) {
            System.out.println("您已经玩耍5次该付费了");
        }else {
            //启动游戏,并且将次数改变
            GuessNumber.startGame();
            numberCount++;
            //更新集合
            prop.setProperty("count", numberCount+"");
            //蒋欣集合中的数据存储到文件中
            FileWriter fw = new FileWriter("count.txt");
            prop.store(fw, null);
            fw.close();
        }
    }
}

至此。IO流已经讲解完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值