day17-缓冲流转换流序列化流打印流Properties

news2024/9/24 15:26:25

day17_JAVAOOP

课程目标

1. 【理解】什么是缓冲流
2. 【掌握】缓冲流的使用
3. 【理解】转换流
4. 【理解】序列化流
5. 【理解】打印流
6. 【掌握】Properties集合的使用

缓冲流

​ 前期我们学习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强。

缓冲流概述

缓冲流,也叫高效流,是对4个基本的`FileXxx` 流的增强,所以也是4个流,按照数据类型分类

通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非常好的。

既然是这样的话,那么,java开始在设计的时候,它也考虑到了这个问题,就专门提供了带缓冲区的字节类。

这种类被称为:缓冲区类(高效类)

写数据:BufferedOutputStream

读数据:BufferedInputStream

构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。

为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?

 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。
名称
字节缓冲流BufferedInputStream BufferedOutputStream
字符缓冲流BufferedReader BufferedWriter

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

字节缓冲流

构造方法

方法名说明
public BufferedInputStream(InputStream in)创建一个 新的缓冲输入流。
public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流。

字节缓冲输出流

public class BufferedDemo {
        public static void main(String[] args) throws IOException {

        //相当于把字节流进行了一次装
        //FileOutputStream fos = new FileOutputStream("a.txt");
        //BufferedOutputStream bos = new BufferedOutputStream(fos);

        //简单写法
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
        //也可以进行追加
        //BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt",true));

        //写一个字节
        bos.write(97);
        //写一个字节数组
        byte[] by = {97,98,99};
        bos.write(by);
        bos.write("hello".getBytes());

        //指定写一个字节
        bos.write(by,1,2);
        //关闭
        bos.close();
    }
}

字节缓冲输入流

public class BufferedDemo {
    public static void main(String[] args) throws IOException {

        //字节输入缓冲流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));

        //一次读出一个字节
        int read = bis.read();
        System.out.println((char)read);

        //一次读出一个字节数组
        byte[] by = new byte[1024];
        int len;
        while ((len = bis.read(by)) != -1){
            System.out.println(new String(by,0,len));
        }

    }
}

字节缓冲流复制

	public static void main(String[] args) throws IOException {
		//读
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
		//写
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
		//复制
		byte[] bys = new byte[1024];
		int len =0;
		while((len = bis.read(bys)) != -1){
			bos.write(bys,0,len);
		}
		
		bis.close();
		bos.close();
	}

测试

/*
 * 需求:把D:\\工作\\EV已录视频\\01-课程介绍.mp4复制到当前项目目录下的copy.mp4中
 * 
 * 字节流四种方式复制文件:
 * 基本字节流一次读写一个字节:	共耗时:117235毫秒
 * 基本字节流一次读写一个字节数组: 共耗时:156毫秒
 * 高效字节流一次读写一个字节: 共耗时:1141毫秒
 * 高效字节流一次读写一个字节数组: 共耗时:47毫秒
 */
public class CopyMp4Demo {
	public static void main(String[] args) throws IOException {

		long start = System.currentTimeMillis();

		 method1("D:\\工作\\EV已录视频\\01-课程介绍.mp4", "copy1.mp4");
		 method2("D:\\工作\\EV已录视频\\01-课程介绍.mp4", "copy2.mp4");
		 method3("D:\\工作\\EV已录视频\\01-课程介绍.mp4", "copy3.mp4");
		 method4("D:\\工作\\EV已录视频\\01-课程介绍.mp4", "copy4.mp4");	
	
		long end = System.currentTimeMillis();
		System.out.println("共耗时:" + (end - start) + "毫秒");
	}

	// 高效字节流一次读写一个【字节数组】:
	public static void method4(String srcString, String destString)
			throws IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
				srcString));
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream(destString));

		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = bis.read(bys)) != -1) {
			bos.write(bys, 0, len);
		}

		bos.close();
		bis.close();
	}

	// 高效字节流一次读写一个【字节】:
	public static void method3(String srcString, String destString)
			throws IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
				srcString));
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream(destString));

		int by = 0;
		while ((by = bis.read()) != -1) {
			bos.write(by);

		}

		bos.close();
		bis.close();
	}

	// 基本字节流一次读写一个字节数组
	public static void method2(String srcString, String destString)
			throws IOException {
		FileInputStream fis = new FileInputStream(srcString);
		FileOutputStream fos = new FileOutputStream(destString);

		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = fis.read(bys)) != -1) {
			fos.write(bys, 0, len);
		}

		fos.close();
		fis.close();
	}

	// 基本字节流一次读写一个字节
	public static void method1(String srcString, String destString)
			throws IOException {
		FileInputStream fis = new FileInputStream(srcString);
		FileOutputStream fos = new FileOutputStream(destString);

		int by = 0;
		while ((by = fis.read()) != -1) {
			fos.write(by);
		}

		fos.close();
		fis.close();
	}
}

