黑马程序员:IO 学习<二>

来源:互联网 发布:idea设置网络 编辑:程序博客网 时间:2024/05/21 22:27

------- 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培训期待与您交流! ---------- 

原创粉丝点击