字符输出流与序列化

编程入门 行业动态 更新时间:2024-10-25 14:22:01

<a href=https://www.elefans.com/category/jswz/34/1771063.html style=字符输出流与序列化"/>

字符输出流与序列化

1. BufferedWriter字符流

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了
创建对象

BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流

测试构造方法以及write方法

public static void main(String[] args) {try {// 1.创建FileOutputStream输出流,将数据输出到d.txt文件中//	true表示写出的数据将会追加文件的末尾, 而不是覆盖原来的数据Writer out = new FileWriter( "d:/demoout/d.txt", true );// 创建BufferedWriter缓冲区输出流, 输出FileWriter流中的数据BufferedWriter bufout = new BufferedWriter( out );// 2.开始往d.txt中写数据//输出单个字符bufout.write( 97 ); //abufout.write( 98 ); //bbufout.write( 99 ); //cbufout.write( 100 );//dbufout.write( 101 );//ebufout.write( 13 );//回车bufout.write( 10 );//换行//输出字符数组bufout.write( "ABCDE\r\n".toCharArray() );//输出字符数组中的一部分,从下标1处(b)开始,输出后面的3个元素(BCD)bufout.write( "ABCDE\r\n".toCharArray(), 1, 3 );//输出字符串bufout.write( "hello\r\n" );//输出字符串中的一部分,从下标1处(e)开始,输出后面的3个字符(ell)bufout.write( "hello\r\n", 1, 3 );// 3.关闭流(释放资源)System.out.println( "成功将数据写入d.txt文件,关闭流..." );bufout.close();} catch (Exception e) {e.printStackTrace();}
}

这里大家可以自行测试BufferedWriter输出流写出数据的效率

2.练习

2.1.字符写出流测试

把数据写出到指定文件中。如果文件不存在会自动创建,文件夹不存在会报错

package cn.tedu.out;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;//这个类用来测试字符流输出数据
//总结:
//效率问题:BufferedWriter  > FileWriter,因为BufferedWriter底层为了一个char[],默认大小是8*1024字节相当于8K
//写出时,把数据填满数组后一把保存在磁盘中,比一个一个给要快,减少了程序和磁盘的交互次数,提高程序的执行效率。
public class Test2_Writer {public static void main(String[] args) {method();// 普通的字符流输出数据method2();// 高效的字符流输出数据}private static void method2() {Writer out = null;try {// 1,创建字符输出流对象
//         out = new BufferedWriter(new FileWriter("D:\\iotest\\a.txt"));//在覆盖数据out = new BufferedWriter(new FileWriter("D:\\iotest\\a.txt",true));//想追加// 2,开始写出数据out.write(90);out.write(91);out.write(92);out.write("io");out.write("test");} catch (IOException e) {e.printStackTrace();} finally {try {// 3,释放资源,放入finally块中,保证资源一定会被释放out.close();} catch (IOException e) {e.printStackTrace();}}}private static void method() {Writer out2 = null;// 声明变量,因为finally要用try {// 1,创建字符输出流对象// Writer out = new Writer();//报错,因为Writer是抽象类不能new// Writer out = new FileWriter(new File("D:\\iotest\\a.txt"));// out2 = new FileWriter("D:\\iotest\\a.txt");//默认就是覆盖数据的模式// 需求:保持原有数据,在原有数据的末尾处追加数据out2 = new FileWriter("D:\\iotest\\a.txt", true);// true表示要追加数据// 2,开始写出数据out2.write(100);out2.write("hello");out2.write("java");} catch (IOException e) {e.printStackTrace();} finally {try {// 3,释放资源,放入finally块中,保证资源一定会被释放out2.close();} catch (IOException e) {e.printStackTrace();}}}
}

2.2.文件复制

前面我们学习了如何通过[字节输入流]和[字符输入流]读取指定文件中的内容
也学习了如何通过[字节输出流]和[字符输出流]如何将数据输出(写入)到指定的文件中
而我们在日常生活中, 将计算机硬盘中的某一个文件(例如,d:/iotest/src/test.txt)复制到另一个位置(例如,d:/iotest/tar/test-副本.txt), 这其实就是文件的读取和写入!

  • 通过输入流先将源文件(test.txt)中的数据读取到Java程序中
  • 再将读取到Java程序中的数据写入到目标文件中(test-副本.txt)
    复制文件文件的代码如下所示
public class CopyFileDemo {public static void main(String[] args) {//1.定义变量, 存储源文件路径String source = "d:/iotest/src/test.txt";//2.定义变量, 存储目标文件路径String target = "d:/iotest/tar/text-副本.txt";try {//3.调用copyTextFile方法复制文本文件copyTextFile( source, target );System.out.println( source+" 文件复制成功!" );} catch (Exception e) {System.out.println( source+" 文件复制失败!" );e.printStackTrace();}}/** 方法作用: 复制指定位置的文本文件到另一位置(只能复制文本文件)* source参数: 源文件路径(即,要复制的文件路径)* target参数: 目标文件路径(即,通过源文件复制的副本文件路径)*/public static void copyTextFile(String source, String target) throws Exception {//1.定义带缓冲区的字符输入流, 读取源文件中的数据BufferedReader in=new BufferedReader(new FileReader(source) );//2.定义带缓冲区的字符输出流, 将源文件中的数据写入到目标文件中BufferedWriter out=new BufferedWriter(new FileWriter(target ) );//3.从源文件中读取(in)数据, 将读取到的数据写入(out)到目标文件中int data;while( (data=in.read()) != -1 ) {//将读取到的数据写入到目标文件out.write( data );}//4.释放资源(关闭流)in.close();out.close();}
}

上面的copyTextFile只能复制文本文件,== 如果复制图片、音频、视频等二进制文件,即使复制成功了,复制后的文件也是无法正常打开的!==这是因为图片、音频、视频等文件中都是二进制(1和0)组成的, 如果按照字符去读取这些二进制, 再按照字符写出到目标文件中, 就会破坏从源文件的中读取到内容, 从而导致这些复制后的目标文件是无法打开的!
下面是支持复制所有文件的方法:(既可以复制文本又可以图片、音频、视频等二进制文件)

public class CopyFileDemo {public static void main(String[] args) {//1.定义变量, 存储源文件路径String source = "d:/iotest/src/meinv.jpg";//2.定义变量, 存储目标文件路径String target = "d:/iotest/tar/meinv-副本.jpg";try {//3.调用copyBinaryFile方法复制任意文件copyBinaryFile( source, target );System.out.println( source+" 文件复制成功!" );} catch (Exception e) {System.out.println( source+" 文件复制失败!" );e.printStackTrace();}}/** 方法作用: 复制指定位置的文本文件到另一位置(可以复制任何文件)* source参数: 源文件路径(即,要复制的文件路径)* target参数: 目标文件路径(即,通过源文件复制的副本文件路径)*/public static void copyBinaryFile(String source, String target) throws Exception {//1.定义带缓冲区的字节输入流, 读取源文件中的数据BufferedInputStream in = new BufferedInputStream( new FileInputStream( source ) );//2.定义带缓冲区的字节输出流, 将源文件中的数据写入到目标文件中BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( target ) );//3.从源文件中读取(in)数据, 将读取到的数据写入(out)到目标文件中int data;while( (data=in.read()) != -1 ) {//将读取到的数据写入到目标文件out.write( data );}//4.释放资源(关闭流)in.close();out.close();}
}	

2.3.批量读写

上面的代码中, 在从源文件中读取数据时, 使用了带缓冲区的字节输入流(BufferedInputStream), 可以保证高效率的读取文件中的数据;在将读取到的数据输出到目标文件中时, 使用了带缓冲区的字节输出流(BufferedOutputStream), 保证了将读到的数据高效率的写出到目标文件中;
但有一个过程中没有使用缓冲区, 就是当把源文件中的数据读取到Java程序中后, 将要通过输出流将数据写出到目标文件中时, 这个过程是一个字节一个字节的去处理的, 没有使用字节数据, 如果此处也加上字节数组, 同样可以提高程序执行的效率!
将上面的代码进行改进如下

public class CopyFileDemo2 {public static void main(String[] args) {//1.定义变量, 存储源文件路径String source = "d:/iotest/src/xiaoquanquan.mp4";//2.定义变量, 存储目标文件路径String target = "d:/iotest/tar/xiaoquanquan-副本.mp4";try {//3.调用copyBinaryFile方法复制任意文件copyBinaryFile( source, target );System.out.println( source+" 文件复制成功!" );} catch (Exception e) {System.out.println( source+" 文件复制失败!" );e.printStackTrace();}}/** 方法作用: 复制指定位置的文本文件到另一位置(可以复制任何文件)* source参数: 源文件路径(即,要复制的文件路径)* target参数: 目标文件路径(即,通过源文件复制的副本文件路径)*/public static void copyBinaryFile(String source, String target) throws Exception {//1.定义带缓冲区的字节输入流, 读取源文件中的数据BufferedInputStream in = new BufferedInputStream( new FileInputStream( source ) );//2.定义带缓冲区的字节输出流, 将源文件中的数据写入到目标文件中BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( target ) );//3.从源文件中读取(in)数据, 将读取到的数据写入(out)到目标文件中//定义一个字节数据, 将读进来的数据存入byte数组中, 再将byte数组写入到目标文件中byte[] buf = new byte[8192];int data;while( (data=in.read( buf )) != -1 ) {//将byte数组中的数据写入到目标文件中out.write( buf );}//4.释放资源(关闭流)in.close();out.close();}/** 方法作用: 复制指定位置的文本文件到另一位置(只能复制文本文件)* source参数: 源文件路径(即,要复制的文件路径)* target参数: 目标文件路径(即,通过源文件复制的副本文件路径)*/public static void copyTextFile(String source, String target) throws Exception {//1.定义带缓冲区的字符输入流, 读取源文件中的数据BufferedReader in = new BufferedReader( new FileReader( source ) );//2.定义带缓冲区的字符输出流, 将源文件中的数据写入到目标文件中BufferedWriter out = new BufferedWriter( new FileWriter( target ) );//3.从源文件中读取(in)数据, 将读取到的数据写入(out)到目标文件中//定义一个字符数据, 将读进来的数据存入char数组中, 再将char数组写入到目标文件中char[] buf = new char[8192];int data;while( (data=in.read( buf )) != -1 ) {//将读取到的数据写入到目标文件out.write( buf );}//4.释放资源(关闭流)in.close();out.close();}
}

3.序列化 / 反序列化

3.1.1.1 概述

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。
– 简单地说: 将内存中的Java对象转换为字节序列(二进制)的过程就是序列化。该字节序列中包含了对象的数据(比如成员变量,成员方法等)以及对象的类型信息。
– 将内存中的Java对象转成二进制文件可以存储在磁盘上, 或者转成流数据, 这样可以通过网络进行Java对象数据的传输。而【反序列化】:
– 将包含对象信息的字节序列(二进制)再转换为内存中的Java对象的过程就是反序列化。
实现序列化:
– 利用ObjectOutputStream字节输出流,将内存中的Java对象,按照固定格式转成字节序列输出
实现反序列化:
– 利用ObjectInputStream字节输入流,读取序列化的字节序列,将这些字节序列重新转换为Java对象

3.2. 应用场景

思考问题1:
内存中的Java对象在服务器关闭后, 随着内存的释放, 内存中的数据也会得到释放。而在服务器重启后也很难恢复这些数据;
解决方法:
如果要重启服务器(比如:重新部署应用程序), 在关闭服务器之前, 可以将内存中的Java对象通过序列化转换为文件存储在磁盘上, 在部署完应用后, 启动服务器, 此时再通过反序列化将磁盘上的文件转换为服务器内存中的Java对象。这样既重启了服务器, 实现了应用的重新部署, 也避免了重启服务器时内存中数据的丢失问题!
思考问题2:
一台服务器内存中的数据只能被当前1号服务器读取, 如果别的服务器也希望拿到这个数据呢?(比如分布式系统中)
解决方法:
可以将1号服务器中的Java对象通过序列化转成二进制流数据, 再通过网络传输到2号服务器中, 二号服务器接收到这些二进制数据后, 再通过反序列化将二进制数据转成内存中的Java对象即可!

4.序列化和反序列化的特点

如果一个对象需要序列化,该对象所属的类必须实现Serializable接口才可以被序列化
如果要进行序列化的对象所属的类没有实现该接口, 在进行序列化时, 将会抛出NotSerializableException异常

Student stu = new Student( "张三", 22 );
class Student extends... implements Serializable{ ... }
  • 如果对象中的个别属性不希望被序列化(比如一些敏感信息, 银行卡号, 密码), 可以使用static修饰,
    由于static修饰的成员属于类, 不会随着对象被序列化输出。
  • 不需要序列化的属性也可以被修饰为transient, 被transient修饰的属性只会存在于内存中, 而不会被序列化持久保存。
  • 每个被序列化的文件都会有一个唯一id, 如果没有手动添加, 编译器会根据类的定义信息计算产生一个版本号; 在反序列化时, 如果和序列化的版本号不一致时, 将无法完成反序列化。
  • 序列化和反序列化常用于不同服务器之间的数据传输,将Java对象序列化字节序列进行传输,另一方在接收后再进行反序列化, 将字节序列转成Java对象

5.ObjectOutputStream

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储

ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。
void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream

测试ObjectOutputStream对Java对象进行序列化:

/*
* 测试使用ObjectOutputStream将Java对象序列化到磁盘的文件中
* 1) 定义学生类, 添加成员变量和成员方法(get,set),构造方法
* 2) 创建ObjectOutputStream流对象, 创建学生类的对象
* 3) 将学生对象转成字节序列(序列化)到磁盘文件中
*/
public class SerializableDemo {public static void main(String[] args) {try {// 1.创建ObjectOutputStream流对象, 用于序列化Java对象// 创建FileOutputStream流对象,将Java对象输出到指定的文件中FileOutputStream out = new FileOutputStream( "d:/iotest/ser/student.ser" );ObjectOutputStream objOut = new ObjectOutputStream( out );// 2.创建学生对象,将学生对象转成字节序列(序列化)到磁盘文件中Student stu = new Student( "张飞", 20 );objOut.writeObject( stu );// 3.关闭流(释放资源)objOut.close();System.out.println( "对象序列化成功!" );} catch (Exception e) {System.out.println( "对象序列化失败!" );e.printStackTrace();}}
}
/*
* 定义学生类
*/
class Student implements Serializable{//成员变量private String name;private int age;//构造方法public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}//get和set方法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;}
}

6.ObjectInputStream

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectInputStream,用于读取序列化后的字节序列,将这些字节序列重新转换为Java对象

ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。
Object readObject() 从 ObjectInputStream 读取对象,读取序列化数据

测试ObjectInputStream对Java对象进行反序列化

/*
* 测试使用ObjectInputStream将序列化后磁盘文件转成内存中的Java对象
* 1) 创建ObjectInputStream流对象
* 2) 将序列化后的磁盘文件转成Java对象
* 3) 测试Java对象
*/
public class SerializableDemo2 {public static void main(String[] args) {try {//1.创建ObjectInputStream流对象, 用于反序列化//创建FileInputStream流对象,用于反序列化(读取)指定文件中的内容FileInputStream in = new FileInputStream( "d:/iotest/ser/Student.ser" );ObjectInputStream objIn = new ObjectInputStream( in );// 2.将序列化后的磁盘文件转成Java对象Object obj = objIn.readObject();// 3.测试Java对象System.out.println( obj ); //cn.tedu.serializable.Student@b684286// 向下转型为Student类型Student stu = (Student)obj;System.out.println( stu.getName()+", "+stu.getAge() );} catch (Exception e) {e.printStackTrace();}}
}

7.编码转换流介绍

输入/输出流体系中还提供了两个转换流, 这两个转换流用于实现将字节流转成字符流, 其中:

InputStreamReader负责将字节输入流转成字符输入流(转换时可以指定编码)
OutputStreamWriter负责将字节输出流转成字符输出流(转换时可以指定编码)

思考: 为什么没有提供将字符流转成字节流?
如果现在有一个字节流:

  • 若读写的文件是图片、音频、视频等二进制数据,只能使用字节流进行读写,也就不能转换!
  • 若读写的文件确定是文本内容,那么把字节流转成字符流来进行读写会更方便一些!
    在读取文本时, 字节流是一个字节一个字节读或写, 而字符流是一个字符一个字符读或写, 显然字符流效率更高!所以Java只提供了字节流转字符流, 没有提供字符流转字节流

7.1.java中常见字符

7.1.1ASCII

ASCII(American Standard Code for Information Interchange,美国信息互换标准编码)是基于罗马字母表的一套电脑编码系统,ASCII主要用于显示现代英语和其他西欧语言,它是最基础,也是最通用的单字节编码系统。
基本的ASCII字符集共有128个字符,字符值从0到127,其中32到126是可打印字符,占 1 bytes(字节),适用于不同地区的扩充的ASCII字符集,扩充字符的编码均为高位为1的8位代码,即128-255,也称为扩展ASCII码

7.1.2.GB2312

简体中文字符集(又称为GB2312-80),兼容ASCII,占 2 bytes(字节),由于我们汉字比较复杂,又不能和ASCII编码冲突,所以,中国制定了GB2312编码,并且需要两个字节
GB2312所收录的汉字已经覆盖99.75%的使用频率,基本满足了汉字的计算机处理需要。在中国大陆和新加坡获广泛使用。GB2312收录简化汉字及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母,共 7445 个图形字符。其中包括6763个汉字

7.1.3.GBK

GB2312的扩展字符集,支持繁体字,兼容GB2312,占 2 bytes(字节),由于汉字太多,太复杂,GB2312无法处理所有的汉字,这就出现GBK字符集,它扩展了GB2312编码,加入了更多的汉字

7.1.4.Unicode

国际标准组织统一标准字符集,占 2 bytes,Unicode是一种在计算机上使用的字符编码。
Unicode是为了解决不同编码兼容性问题,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求

7.1.5.UTF-8

UTF-8是Unicode的其中一个使用方式。(UTF是Unicode Tranformation Format简写)
它的出现是为了提高Unicode编码的效率,根据不同符号自动选择编码的长短。
UTF-8使用可变长度字节来储存 Unicode字符 ,占 1-3 bytes,
例如:

  • ASCII字母(英文字母,数字,西欧语言)继续使用 1 字节储存,
  • 重音文字、希腊字母或西里尔字母等使用 2 字节来储存,
  • 而我们常用的汉字就要使用 3 字节来储存

7.2.工具类

OutputStreamWriter:是字节流通向字符流的桥梁
--OutputStreamWriter(OutputStream out, String charsetName)
--OutputStreamWriter(OutputStream out) 
InputStreamReader: 是字节流通向字符流的桥梁
--InputStreamReader(InputStream in)
--InputStreamReader(InputStream in,String charsetName)

7.3.InputStreamReader案例

InputStreamReader负责将字节输入流转成字符输入流(转换时可以指定编码)
InputStreamReader(InputStream in) -- 创建一个 InputStreamReader 字符输入流对象, 该对象负责将 字节输入流 转成字符输入流-- 在将字节流转成字符流时, 默认使用系统默认字符集(win中, GBK)
InputStreamReader(InputStream in, String charsetName)-- 创建一个 InputStreamReader 字符输入流对象, 该对象负责将 字节输入流 转成字符输入流-- 在将字节流转成字符流时, 将会使用charsetName指定的字符集

下面以获取键盘输入为例来介绍转换流的用法。
Java使用System.in代表标准输入(即键盘输入),但这个标准输入流是InputStream类的实例,使用不太方便,而且键盘输入内容都是文本内容。
所以可以使用InputStreamReader将其转换成字符输入流,普通的Reader读取输入内容时依然不太方便,可以将普通的Reader再次包装成BufferedReader,利用BufferedReader的readLine()方法可以一次读取一行内容。如下程序所示

public static void main(String[] args) {//1.将System.in字节输入流转成Reader字符流Reader reader = new InputStreamReader(System.in);// 再将普通的Reader字符流转成带缓冲区功能的BufferReader流BufferedReader br = new BufferedReader( reader );try {//2.读取用户通过键盘输入的一行文本//String line1 = br.readLine();//String line2 = br.readLine();//System.out.println( line1 );//System.out.println( line2 );	//3.使用循环来逐行读取用户通过键盘输入的每一行文本String line;while( (line=br.readLine()) != null ) {System.out.println( "输入的内容为: "+line );//如果读取的内容为exit, 则结束循环if( line.equals( "exit" ) ) {break;}}//4.关闭流br.close();	} catch (Exception e) {e.printStackTrace();}
}

之所以将System.in字节流包装成BufferedReader,因为BufferedReader流具有缓冲功能,它可以一次读取一行文本——以换行符为标志,如果它没有读到换行符,则程序阻塞,等到读到换行符为止。运行上面程序可以发现这个特征,在控制台执行输入时,只有按下回车键,程序才会打印出刚刚输入的内容

7.4.OutputStreamWriter案例

OutputStreamWriter负责将字节输出流转成字符输出流(转换时可以指定编码)
OutputStreamWriter(OutputStream out)-- 创建一个 OutputStreamWriter 字符输出流对象, 该对象负责将 字节输出流 转成字符输出流-- 在将字节流转成字符流时, 默认使用系统默认字符集(win中, GBK)
OutputStreamWriter(OutputStream out, String charsetName)  -- 创建一个 OutputStreamWriter 字符输出流对象, 该对象负责将 字节输出流 转成字符输出流-- 在将字节流转成字符流时, 将会使用charsetName指定的字符集

通过FileWriter字符输出流往文件中写数据时, 默认使用的是系统平台(GBK)
但如果要写入的文件中有数据,并且该文件使用的编码不是GBK, 而是utf-8, 那么此时将GBK编码的数据写入到utf-8的文件中, 就可能会出现乱码问题!
e.txt: 你好, utf-8
e.txt: 追加数据, 韩少云, FileWriter, GBK
下面测试FileWriter字符流写数据时可能出现的乱码问题!

public static void main(String[] args) {try {/* * 通过FileWriter字符输出流往文件中写数据时, 默认使用的是系统平台码(GBK)* 但如果e.txt文件中有数据,并且该文件使用的编码不是GBK,而是utf-8*那么此时将GBK编码数据写入到utf-8的文件中,就可能会出现乱码问题!*///1.创建FileWriter字符输出流对象,将数据写入到d:/demoout/e.txt文件中FileWriter writer=new FileWriter( "d:/demoout/e.txt", true );System.out.println( writer.getEncoding() );// 2.输出数据writer.write( "你好,马云\r\n" );// 3.关闭流writer.close();System.out.println( "写入成功!" );} catch (Exception e) {e.printStackTrace();}
}

将FileWriter字符流替换为FileOutputStream字节流, 再通过OutputStreamWriter将字节流转成字符流, 还可以指定编码, 修改后的代码如下

public static void main(String[] args) {try {// 1.创建FileOutputStream字节输出流对象, 将数据写入到 d:/demoout/e.txt 文件中FileOutputStream out = new FileOutputStream( "d:/demoout/e.txt", true );// 2.通过OutputStreamWriter将字节流转成字符流, 并可以指定编码OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");//System.out.println( writer.getEncoding() );// 3.输出数据writer.write( "你好,马云!\r\n" );// 4.关闭流writer.close();System.out.println( "写入成功!" );} catch (Exception e) {e.printStackTrace();}
}

更多推荐

字符输出流与序列化

本文发布于:2024-03-08 20:33:50,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1722240.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:字符   序列化

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!