字符缓冲流

构造方法

方法名说明
public BufferedReader(Reader in)创建一个 新的缓冲输入流。
public BufferedWriter(Writer out)创建一个新的缓冲输出流。

字符缓冲输出流

    public static void main(String[] args) throws IOException {

        //字符输出流
        BufferedWriter bw = new BufferedWriter(new FileWriter("c.txt"));

        bw.write(97);
        bw.write("hello");
        char[] chs = {'j','a','v','a',};
        bw.write(chs);
        bw.close();
    }

字符缓冲输入流

    public static void main(String[] args) throws IOException {

        //字符输入流
        BufferedReader br = new BufferedReader(new FileReader("c.txt"));

        //读一个字符
        int read = br.read();
        System.out.println(read);

        //循环读
        int ch;
        while ( (ch = br.read()) != -1){
            System.out.print((char)ch);
        }

        //循环读字符数组
        char[] c = new char[1024];
        int ch2;
        while ( (ch2 = br.read(c)) != -1){
            System.out.print(new String(c,0,ch2));
        }

    }

字符流缓冲流复制

/*
 * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
 * 
 * 数据源:
 * 		a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader
 * 目的地:
 * 		b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter -- BufferedWriter
 */
public class CopyFileDemo {
	public static void main(String[] args) throws IOException {
		// 封装数据源 读
		BufferedReader br = new BufferedReader(new FileReader("a.txt"));
		// 封装目的地 写
		BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

		// 两种方式其中的一种一次读写一个字符数组
		char[] chs = new char[1024];
		int len = 0;
		while ((len = br.read(chs)) != -1) {
			bw.write(chs, 0, len);
			bw.flush();
		}

		// 释放资源
		bw.close();
		br.close();
	}
}

字符缓冲流特有方法

类名方法名说明
BufferedReaderpublic String readLine()一次读取一行文字
BufferedWriterpublic void newLine()写一行行分隔符,由系统属性定义符号
/*
 * 字符缓冲流的特殊方法:
 * BufferedWriter:
 *        public void newLine():根据系统来决定换行符  写入时换行
 */
public static void main(String[] args) throws IOException {

    // 创建字符缓冲输出流对象
    BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

    for (int x = 0; x < 10; x++) {
        bw.write("hello" + x);
        // bw.write("\r\n");//之前换行做法
        bw.newLine();//现在换行做法
        bw.flush();
    }

    bw.close();
}

/*
 * 字符缓冲流的特殊方法:
 * BufferedReader:
 *        public String readLine():一次读取一行数据
 *        包含该行内容的字符串,不包含任何行终止符(不包含换行),如果已到达流末尾,则返回 null
 */
public static void main(String[] args) throws IOException {
    // 创建字符缓冲输入流对象
    BufferedReader br = new BufferedReader(new FileReader("bw2.txt"));

    // String line = br.readLine();//一次读取一行数据
    // System.out.println(line);

    // 最终版代码
    String line = null;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }

    //释放资源
    br.close();
}

转换流

OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流
OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
把字节流转换为字符流。
转换流 <==> 字符流 = 字节流 + 编码表。

字符编码和字符集

字符编码

​ 计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。

编码:字符(能看懂的)–字节(看不懂的)

解码:字节(看不懂的)–>字符(能看懂的)

  • 字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。

    编码表:生活中文字和计算机中二进制的对应规则

字符集

  • 字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0QAh24O-1672536952878)(assets/1_charset.jpg)]

可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。

