IO中的各种流简介及其代码演示
发布日期:2022-02-01 14:28:21 浏览次数:37 分类:技术文章

本文共 12239 字,大约阅读时间需要 40 分钟。

一.缓冲流

作用:主要是为了增强基础流的功能而存在的,提高了流的工作效率【读写效率】

注意:如果使用记事本创建的文件,文件是utf-8或者unicode编码,文件的前面有一个BOM(Byte Order Mark)头,BOM作用指定文件使用的编码类型。GBK编码没有添加bom头。

utf-8:EF BB BF
unicode 小端: FF FE 66 00
unicode 大端 :FE FF 00 66

1.1 BufferedInputStream类

字节输入缓冲流, BufferedInputStream本身不具备读写文件的能力,所以需要借助FileInputStream来读取文件的数据。

BufferedInputStream 缓冲输入字节流,缓冲输入字节流的出现主要是为了提高读取文件数据的效率。
其实BufferedInputStream类内部只不过维护了一个8kb的字节数组而已。
注意:凡是缓冲流都不具备读写文件的能力。

代码案例:

package BufferedStream;import java.io.BufferedInputStream;import java.io.FileInputStream;import java.io.IOException;public class BufferedInputStreamTest {    public static void main(String[] args) throws IOException {        FileInputStream fis=new FileInputStream("aaa.txt");        BufferedInputStream bis=new BufferedInputStream(fis);            //可以一步到位的写:           BufferedInputStream bis=new BufferedInputStream(new FileInputStream("aaa.txt"));/*		//没有使用缓冲区的		byte[] arr = new byte[1024];		int len = 0;		while((len = input.read(arr)) != -1) {			String string = new String(arr, 0, len);		}		*/		    使用缓冲区读取        byte[] arr=new byte[1024];        int len=-1;        while ((len=bis.read(arr))!=-1){           String string=new String(arr,0,len);            System.out.print(string);        }        bis.close();    }}

1.2 BufferedOutputStream类

使用BufferedOutputStream输出信息和往OutputStream输出信息完全一样,只不过BufferedOutputStream有一个flush()方法用来将缓存区的数据强制输出完。

代码案例:

package BufferedStream;import java.io.BufferedOutputStream;import java.io.FileOutputStream;import java.io.IOException;public class BufferedOutputStreamTest {    public static void main(String[] args) throws IOException {        FileOutputStream fos=new FileOutputStream("good.txt");        BufferedOutputStream bos=new BufferedOutputStream(fos);        for (int i = 0; i <10 ; i++) {            bos.write("好好学习天天向上".getBytes());            bos.flush();        }        bos.close();    }}

1.3BufferedReader类

BufferedReader由Reader类扩展而来,提供通用的缓冲方式文本读取而且提供了很实用的readLine,读取一个文本行,从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。

  BufferedReader和BufferedWriter为默认带有缓冲的字符输出输入流,因为有缓冲区所以效率比没有缓冲区的高

代码实现:

public class BufferedReaderDemo {	public static void main(String[] args) throws IOException {				//实例化缓冲字符流的对象		BufferedReader reader = new BufferedReader(new FileReader(“aaa.txt”));		//方式一:read循环读取		/*		//读取		char[] arr = new char[8];		int len = 0;		while((len = reader.read(arr)) != -1) {			String string = new String(arr, 0, len);		}		*/		 /* 方式二:字符数组读取        int len=0;        String str=null;        char[] chars=new char[1024];        while ((len=br.read(chars))!=-1){            str=new String(chars,0,len);//将读到的字符装换成字符串  从0开始转换长度为len        }        System.out.print(str);*/				//方式三:readLine循环读取		String result = null;		while((result = reader.readLine()) != null) {			System.out.println(result);		}					reader.close();	}}

1.4BufferedWriter类

public class BufferedWriterDemo {	public static void main(String[] args) throws IOException {		// 实例化FIle对象		File file = new File("test33.txt");		//实例化缓冲字符输出流		BufferedWriter writer = new BufferedWriter(new FileWriter(file,true));		// 写		writer.write("今天天气还可以");		// 作用:主要就是为了换行		writer.newLine();		// 刷新		writer.flush();				//关闭		writer.close();	}}

2.内存流

输入和输出都是从文件中来的,当然,也可将输出输入的位置设置在内存上,这就需要ByteArrayInputStreamByteArrayOutputStream

ByteArrayInputStream:将内容写入到内存中,是Inputstream的子类
ByteArrayOutputStream:将内存中数据输出,是OutputStream的子类
此时的操作应该以内存为操作点
案例:接下来一个字母大小写转换的程序让我们了解内存流

public class ByteArrayInputStreamTest {    public static void main(String[] args) throws IOException {             String str="HELLO";//先声明一个要转换的字符串        ByteArrayInputStream bais= new ByteArrayInputStream(str.getBytes());//因为内存输入流构造只支持字节需要将字符串转成字节        ByteArrayOutputStream baos=new ByteArrayOutputStream();//这是无参的        int a=0;//定义一个变量 读取时候进行判断        while ((a=bais.read())!=-1){            baos.write(Character.toLowerCase((char)a));//将读出来的字节变成字符,再将字符转换成小写字母写出去            baos.flush();//刷新,将缓冲区中的数据刷新到内存,在这里可以不刷新        }           bais.close();           baos.close();        String s = baos.toString();//将内存中的数据转成字符串在输出        System.out.println(s);    }}

注意:内存操作流的操作对象,一定是以内存为主准,不要以硬盘为准。

三. 标准输入输出流

Java的标准输入/输出分别通过System.in和System.out实现,默认情况下分别代表是键盘和显示器

PrintStream类:PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。

PrintWriter类:向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream中的所有 print方法。它不包含用于写入原始字节的方法

使用PrintStream的print方法打印数字出现的是数字,使用其write方法打印数字 会打印其对应的字符

public class Demo2 {    public static void main(String[] args) throws FileNotFoundException {       /* PrintStream ps=new PrintStream("stifly.txt");//使用PrintStream的print方法打印数字出现的数字        //使用PrintStream的print方法打印数字出现的是数字,使用其write方法打印数字 会打印其对应的字符        ps.write(97);//a        ps.println();        ps.println(97);//97        ps.println('a');        ps.println("java");        ps.print("中国");*/        PrintStream ps=new PrintStream("systemout.txt");        System.setOut(ps);//重定向到指定的ps对应的文件systemout.txt,打印的内容便会出现在systemout.txt        System.out.println("好久不见");        ps.close();    }}

可以使用system.in来获取键盘输入对象并接收

在这里插入图片描述

接下来通过输入流来键盘输入字符串,然后通过标准输出流输出,输入为over时候结束

public class Demo {    public static void main(String[] args) throws IOException {       InputStream in=System.in;//获取标准输入流对象(注意这里输入的是字节)        InputStreamReader isr=new InputStreamReader(in);//创建转换流对象        BufferedReader br=new BufferedReader(isr);//放入缓冲区        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));        while (true){            String line = br.readLine();            System.out.println(line);            if(line.equals("over")){                break;            }        }    }}

四. 对象流(序列化与反序列化)

流中流动的数据是对象

将一个对象写入到本地文件(硬盘)中,被称为对象的序列化
将一个本地文件中的对象读取出来到内存中,被称为对象的反序列化
使用对象流
ObjectInputStream: 对象输入流(将对象从硬盘读出,到内存中 这是可以显示到控制台的,即反序列化)
ObjectOutputStream:对象输出流(将内存中的对象读入到硬盘,即序列化)

注意:

序列化对象的类型必须实现Serializable接口。否则不能序列化。
如果向将多个对象序列化到本地,可以借助于集合,【思路:将多个对象添加到集合中,将集合的对象写入到本地文件中,再次读出来,获取到的仍然是集合对象,遍历集合】。
对象中那些字段可以不序列化:
1 transient 修饰的字段
2 静态的字段
在要序列化类中添加字段,保证序列化和反序列化是同一个类
private static final long serialVersionUID = 100L;

接下来创建一个学生类对象对其实现序列化和反序列化 必须实现Serializable接口

import java.io.Serializable;/* * 佛祖保佑,永无BUG! * 不能序列化:(1)transient修饰的成员(2)静态成员 * 序列化版本id:判断序列化和反序列化是否是同一个类. */public class Student implements Serializable {    //序列化版本id  不加版本id的话  当序列化的对象属性和反序列化属性不一致时侯 系统会认为不是同       一个类  会报异常       比如序列化的时候没有email,反序列化的时候加了**email**属性  如果没有版本id来标记这是同一个类的话  就会报错认为不是同一个类    加了id之后序列化在反序列化就正常运行了  但是Email不会有只     private static final long serialVersionUID=1000L;    private String name;    private transient int age; //transient:瞬间的  加了次关键字的无法被序列化    private String address;    public static String country="中国";  静态的也无法序列化    //修改    private String email;//序列化时候加了  反序列的时候没有  测试版本ID的作用    public Student(String name, int age, String address) {        this.name = name;        this.age = age;        this.address = address;    }    public Student() {    }    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 String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email;    }    @Override    public String toString() {        return "Student{" +                "name='" + name + '\'' +                ", age=" + age +                ", address='" + address + '\'' +                '}';    }}

测试

* 使用ObjectOutputStream实现序列化 * 使用ObjectInputStreaam实现反序列化 * Serializable * Deserializable */public class Demo12 {    public static void main(String[] args) throws Exception{        //writeObject();        readObject();    }    public static void writeObject() throws Exception{        //1创建流        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("stu.bin"));        //2序列化        Student shaobo=new Student("少泊", 16, "北京");        Student zhangsan=new Student("张三", 16, "北京");        Student lisi=new Student("李四", 16, "北京");        ArrayList
list=new ArrayList<>(); list.add(shaobo); list.add(zhangsan); list.add(lisi); oos.writeObject(list); //3关闭 oos.close(); System.out.println("序列化完毕"); }//反序列化 将硬盘文件中的数据读到内存控制台显示 public static void readObject() throws Exception{ //1创建流 ObjectInputStream ois=new ObjectInputStream(new FileInputStream("stu.bin")); //2读取// Student stu1= (Student) ois.readObject();// Student stu2= (Student) ois.readObject();// Student stu3= (Student) ois.readObject(); ArrayList
list = (ArrayList
) ois.readObject();//这里反序列化返回的是object类型需要转换成集合类型 在进行遍历 for (Student student : list) { System.out.println(student.toString()); } //3关闭 ois.close(); }}

五. RandomAccessFile类

RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。

* 使用RandomAccessFile读写文件 */public class Demo1 {    public static void main(String[] args) throws Exception{        //write();        read();    }    public static void write() throws Exception{        //1创建对象        RandomAccessFile raf=new RandomAccessFile("ran.txt", "rw");        //2写入        raf.writeUTF("张三");        raf.writeInt(20);        raf.writeDouble(170.5);        raf.writeBoolean(true);        raf.writeUTF("李四");        raf.writeInt(22);        raf.writeDouble(180.5);        raf.writeBoolean(false);        //3关闭        raf.close();        System.out.println("写入完毕");    }    public static void read() throws Exception{        //1创建对象        RandomAccessFile raf=new RandomAccessFile("ran.txt", "r");        //设置跳过张三,设置读取指针的偏移量,从0开始//        raf.seek(21);//        raf.seek(21);        //跳过21个字节,从当前位置        raf.skipBytes(21);        //raf.skipBytes(21);        //2读取        String name = raf.readUTF();        int age = raf.readInt();        double height = raf.readDouble();        boolean b = raf.readBoolean();        System.out.println(name+" "+age+" "+height+" "+b);        //3关闭        raf.close();    }}

六. Properties类

是Map接口的一个实现类,并且是Hashtable的子类

因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。如果在“不安全”的 Properties 对象(即包含非 String 的键或值)上调用 store 或 save 方法,则该调用将失败。类似地,如果在“不安全”的 Properties 对象(即包含非 String 的键)上调用 propertyNames 或 list 方法,则该调用将失败。

常用方法getProperty(String key)           用指定的键在此属性列表中搜索属性。setProperty(String key, String value)     调用 Hashtable 的方法 put。(相当于添加键值对,但是String类型)遍历可采用  stringPropertyNames() 方法,获取一个keyset的集合 再根据遍历key来获取值list(PrintStream out)     将属性列表输出到指定的输出流,将properties中的键值对输出到指定文件中)例如:list(new PrintStream("aaa.txt"));list(System.out);  将properties中的键值对元素输出到控制台load(InputStream inStream)  将指定文件中的属性加载出来
Properties集合中元素也是以键值对的形式存在的

Properties特点:

1 存储属性名和属性值
2 属性名和属性值都是字符串
3 和流有关系
4 没有泛型

* 使用Properties集合保存数据 */public class Demo2 {    public static void main(String[] args) throws Exception{        //创建集合        Properties properties=new Properties();        //1添加        properties.setProperty("name", "少泊");        properties.setProperty("age", "20");        properties.setProperty("address", "北京");        //2遍历        Set
keyset = properties.stringPropertyNames(); for (String key : keyset) { System.out.println(key+"===="+properties.getProperty(key)); } //3和流有关的方法 //3.1 list方法 System.out.println("-----------list---------"); properties.list(new PrintStream("prop.properties")); properties.list(System.out); //3.2load方法 System.out.println("-----------load-----------------"); Properties properties2=new Properties(); properties2.load(new FileReader("prop2.properties"));//将prop2.properties中的键值加载出来 properties2.list(System.out);//将加载出来的内容打印出来 //3.3store方法 properties2.store(new FileWriter("prop3.properties"), "信息"); //3.4System.getProperties(); System.out.println("---------System.getProperties();----------"); Properties sysprop = System.getProperties(); sysprop.setProperty("myname", "hello"); sysprop.list(System.out); }}

转载地址:https://blog.csdn.net/shunshizhen120412/article/details/98990359 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Request 对象
下一篇:详细的java单例模式线程安全问题详解

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月24日 15时30分18秒