------- android培训、java培训、期待与您交流! ----------
(1)--------------------------------对象流,序列化流(理解)
ObjectOutputStream:
void writeObject(Object obj)
ObjectInputStream:
Object readObject()
注意:
A:如果一个类的对象要想被对象流操作,就必须实现序列化接口。
B:这个接口只是起到标识的作用,没有方法需要实现。
C:如果类的简单改动不像影响程序的运行,我们就自己给定序列化id号。
D:序列化:把对象按照流一样的方式在网络中传输和写入文本文件。
反序列化:把文本文件的数据或者网络中传递的流对象数据解析成一个对象。
前面呢,我们已经可以往文件里面写入文本,简单数据。
* 现在呢,我要把一个对象写入到文本文件。该怎么做呢?
* 我们应该定义一个自定类。
* 通过查看API,我们看到了对象的读写:
* ObjectOutputStream:
* void writeObject(Object obj)
* ObjectInputStream:
* Object readObject()
*
* 对象流,序列化流。
*/
public class ObjectStreamDemo {
public static void main(String[] args) throws Exception {
// write();
read();
}
private static void read() throws Exception {
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"oos.txt"));
// 读取数据
Object obj = ois.readObject();
// 释放资源
ois.close();
Person p2 = (Person) obj;
System.out.println(p2.getName() + "***" + p2.getAge());
}
private static void write() throws Exception {
// 我要把Person写到文件
// 创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
"oos.txt"));
// 写数据
Person p = new Person("林青霞", 25);
oos.writeObject(p);
// 释放资源
oos.close();
}
}
NotSerializableException:
当对象要被序列化流对象操作的时候,必须实现一个接口。
* 通过查看Serializable我们知道类可以通过实现 java.io.Serializable 接口以启用其序列化功能。
* Exception in thread "main" java.io.InvalidClassException:
* cn.itcast_01.Person; local class incompatible: stream classdesc serialVersionUID = 2586984019240964030,
* local class serialVersionUID = -241056507998041204
*
* Serializable是对类打了标记,这个时候,
在生成的class文件中会有一个标记号自动生成。serialVersionUID = 2586984019240964030
* 那么,这样的话,我们把这个对象写入到文件中的时候,
也会把这个标记号写到文件中。serialVersionUID = 2586984019240964030
* 但是,我们刚才的动作,是把写给关闭了,
那么,这个时候,文件中的标记号应该还是:serialVersionUID = 2586984019240964030
* 这个时候,我们又重写在Person类里面修改了一个成员变量的修饰符,一旦修改,这个标记号就会改动。也就是现在的:serialVersionUID = -241056507998041204* 我们再次读取数据的时候,class中的标记号和文件中的标记号不一致了,就导致了现在的问题。
* class文件和对象写入的文件应该保证一致。
* 我们现在应该去想一个办法,在类中把标记号给固定死,那么,生成的class中的标记号也就是固定的了。
* 问题来了,这个标记号该怎么定义才能让jvm识别。
* 这个就是用来被jvm识别的:private static final long serialVersionUID = -241056507998041204L;
*
*/
public class Person implements Serializable {
*
* 按照序列化的方式写多个对象到文件。
*
* Exception in thread "main" java.io.EOFException:当输入过程中意外到达文件或流的末尾时,抛出此异常。
* 流以-1作为结束条件,而你现在要得到的是一个对象,所以不成功。
*
* 存储多个对象的时候,建议把多个对象添加到一个集合中,把结合对象作为一个对象写入。
* 读取的时候,就读取一次即可。
*
* 总结代码。分类整理。
*/
public class ObjectStreamTest {
public static void main(String[] args) throws Exception {
write();
read();
}
private static void read() throws Exception {
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"oos.txt"));
// 读取数据
// Object obj = ois.readObject();
// Object obj2 = ois.readObject();
// Object obj3 = ois.readObject();
// try {
// Object obj = null;
// while ((obj = ois.readObject()) != null) {
// Person p = (Person) obj;
// System.out.println(p.getName() + "***" + p.getAge());
// }
// } catch (EOFException e) {
// // 但是这样解决不好,这还不如不解决
// // 处理的时候,一定要给出提示,不要认为的把异常给隐藏掉
// }
Object obj = ois.readObject();
ArrayList<Person> array = (ArrayList<Person>) obj;
for (Person p : array) {
System.out.println(p.getName() + "***" + p.getAge());
}
// 释放资源
ois.close();
// Person p = (Person) obj;
// System.out.println(p.getName() + "***" + p.getAge());
// Person p2 = (Person) obj2;
// System.out.println(p2.getName() + "***" + p2.getAge());
// Person p3 = (Person) obj3;
// System.out.println(p3.getName() + "***" + p3.getAge());
}
private static void write() throws Exception {
// 我要把Person写到文件
// 创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
"oos.txt"));
// 写数据
Person p = new Person("林青霞", 25);
// oos.writeObject(p);
Person p2 = new Person("林志玲", 22);
// oos.writeObject(p2);
Person p3 = new Person("刘德华", 40);
// oos.writeObject(p3);
ArrayList<Person> array = new ArrayList<Person>();
array.add(p);
array.add(p2);
array.add(p3);
oos.writeObject(array);
// 释放资源
oos.close();
}
}
打印流:
* PrintWriter://字符打印流
* PrintStream://字节打印流
*
* 为什么要学习Print呢?
* 特点:
* 1:可以把任意类型的数据写入文件
* 2:它是可以直接操作设备(文件)的流对象流对象很多,那么,哪些流对象时可以直接操作文件的呢?
* 观察构造方法,如果可以传递File file参数和String fileName参数同时存在,
说明该流对象就是可以操作文件的对象。
* 3:能够自动刷新。前提是:要启动自动刷新,使用println、printf 或 format的时候才可以。
* 不但能够刷新,还能够自动换行。
*/
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
// write1();
// write2();'
write3();
}
// 使用println方法自动刷新
private static void write3() throws IOException {
// 创建打印流对象,启用自动刷新
PrintWriter pw = new PrintWriter(new FileWriter("pw.txt"),true);
// 写入数据
pw.println("haha");
pw.println("hehe");
pw.println("xixi");
pw.println("heihei");
pw.println("gaga");
//释放资源
pw.close();
}
// 使用print方法写入不同数据类型的数据
private static void write2() throws IOException {
// 创建对象
PrintWriter pw = new PrintWriter("b.txt");
// 写入数据
pw.print(true);
pw.print(123);
pw.print("hell");
pw.flush();
pw.close();
}
// PrintWriter作为基本的Writer体系的使用
private static void write1() throws IOException {
// 创建打印流对象
PrintWriter pw = new PrintWriter("a.txt");
// 下面这个不可以
// BufferedWriter bw = new BufferedWriter("a.txt");
// 调用pw的write方法
pw.write("hello");
pw.flush();
// 释放资源
pw.close();
}
}
Properties:是Hashtaable的子类,具有Map集合的特点。它还可以和io进行结合使用。它的键和值都是字符串。
Properties作为Map体系使用。
把Properties集合中的数据写入到文本文件中。
思路:
1:得到有数据的集合对象。
2:遍历集合,获取键和值
3:把键和值存入文件
那么, 什么又是我们说的结合呢?
也就是说,我们不需要看到基本的读写操作。
特殊方法:
1:根据键获取值
* String getProperty(String key):根据键获取值
* String getProperty(String key, String defaultValue):当键对应的值存在,就返回值,否则,就返回给定的默认值。
* Object setProperty(String key, String value):当键存在的时候,就是修改动作,当键不存在的时候,就是添加动作。
*
* 2:load:把键值对的文本数据加载到集合中
* load(InputStream is)
* load(Reader r)
2:list 把集合中的数据写入文本文件
list(PrintStream out)
list(PrintWriter out)
3:load:把键值对的文本数据加载到集合中
* load(InputStream is)
* load(Reader r)
4: store:保存数据(重新保存到Properties里面的文件里面)
store(OutputStream os,String str)
store(Writer w,String str)
JDK的bin目录下有一个工具:
1、native2ascii a.txt b.txt
2、native2ascii b.txt -reverse c.txt
例:------
public class PropertiesDemo {
public static void main(String[] args) {
// 创建集合对象
Properties prop = new Properties();
System.out.println("prop:" + prop);
prop.put("hello", "haha");
prop.put("world", "hehe");
System.out.println("prop:" + prop);
// 遍历方式
Set<Object> set = prop.keySet();
Iterator<Object> it = set.iterator();
while (it.hasNext()) {
Object key = it.next();
Object value = prop.get(key);
System.out.println(key + "***" + value);
}
}
}
例:
*
* 请问应用在哪里?
* 玩过游戏吗?加载游戏进度。
*/
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
// 创建集合对象
Properties prop = new Properties();
System.out.println("prop:" + prop);
// load(Reader r)
FileReader fr = new FileReader("prop.txt");
prop.load(fr);
fr.close();
System.out.println("prop:" + prop);
}
}
/*
* 游戏进度的保存。
*/
public class PropertiesDemo4 {
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
// 把文本文件中的键值对数据加载到集合中
FileReader fr = new FileReader("prop.txt");
prop.load(fr);
fr.close();
// System.out.println("prop:" + prop);
prop.setProperty("lisi", "50");
// System.out.println("prop:" + prop);
// 保存数据
// store(Writer w,String str);
FileWriter fw = new FileWriter("prop.txt");
prop.store(fw, "name and age"); // 第二个参数其实就是解释说明数据的意义
fw.close();
}
}
JDK的bin目录下有一个工具:
native2ascii a.txt b.txt
native2ascii b.txt -reverse c.txt
查找文件prop.txt中,看有没有键为lisi的值,如果有,则把其值修改为35
*
* 思路:
1:把prop.txt中的键值对数据加载到Properties集合中。load
2:遍历这个集合,获取到每一个键,进行判断。
如果有键为lisi的,则把其值修改为35
3:最后,把改变后的集合数据保存到prop.txt文件中。store
*/
public class PropertiesTest {
public static void main(String[] args) throws IOException {
// 把prop.txt中的键值对数据加载到Properties集合中。
Properties prop = new Properties();
FileReader fr = new FileReader("prop.txt");
prop.load(fr);
fr.close();
// System.out.println("prop:" + prop);
// 遍历这个集合,获取到每一个键,进行判断。
Set<Object> set = prop.keySet();
for (Object key : set) {
if ("lisi".equals(key)) {
prop.setProperty(String.valueOf(key), String.valueOf(35));
break;
}
}
// 最后,把改变后的集合数据保存到prop.txt文件中
FileWriter fw = new FileWriter("prop.txt");
prop.store(fw, "这是数据表示姓名和年龄");
fw.close();
}
}
编码表:就是由数字及其表示的字符组成的一张数据表:
ASCII
ISO-8859-1码表
GBK
GBK2312
BIG5
UTF-8
UTF-16
为了实现国际化,国际化标准组织,就做了统一规定,用统一的编码表。
unicode编码。
字符串编码问题:
*
* 编码:
* 把能够看懂的变成看不懂的。
* String -- getBytes()
* 解码:
* 把看不懂的变成能够看懂的。
* byte[] -- String
*/
----------------------------------------------------------
public class StringEncode {
public static void main(String[] args) throws UnsupportedEncodingException {
// 创建一个字符串
String str = "你好";
// 编码
// byte[] bys = str.getBytes();
// -60, -29, -70, -61
// byte[] bys = str.getBytes("GBK");
// -28, -67, -96, -27, -91, -67
byte[] bys = str.getBytes("UTF-8");
System.out.println("bys:" + Arrays.toString(bys));
// 解码
// String s = new String(bys);
// 浣犲ソ
String s = new String(bys, "GBK");
// ???
// String s = new String(bys, "UTF-8");
System.out.println("s:" + s);
}
}
------------------------------------------
* 在IO流操作中的编码问题:
* 如果你想在io流操作中指定编码,得使用转换流。
* 只有转换流才可以指定编码。
* 字符流 = 字节流 + 编码表
*/
public class EncodeDemo {
public static void main(String[] args) throws IOException {
// 这里使用了默认编码表GBK
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
// "osw.txt"));
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
// "osw.txt"), "GBK");
// FileWriter osw = new FileWriter("osw.txt");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
"osw.txt"), "UTF-8");
osw.write("中国");
osw.close();
// InputStreamReader isr = new InputStreamReader(new FileInputStream(
// "osw.txt"), "UTF-8");
InputStreamReader isr = new InputStreamReader(new FileInputStream(
"osw.txt"), "GBK");
char[] chs = new char[1024];
int len = isr.read(chs);
System.out.println(String.copyValueOf(chs, 0, len));
isr.close();
}
}
如果保证数据不出现乱码的现象。就把编码改成相同的样式
如何使用面向对象的思想思考问题
1、分析该系统有哪些类
2、每个类有哪些成员
3、类的相互调用关系
------- android培训、java培训、期待与您交流! ----------