常见的字符集

  • ASCII字符集

    • ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
    • 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
  • ISO-8859-1字符集

    • 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
    • ISO-8859-1使用单字节编码,兼容ASCII编码
  • GBxxx字符集

    • GB就是国标的意思,是为了显示中文而设计的一套字符集。
    • GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
    • GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
    • GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
  • Unicode字符集

    • Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。
    • 它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
    • UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
      1. 128个US-ASCII字符,只需一个字节编码。
      2. 拉丁文等字符,需要二个字节编码。
      3. 大部分常用字(含中文),使用三个字节编码。
      4. 其他极少使用的Unicode辅助字符,使用四字节编码。
    	/*
    	 * 计算机是如何识别什么时候该把两个字节转换为一个中文呢?
    	 * 在计算机中中文的存储分两个字节:
    	 * 		第一个字节肯定是负数。
    	 * 		第二个字节常见的是负数,可能有正数。但是没影响。
    	 */
    		public static void main(String[] args) {
    //			 String s = "abcde";
    			//[97, 98, 99, 100, 101]  正数不拼
    
    			String s = "我爱你中国";//因为当前我的编码是utf-8 是占三个字节的
    			// [-26, -120, -111, -25, -120, -79, -28, -67, -96, -28, -72, -83, -27, -101, -67]  负数拼
    
    			byte[] bys = s.getBytes();
    			System.out.println(Arrays.toString(bys));
    		}
    	}
    
    

InputStreamReader类

转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法

方法名说明
InputStreamReader(InputStream in)创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName)创建一个指定字符集的字符流。
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");

指定编码读取文件

public class ReaderDemo2 {
	public static void main(String[] args) throws IOException {
		// 创建对象
		// InputStreamReader isr = new InputStreamReader(new FileInputStream(
		// "osw.txt"));

		// InputStreamReader isr = new InputStreamReader(new FileInputStream(
		// "osw.txt"), "GBK");

		InputStreamReader isr = new InputStreamReader(new FileInputStream(
				"osw.txt"), "UTF-8");

		// 读取数据
		// 一次读取一个字符
		int ch = 0;
		while ((ch = isr.read()) != -1) {
			System.out.print((char) ch);
		}

		// 释放资源
		isr.close();
	}

}

OutputStreamWriter类

转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集

构造方法

方法名说明
OutputStreamWriter(OutputStream in)创建一个使用默认字符集的字符输出流。
OutputStreamWriter(OutputStream in, String charsetName)创建一个指定字符集的字符输出流。
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");

指定编码写出数据

/*
 * OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流
 * OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
 * 把字节流转换为字符流。
 * 字符流 = 字节流 +编码表。
 */
public class OutputDemo {
    public static void main(String[] args) throws IOException {
      	// 定义文件路径
        String FileName = "E:\\out.txt";
      	// 创建流对象,默认UTF8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
        // 写出数据
      	osw.write("你好"); // 保存为6个字节
        
        String encoding = osw.getEncoding();
        System.out.println(encoding);//UTF8
        
        osw.close();
      	System.out.println("================");
        
        
		// 定义文件路径
		String FileName2 = "E:\\out2.txt";
     	// 创建流对象,指定GBK编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
        // 写出数据
      	osw2.write("你好");// 保存为4个字节
        
        String encoding1 = osw2.getEncoding();
        System.out.println(encoding1);//GBK
        
        osw2.close();
    }
}

转换流复制

读写的数据编码一定要保持一致

代码实现

public class TransDemo {
    public static void main(String[] args) throws IOException {

        //编码,你好 转成 字节 utf-8 3个字
        //解码,utf-8 3个字
        //解码,3个字节解,GBK只解到2个字节,所以就出现了乱码问题
        //我们在使用转换流时,一定要注意读和写的字符编码一保持一致

        //读 GBK    占两个字节
        InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");

        //写 ide中的 utf-8   占三个字节
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));

        //复制
        char[] chs = new char[1024];
        int len;
        while ((len = isr.read(chs)) != -1){
            osw.write(chs,0,len);
        }
        isr.close();
        osw.close();

    }
}

流的总结

    public static void main(String[] args) throws IOException {
        //基本字节流   构造方法参数 是  路径字符串/File
        FileOutputStream fs = new FileOutputStream("a.txt");
        FileInputStream fis = new FileInputStream("a.txt");
        //基本字符流
        FileWriter fw = new FileWriter("a.txt");
        FileReader fr = new FileReader("a.txt");

        //缓冲字节流  构造方法参数时基本流对象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        //缓冲字符流
        BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));

        //转换输出流  字符流   构造方法参数时基本流对象 +字符集
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),"utf-8");
        //转换输入流  字符流
        InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
    }

序列化流

概述

​ Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化对象的数据对象的类型对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qiSk68Ib-1672536952880)(assets/3_xuliehua.jpg)]

ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

构造方法

方法名说明
public ObjectOutputStream(OutputStream out)创建一个指定OutputStream的ObjectOutputStream。
FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);

序列化常用方法

方法名说明
public final void writeObject (Object obj)将指定的对象写出。

序列化

一个对象要想序列化,必须满足两个条件:

  • 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。

ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

构造方法

方法名说明
public ObjectInputStream(InputStream in)创建一个指定InputStream的ObjectInputStream。

4.3.2 反序列化常用方法

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法

方法名说明
public final Object readObject ()读取一个对象。

反序列化

  • 注意事项

    当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。**发生这个异常的原因如下:

    • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
    • 该类包含未知数据类型
    • 该类没有可访问的无参数构造方法

    Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

序列化和反序列化的实现

/**
 * 序列化: 把对象以流的形式进行流化,存储或者在网络中转输        对象 --- 流数据 ObjcetOutputStream
 * 返序列化: 把文本中的数据据以流的形式进行还原成对象            流数据---对象   ObjectInPutStream
 * 
 * 帮助理解:
 *      序列化:将 Java 对象转换成字节流的过程。
 *      反序列化:将字节流转换成 Java 对象的过程。
 */
public static void main(String[] args) throws IOException, ClassNotFoundException {
    // 由于我们要对对象进行序列化,所以我们先自定义一个类
    // 序列化数据其实就是把对象写到文本文件
    write();//序列化

    // read();//反序列化

}

private static void read() throws IOException, ClassNotFoundException {
    // 创建反序列化对象
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
            "oos.txt"));

    // 还原对象
    Object obj = ois.readObject();

    // 释放资源
    ois.close();

    // 输出对象
    System.out.println(obj); //Person{name='江一燕', age=27}
}

private static void write() throws IOException {
    // 创建序列化流对象
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));

    // 创建对象
    Person p = new Person("江一燕", 27);

    // public final void writeObject(Object obj) 
    oos.writeObject(p); //把对象写入到序列化流中,需要Person实现Serializable接口

    // 释放资源
    oos.close();
}

/**
 * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
 * 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。
 */
public class Person implements Serializable {

    private String name;
    private int age;
}

注意事项

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PE4I6QLJ-1672536952881)(assets/image-20211109134645535.png)]

注意: 假如我序列化时加了private int age, 我反序列化时改成int age ,这时就会报错,原因是序列化时的序列号 与 反序例化的序列号已经不对称了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipFL54ya-1672536952881)(assets/image-20211109134634740.png)]

//解决办法,给这个类序列化时,给出一个序列号进行绑定
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;

反序列化读取序列化对象的顺序要保持一致

测试成员变量不序列化

transient关键字

/**
 *  注意:
 *     我一个类中可能有很多的成员变量,有些成员变量我不想进行序列化。请问该怎么办呢?
 *        使用transient关键字声明不需要序列化的成员变量
 */
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    private String name;
    private transient int age;//transient不会被序例化

Static关键字

/**
 *  注意:
 *     每一个类中可能有很多的成员变量,有些成员变量我不想进行序列化。请问该怎么办呢?
 *        使用static关键字声明不需要序列化的成员变量
 */
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    private String name;
    private static int age;// static不会被序例化

· 声明为 static 和 transient 的成员变量,不能被序列化。

· static 成员变量是描述类级别的属性,transient 表示临时数据

测试

先序列化,再反序列化 看到age并没有值

img

序列化集合

案例需求

  1. 将存有多个自定义对象的集合序列化操作,保存到list.txt文件中。
  2. 反序列化list.txt ,并遍历集合,打印对象信息。

案例分析

1. 把若干学生对象 ,保存到集合中。
2. 把集合序列化。
3. 反序列化读取时,只需要读取一次,转换为集合类型。
4. 遍历集合,可以打印所有的学生信息

代码实现

public class SerTest {
    public static void main(String[] args) throws Exception {
        // 创建 学生对象
        Student student = new Student("老王", "laow");
        Student student2 = new Student("老张", "laoz");
        Student student3 = new Student("老李", "laol");

        ArrayList<Student> arrayList = new ArrayList<>();
        arrayList.add(student);
        arrayList.add(student2);
        arrayList.add(student3);
        // 序列化操作
        // serializ(arrayList);

        // 反序列化  
        read();
    }
    
   private static void read() throws IOException, ClassNotFoundException {

        //反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));

        //进行读取出来
        ArrayList<Student> list = (ArrayList<Student>) ois.readObject();

        for(Student s : list){
            System.out.println(s.getName());
            System.out.println(s.getPwd());
        }
    }

    private static void serializ(ArrayList<Student> arrayList) throws Exception {
        // 创建 序列化流 
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));
        // 写出对象
        oos.writeObject(arrayList);
        // 释放资源
        oos.close();
    }
}

打印流

平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

打印流的分类

名称类名
字节打印流PrintStream
字符打印流PrintWriter

打印流的特点

- 只负责输出数据,不负责读取数据
- 永远不会抛出IOException
- 有自己的特有方法

PrintWriter特点

* 自动换行 println()
* 不能输出字节 可以输出字节以外的内容
* 必须是通过配置 自动刷新 (println,printf,format)
	boolean autoFlush: true 自动刷新 false,不自动刷新
* 包装流本身没有写出功能
* 将字节输出流转换字符输出流

PrintWriter构造方法

方法名说明
PrintWriter(String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush)创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区

PrintWriter特有方法

方法名说明
void write(String s)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
void print(String s)输出字符串, 没有换行
void println(String s)输出字符串并换行. 如果启动了自动刷新, 则会执行自动刷新写入数据
void printf(Locale l, String format, Object… args)使用指定格式字符串和参数将格式化的字符串写入输出流. 如果启动了自动刷新, 则会执行自动刷新写入数据
void format(Locale l, String format, Object… args)使用指定格式字符串和参数将格式化的字符串写入输出流. 如果启动了自动刷新, 则会执行自动刷新写入数据

字符打印流特点

/*
 * 打印流
 * 字节打印流   PrintStream
 * 字符打印流   PrintWriter
 *
 * 打印流的特点:
 *        A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。
 *        B:可以操作任意类型的数据。
 *        C:如果启动了自动刷新,能够自动刷新。
 *        D:该流是可以直接操作文本文件的。
 *           哪些流对象是可以直接操作文本文件的呢?
 *           FileInputStream
 *           FileOutputStream
 *           FileReader
 *           FileWriter
 *           PrintStream
 *           PrintWriter
 *           看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。
 *
 */

public static void main(String[] args) throws IOException {
    //字符打印流对象
    PrintWriter pw = new PrintWriter("pw.txt");

    //A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。
    pw.write("hello");
    pw.write("world");
    pw.write("java");
    //为什么没有写进去呢?
    //字符流并不会像字节流一样直接操作数据,字符流会先存入缓存区中,并没有直接写入文本中,需要刷新

    //close相当于启动了自动刷新,能够自动刷新
    pw.close();
}


字符 打印流自动刷新

/*
 * 1:可以操作任意类型的数据。
 *        print()
 *        println()
 * 2:启动自动刷新: PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
 *    调用println()才可以自动刷新
	其实等价于于:
 *            bw.write();
 *            bw.newLine();
 *            bw.flush();
 */
public static void main(String[] args) throws IOException {

    // 创建打印流对象,启动自动刷新:PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
    PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
    //可以操作任意类型的数据。
	// print()这个方法不会自动刷新
    pw.print(true);
    pw.print(100);
    pw.print("hello");
    pw.close();

    // 创建打印流对象
    PrintWriter pw2 = new PrintWriter(new FileWriter("pw3.txt"), true);
    //println() 这个方法不仅仅自动刷新了,还实现了数据的换行。
    pw2.println("world");
    pw2.println(false);
    pw2.println(200);
    //pw2.close();
}

字节打印流

    public static void main(String[] args) throws IOException {

        //创建字节打印流对象
        PrintStream ps = new PrintStream(new FileOutputStream("c.txt"));//c.txt位于项目根目录

        ps.write(97);
        ps.write("hello".getBytes());

        ps.print("hello");
        ps.print(1314);
        ps.print(true);

        ps.println("hello");
        ps.println("1314");
        ps.println(true);

        //关闭流
        // ps.close();
    }

标准输入输出流

获取标准输出流PrintStream

/*
 * 标准输入输出流
 * System类中的两个成员变量:
 *        public static final InputStream in “标准”输入流。
 *        public static final PrintStream out “标准”输出流。
 *
 *        InputStream is = System.in;
 *        PrintStream ps = System.out;
 */
public static void main(String[] args) throws IOException {

    // 有这里的讲解我们就知道了,这个输出语句其本质是IO流操作,把数据输出到控制台。
    System.out.println("helloworld");

    // 获取标准输出流对象
    PrintStream ps = System.out;
    ps.println("helloworld");

    ps.println();
    // ps.print();//空参方法不存在

    System.out.println();
    // System.out.print();//所以空参不能使用
}

获取标准输入流InputStream

/*
 * System.in 标准输入流。是从键盘获取数据的
 *
 * 键盘录入数据:
 *        A:main方法的args接收参数。
 			java hello.java
 *           java Hello hello world java
 *        B:Scanner
 *           Scanner sc = new Scanner(System.in);
 *           String s = sc.nextLine();
 *           int x = sc.nextInt()
 *        C:通过字符缓冲流包装标准输入流实现
 *           BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 */
public static void main(String[] args) throws IOException {

    //获取标准输入流
    // InputStream is = System.in;
    // BufferedReader br = new BufferedReader(new InputStreamReader(is));

    //通过字符缓冲流包装标准输入流实现,但只能读字符串,因为有scnner对象,提供了很多方法
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("请输入一个字符串:");
    String line = br.readLine();
    System.out.println("你输入的字符串是:" + line);

    System.out.println("请输入一个整数:");
    line = br.readLine();
    int i = Integer.parseInt(line);
    System.out.println("你输入的整数是:" + i);
}


Properties集合

Properties集合概述

- 是一个Map体系的集合类
- Properties可以保存到流中或从流中加载
- 属性列表中的每个键及其对应的值都是一个字符串

Properties基本使用

public class PropertiesDemo01 {
    public static void main(String[] args) {
        //创建集合对象
//        Properties<String,String> prop = new Properties<String,String>(); //错误
        Properties prop = new Properties();

        //存储元素
        prop.put("itfxp001", "林青霞");
        prop.put("itfxp002", "张曼玉");
        prop.put("itfxp003", "王祖贤");

        //遍历集合
        Set<Object> keySet = prop.keySet();
        for (Object key : keySet) {
            Object value = prop.get(key);
            System.out.println(key + "," + value);
        }
    }
}

Properties集合的特有方法

方法名说明
Object setProperty(String key, String value)设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
String getProperty(String key)使用此属性列表中指定的键搜索属性
Set stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串

代码演示

/*
 * 特殊功能:
 * public Object setProperty(String key,String value):添加元素
 * public String getProperty(String key):获取元素
 * public Set<String> stringPropertyNames():获取所有的键的集合
 */
public static void main(String[] args) throws IOException, ClassNotFoundException {
    // 创建集合对象
    Properties prop = new Properties();

    // 添加元素
    prop.setProperty("张三", "30");
    prop.setProperty("李四", "40");
    prop.setProperty("王五", "50");

    // public Set<String> stringPropertyNames():获取所有的键的集合
    Set<String> set = prop.stringPropertyNames();
    for (String key : set) {
        String value = prop.getProperty(key);//获取元素(value)
        System.out.println(key + "---" + value);
    }
}

Properties和IO流相结合的方法

方法名说明
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流

代码示例

/*
 * 这里的集合必须是Properties集合:
 * public void load(Reader reader):把文件中的数据读取到集合中
 * public void store(Writer writer,String comments):把集合中的数据存储到文件
 */
public static void main(String[] args) throws IOException, ClassNotFoundException {

    // myLoad();
    myStore();
}

//读数据
private static void myStore() throws IOException {
    // 创建集合对象
    Properties prop = new Properties();

    prop.setProperty("江一燕", "27");
    prop.setProperty("jack", "30");
    prop.setProperty("肉丝", "18");

    //public void store(Writer writer,String comments) 把集合中的数据存储到文件
    FileWriter w = new FileWriter("name.properties");
    //写
    prop.store(w, "写入文件的说明:因为我要学习所有我要写入");//comments:信息的描述
    w.close();
}

//写数据
private static void myLoad() throws IOException {

    Properties prop = new Properties();
    // public void load(Reader reader) 把文件中的数据读取到集合中
    // 注意:这个文件的数据必须是键值对形式
    FileReader r = new FileReader("name.properties");
    //读
    prop.load(r);
    r.close();		
    System.out.println("prop:" + prop);
}

nts) | 将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流 |
| void store(Writer writer, String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流 |

代码示例

/*
 * 这里的集合必须是Properties集合:
 * public void load(Reader reader):把文件中的数据读取到集合中
 * public void store(Writer writer,String comments):把集合中的数据存储到文件
 */
public static void main(String[] args) throws IOException, ClassNotFoundException {

    // myLoad();
    myStore();
}

//读数据
private static void myStore() throws IOException {
    // 创建集合对象
    Properties prop = new Properties();

    prop.setProperty("江一燕", "27");
    prop.setProperty("jack", "30");
    prop.setProperty("肉丝", "18");

    //public void store(Writer writer,String comments) 把集合中的数据存储到文件
    FileWriter w = new FileWriter("name.properties");
    //写
    prop.store(w, "写入文件的说明:因为我要学习所有我要写入");//comments:信息的描述
    w.close();
}

//写数据
private static void myLoad() throws IOException {

    Properties prop = new Properties();
    // public void load(Reader reader) 把文件中的数据读取到集合中
    // 注意:这个文件的数据必须是键值对形式
    FileReader r = new FileReader("name.properties");
    //读
    prop.load(r);
    r.close();		
    System.out.println("prop:" + prop);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/131849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

babylon.js魔方建模

本文主要内容可能和babylon并无太紧密的关联&#xff0c; 主要是对旋转&#xff08; 空间想象力 &#xff09;的练习。 本来想写个魔方练练&#xff0c;就想着顺便练练baboly. 结果反正是最重要的交互逻辑没有实现。 标题已经说明了本文的主题是建模&#xff0c;也就是说&…

ArcGIS基础实验操作100例--实验29矢量数据空间校正

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验29 矢量数据空间校正 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

android中service实现原理分析

前言&#xff1a; 一开始的目标是解决各种各样的ANR问题的&#xff0c;我们知道&#xff0c;ANR总体上分有四种类型&#xff0c;这四种类型有三种是和四大组件相对应的&#xff0c;所以&#xff0c;如果想了解ANR发生的根因&#xff0c;对安卓四大组件的实现流程是必须要了解的…

Odoo 16 企业版手册 - 库存管理之产品管理

产品管理 记录与产品相关的每个方面对于有效维护库存至关重要。Odoo 库存模块使您可以在数据库中配置新产品&#xff0c;这些产品将有效跟踪和监控所有操作&#xff0c;以加强各自产品的库存管理。库存模块中的产品配置过程与销售和购买模块的流程几乎相似。您将在库存的主菜单…

一步一步学爬虫(4)数据存储之CSV文件存储

一步一步学爬虫&#xff08;4&#xff09;数据存储之CSV文件存储4.3 CSV文件存储4.3.1 写入4.3.2 读取4.3.3 总结4.3 CSV文件存储 CSV&#xff0c;全称Comma-Separated Values&#xff0c;中文叫做逗号分隔值或字符分隔值&#xff0c;其文件以纯文本形式存储表格数据。CSV文件…

java.lang.OutOfMemoryError: GC overhead limit exceeded问题分析及解决

一、错误重现 2022-12-29 10:12:07.210 ERROR 73511 --- [nio-8001-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.…

SQL刷题宝典-MySQL速通力扣困难题

&#x1f4e2;作者&#xff1a; 小小明-代码实体 &#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/as604049322 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 欢迎讨论&#xff01; 本手册目录&#xff1a; 文章目录前言Markdown导入数据库python脚…

奇安信 工业互联网安全发展与实践 报告 学习笔记一 欢迎扶正

声明 本文是学习2021工业互联网安全发展与实践分析报告. 下载地址而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 主要观点 工业系统安全漏洞数量增长显著放缓&#xff0c;但超高危漏洞数量却大幅增加。统计显示&#xff0c;2021年&#xff0c;国内外…

Linux 软件包管理器 yum

1.什么是软件包 在Linux下安装软件&#xff0c;一个通常的办法是下载到程序的源代码&#xff0c;并进行编译&#xff0c;得到可执行程序。但是这样太麻烦了&#xff0c;于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上&…

再见2022

大家好&#xff0c;我是bigsai&#xff0c;好久不见。看了上一篇更新时间&#xff0c;大概已经停更近10个月(呜呜后面还会坚持的)&#xff0c;在2022的最后一天&#xff0c;这一篇也算是对这一年做个总结。期间也收到一些朋友的问候和鼓励&#xff0c;确实自己在读研期间的前两…

山东大学2022-2023非关系型数据库(Nosql)期末考试

写在前面的话&#xff1a; 今年线上开卷考试&#xff0c;Nosql考试软工&#xff08;限选课&#xff09;和大数据&#xff08;必修课&#xff09;是一套试题&#xff0c;因此大数据所学的许多内容考试并无涉及。考察点主要以学过的四类Nosql数据库的相关知识为主。 试题如下&…

引用量超1400的经典语义分割方法BiSeNet解读

今天给大家分享语义分割领域非常经典的一篇论文&#xff1a;BiSeNet&#xff0c;该论文发表在了ECCV2018上&#xff0c;引用量超过1400。 开源代码地址&#xff1a;https://github.com/ycszen/TorchSeg 1.动机 语义分割任务&#xff0c;即为图片的每个像素分配一个标签&#…

嵌入式 程序调试之gdb+gdbserver+vscode可视化调试

嵌入式 程序调试之gdbgdbservervscode可视化调试 一、简述 记--使用过visual studio的都知道&#xff0c;它的单步调试真的好用&#xff0c;可以直接在源码下断点&#xff0c;实时查看内存变量、寄存器等相关信息。嵌入式linux开发多用的是gdb, 都是命令行执行的&#xff0c;毕…

python特殊数据类型应用(1)字典类型

目录python中特殊数据类型应用&#xff08;1&#xff09;字典类型字典类型定义字典类型注意事项字典类型的访问python中特殊数据类型应用&#xff08;1&#xff09;字典类型 python作为最流行的几种开发语言之一&#xff0c;在数据类型上和传统的c、c和java等有很大的不同&…

Typora使用方法

自用&#xff0c;有错误请谅解 tpora破解版使用学习使用&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Wj46k3iVIzr-7kwQstp9nQ 提取码&#xff1a;2sa8 来源教程网址&#xff1a;Typora一款 Markdown 编辑器和阅读器 记得更改图片位置&#xff0c;以后就是相对路径…

babel及其使用

什么是Babel&#xff1f; Babel 是一个工具链&#xff0c;由大量的工具包组成&#xff0c;接下来我们逐步了解。主要用于将 ECMAScript 2015 版本的代码转换为向后兼容的 JavaScript 语法&#xff0c;以便能够运行在当前和旧版本的浏览器或其他环境中。 核心库 babel/core B…

‘this’不能用于常量表达式错误(C++)【问题解决】

目录 一、报错问题 1、代码 test.h test.cpp 2、问题描述 二、网上解决思路 三、解决方案 【元旦快乐&#x1f339;&#xff0c;新年快乐&#x1f389;】 最近在编译程序时出现了“ ‘this’不能用于常量表达式错误(C )”的报错问题&#xff0c;查阅多位博主写的文章后&…

mysql 性能优化

mysql 调优可以从这个四个方面来看 1.性能监控 1.1 show profile for query n 查看具体的sql语句各阶段执行时间 show profiles; show profile for query n; 1.2 performance schema 监控mysql 整个服务器中发生的各种事件。 performance schema 表中的数据不会持久化的磁…

一文搞定垃圾回收的三色标记法

我们之前介绍了各种常见垃圾回收器的基本原理&#xff0c;本小节我们讨论一个更深入的问题——垃圾回收器的底层是如何做的。 在并发标记的过程中&#xff0c;因为标记期间应用线程还在继续跑&#xff0c;对象间的引用可能发生变化&#xff0c;多标和漏标的情况就有可能发生。…

计算机视觉(CV)领域Transformer最新论文及资源整理分享

Transformer由论文《Attention is All You Need》提出&#xff0c;现在是谷歌云TPU推荐的参考模型。Transformer模型最早是用于机器翻译任务&#xff0c;当时达到了SOTA效果。Transformer改进了RNN最被人诟病的训练慢的缺点&#xff0c;利用self-attention机制实现快速并行。并…