Java IO(三)
-----------------------------
回退流
给用户第二次读的机会。在JAVA IO中所有的数据都是采用顺序的读取方式,即,对于一个输入流来讲都是采用从头到尾顺序读取,如果在输入流中某个不需要的内容被读取进来,则只能通过程序将这些不需要的内容处理掉,为了解决这样的读取问题,在JAVA中提供了一种回退输入流(PushbackInputStream、PushbackReader),可以把读取进来的某些数据重新退回到输入流的缓冲区之中。
对于回退操作来说,提供了三个unread()的操作方法,这三个操作方法与InputStream类中的read()方法是一一对应的。
实例:把内容设置到内存中
importjava.io.ByteArrayInputStream ;
importjava.io.PushbackInputStream ;
publicclass PushInputStreamDemo{
public static void main(String args[])throws Exception { // 所有异常抛出
String str = "www.hmjava.cn"; // 定义字符串
PushbackInputStreampush = null ; // 定义回退流对象
ByteArrayInputStream bai = null ; // 定义内存输入流
bai = newByteArrayInputStream(str.getBytes()) ; //实例化内存输入流
push = newPushbackInputStream(bai) ; // 从内存中读取数据
System.out.print("读取之后的数据为:") ;
int temp = 0 ;
while((temp=push.read())!=-1){ // 读取内容
if(temp=='.'){ // 判断是否读取到了“.”
push.unread(temp) ; // 放回到缓冲区之中
temp = push.read() ; // 再读一遍
System.out.print("(退回"+(char)temp+")") ;
}else{
System.out.print((char)temp); // 输出内容
}
}
}
};
字符编码
任何的文字都是以指定的编码方式存在的,在JAVA程序的开发中最常见的是以下几种编码:ISO8859-1、GBK/GB2312、unicode、UTF编码。
ISO8859-1编码属于单字节编码,最多只能表示0~255的字符范围,主要在英文上应用。
GBK/GB2312:中文的国际编码,专门用来表示汉字,是双字节编码。
unicode:JAVA中就是使用此编码方式,也是最标准的一种编码,是使用16进制表示的编码。但此编码不兼容ISO8859-1编码。
UTF:由于unicode不支持ISO8859-1编码,因此产生了UTF编码,UTF编码兼容了ISO8859-1编码,同时也可以用来表示所有的语言字符,一般在中文网页中使用此编码。
乱码的产生
如果本机的默认编码是GBK,但是在程序中使用了ISO8859-1编码,则就会出现字符乱码问题。
利用System类来得到当前系统的有关信息,也可以直接使用此类来找到系统的默认编码。
public sstatic Properties getProperty()
实例:
publicclass CharSetDemo01{
public static void main(String args[]){
System.out.println("系统默认编码:" +
System.getProperty("file.encoding")); // 获取当前系统编码
}
};
乱码问题实例:
importjava.io.OutputStream ;
importjava.io.FileOutputStream ;
importjava.io.File ;
publicclass CharSetDemo02{
public static void main(String args[])throws Exception {
File f = new File("D:" +File.separator + "test.txt") ; //实例化File类
OutputStream out = newFileOutputStream(f) ; // 实例化输出流
byte b[] = "中国,你好!".getBytes("ISO8859-1") ; // 转码操作
out.write(b) ; // 保存
out.close() ; // 关闭
}
};
对象序列化
掌握对象序列化的作用
掌握Serializable接口的作用
可以使用ObjectOutputStream进行对象序列化操作
可以使用ObjectInputSTream进行对象反序列化操作
掌握Externalizable接口的作用及与Serializable接口的实现区别
掌握transient关键字的作用
序列化一组对象
对象序列化:一个对象产生之后实际上是在内存中为其开辟了一个存储空间,方便存储信息。
对象序列化与反序列化:
想要完成对象的输入输出,还必须依靠对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)
使用对象输出流输出序死化对象的步骤,有时也称为列化,而使用对象输入流读入对象的过程,有时也称为反序列化。
序列化操作(ObjectOutputStream)实例:
importjava.io.File ;
importjava.io.FileOutputStream ;
importjava.io.OutputStream ;
importjava.io.ObjectOutputStream ;
publicclass SerDemo01{
public static void main(String args[])throws Exception {
File f = new File("D:" +File.separator + "test.txt") ; //定义保存路径
ObjectOutputStream oos = null ; // 声明对象输出流
OutputStream out = newFileOutputStream(f) ; // 文件输出流
oos = new ObjectOutputStream(out);
oos.writeObject(new Person("张三",30)) ; //保存对象
oos.close() ; // 关闭
}
};
所有的对象拥都拥有各自的属性,但是所有的方法都是公共的,所以序列化对象的时候实际上序列化的就是属性。
反序列化操作(ObjectInputStream)实例:
importjava.io.File ;
importjava.io.FileInputStream ;
importjava.io.InputStream ;
importjava.io.ObjectInputStream ;
publicclass SerDemo02{
public static void main(String args[])throws Exception {
File f = new File("D:" +File.separator + "test.txt") ; //定义保存路径
ObjectInputStream ois = null ; // 声明对象输入流
InputStreaminput = new FileInputStream(f) ; // 文件输入流
ois = new ObjectInputStream(input); // 实例化对象输入流
Object obj = ois.readObject() ; // 读取对象
ois.close() ; // 关闭
System.out.println(obj) ;
}
};
Externalizable接口
使用Serilizable接口可以方便的序列化一个对象,但是在序列化操作中也提供了另外一种序列化机制——Externalizable接口。
利用此接口修改前面的程序:
importjava.io.File ;
importjava.io.IOException ;
importjava.io.FileOutputStream ;
importjava.io.OutputStream ;
importjava.io.ObjectOutputStream ;
importjava.io.FileInputStream ;
importjava.io.InputStream ;
importjava.io.ObjectInputStream ;
publicclass SerDemo04{
public static void main(String args[])throws Exception{
ser() ;
dser() ;
}
public static void ser() throws Exception{
File f = new File("D:" +File.separator + "test.txt") ; //定义保存路径
ObjectOutputStream oos = null ; // 声明对象输出流
OutputStream out = newFileOutputStream(f) ; // 文件输出流
oos = new ObjectOutputStream(out);
oos.writeObject(new Person("张三",30)) ; //保存对象
oos.close() ; // 关闭
}
public static void dser() throws Exception{
File f = new File("D:" +File.separator + "test.txt") ; //定义保存路径
ObjectInputStream ois = null ; // 声明对象输入流
InputStream input = newFileInputStream(f) ; // 文件输入流
ois = new ObjectInputStream(input); // 实例化对象输入流
Object obj = ois.readObject() ; // 读取对象
ois.close() ; // 关闭
System.out.println(obj) ;
}
};
在开发中使用Serializable接口是最多的,而Externalizable接口基本上是不会出现的。
transient关键字
当使用Serializalbe接口实现序列化操作时,如果一个对象的某个属性不希望被序列化,则可以使用transient关键字进行声明。
序列化一组对象
如果要保存一组对象,则最好使用对象数组的形式完成。
importjava.io.File ;
importjava.io.IOException ;
importjava.io.FileOutputStream ;
importjava.io.OutputStream ;
importjava.io.ObjectOutputStream ;
importjava.io.FileInputStream ;
importjava.io.InputStream ;
importjava.io.ObjectInputStream ;
publicclass SerDemo05{
public static void main(String args[])throws Exception{
Person per[] = {new Person("张三",30),new Person("李四",31),
new Person("王五",32)} ;
ser(per) ;
Object o[] = (Object[])dser() ;
for(int i=0;i<o.length;i++){
Person p = (Person)o[i] ;
System.out.println(p) ;
}
}
public static void ser(Object obj[])throws Exception {
File f = new File("D:" +File.separator + "test.txt") ; //定义保存路径
ObjectOutputStream oos = null ; // 声明对象输出流
OutputStream out = newFileOutputStream(f) ; // 文件输出流
oos = new ObjectOutputStream(out);
oos.writeObject(obj) ; // 保存对象
oos.close() ; // 关闭
}
public static Object[] dser() throwsException {
File f = new File("D:" +File.separator + "test.txt") ; //定义保存路径
ObjectInputStream ois = null ; // 声明对象输入流
InputStream input = newFileInputStream(f) ; // 文件输入流
ois = new ObjectInputStream(input); // 实例化对象输入流
Object obj[] =(Object[])ois.readObject() ; // 读取对象
ois.close() ; // 关闭
return obj ;
}
};
---------------------------------------------------------------------------------------------
实例操作:单人信息管理程序
实例要求:
将之前的菜单程序进行扩充,要求:增加的时候可以增加一个人的完整信息,人的信息包括年龄和姓名。保存之后也可以修改此信息,删除此信息,查询此信息。
提示:使用对象序列化保存
此时程序可以使用之前讲解过的几个类:InputData、Person、Operate、Menu。
文件操作类实现:
importjava.io.File ;
importjava.io.FileInputStream ;
importjava.io.FileOutputStream ;
importjava.io.ObjectInputStream ;
importjava.io.ObjectOutputStream ;
publicclass FileOperate{ // 此类专门用于保存和读取
private File file = null ; // 定义文件对象
public FileOperate(String pathName){ // 通过 构造传递文件路径
this.file = new File(pathName) ;
}
public boolean save(Object obj) throwsException{ // 保存对象
ObjectOutputStream oos = null ; // 对象输出流
boolean flag = false ; // 定义操作标志位
try{
oos = newObjectOutputStream(new FileOutputStream(this.file)) ; // 实例化对象输出流
oos.writeObject(obj) ; // 写入对象
flag = true ;
}catch(Exception e){
throw e ; // 有异常交给被调用处处理
}finally{
if(oos!=null){
oos.close() ;
}
}
return flag ;
}
public Object load() throws Exception{ // 读取对象
Object obj = null ; // 接收读取的内容
ObjectInputStream ois = null ;
try{
ois = new ObjectInputStream(newFileInputStream(this.file)) ; // 实例化对象输入流
obj = ois.readObject() ; // 读取对象
}catch(Exception e){
throw e ;
}finally{
if(ois!=null){
ois.close() ; // 关闭
}
}
return obj ;
}
};
Person类:
importjava.io.Serializable ;
publicclass Person implements Serializable{
private String name ; // 定义name属性
private int age ; // 定义age属性
public Person(String name,int age){
this.name = name;
this.age = age ;
}
public String toString(){
return "姓名:" + this.name + ";年龄:" + this.age ;
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
};
修改操作类:
publicclass Operate{
public static void add(){ // 增加操作
InputData input = new InputData(); // 实例化输入数据对象
FileOperate fo = newFileOperate("d:\\test.per") ;
String name =input.getString("请输入姓名:") ;
int age = input.getInt("请输入年龄:" , "年龄必须是数字!") ;
Person per = new Person(name,age); // 实例化Person对象
try{
fo.save(per) ; // 保存对象
}catch(Exception e){
e.printStackTrace() ;
}
System.out.println("信息增加成功!") ;
}
public static void delete(){ // 删除操作
FileOperate fo = newFileOperate("d:\\test.per") ;
try{
fo.save(null) ; // 保存对象
}catch(Exception e){
e.printStackTrace() ;
}
System.out.println("信息删除成功!") ;
}
public static void update(){ // 更新操作
InputData input = new InputData(); // 实例化输入数据对象
FileOperate fo = newFileOperate("d:\\test.per") ;
Person per = null ;
try{
per = (Person)fo.load() ; // 读取对象
}catch(Exception e){
e.printStackTrace() ;
}
String name =input.getString("请输入姓名(原姓名:"+per.getName()+"):") ;
int age = input.getInt("请输入年龄(原年龄:"+per.getAge()+"):" , "年龄必须是数字!") ;
per = new Person(name,age) ; // 实例化Person对象
try{
fo.save(per) ; // 保存对象
}catch(Exception e){
e.printStackTrace() ;
}
System.out.println("信息修改成功!") ;
}
public static void find(){ // 查看操作
FileOperate fo = newFileOperate("d:\\test.per") ;
Person per = null ;
try{
per = (Person)fo.load() ; // 读取对象
}catch(Exception e){
e.printStackTrace() ;
}
System.out.println(per) ;
}
};
菜单类:
publicclass Menu{
public Menu(){
while(true){
this.show() ; // 无限制调用菜单的显示
}
}
public void show(){
System.out.println("===== Xxx系统 =====") ;
System.out.println(" [1]、增加数据");
System.out.println(" [2]、删除数据");
System.out.println(" [3]、修改数据");
System.out.println(" [4]、查看数据");
System.out.println(" [0]、系统退出\n");
InputData input = new InputData();
int i = input.getInt("请选择:","请输入正确的选项!") ;
switch(i){
case 1:{
Operate.add() ; // 调用增加操作
break ;
}
case 2:{
Operate.delete() ; // 调用删除操作
break ;
}
case 3:{
Operate.update() ; // 调用更新操作
break ;
}
case 4:{
Operate.find() ; // 调用查看操作
break ;
}
case 0:{
System.exit(1) ; // 系统退出
break ;
}
default:{
System.out.println("请选择正确的操作!") ;
}
}
}
};
主类(测试类):
importjava.io.* ;
publicclass ExecDemo03{
public static void main(String args[])throws Exception{
new Menu() ;
}
};
--------------------------------------------------------
实例操作:投票程序
实例要求:
有一个班采用民主投票的方法推选班长,班长候选人共4位,每个人姓名及代号分别为1、张三 2、李四3、王五 4、赵六。程序操作员将每张选票上所填的代号(1、2、3、4)循环输入电脑,输入数字0结束输入,然后将所有候选人的得票情况显示出来,并显示最终当选者信息。
提示:利用Comparable比较器、Arras类、对象数组实现
学生类实现:
publicclass Student implements Comparable<Student>{
private int stuNo ; // 学生编号
private String name ; // 学生姓名
private int vote ; // 学生票数
public Student(int stuNo,String name,intvote){
this.setStuNo(stuNo) ;
this.setName(name) ;
this.setVote(vote) ;
}
public int compareTo(Student o){
if(this.vote<o.vote){
return 1 ;
}else if(this.vote>o.vote){
return -1 ;
}else{
return 0 ;
}
}
public void setStuNo(int stuNo){
this.stuNo = stuNo ;
}
public void setName(String name){
this.name = name ;
}
public void setVote(int vote){
this.vote = vote ;
}
public int getStuNo(){
return this.stuNo ;
}
public String getName(){
return this.name ;
}
public int getVote(){
return this.vote ;
}
};
InputData类实现;
importjava.io.BufferedReader ;
importjava.io.InputStreamReader ;
importjava.io.IOException ;
publicclass InputData{
private BufferedReader buf = null ; // 接收数据
public InputData(){
this.buf = new BufferedReader(newInputStreamReader(System.in)) ;
}
public String getString(String info){ // 得到字符串
String temp = null ; //接收输入内容
System.out.print(info) ;
try{
temp = this.buf.readLine(); // 接收数据
}catch(IOException e){
e.printStackTrace() ;
}
return temp ;
}
public int getInt(String info,Stringerr){ // 得到整型数据
int temp = 0 ;
String str = null ;
boolean flag = true ; // 定义一个循环标记
while(flag){
str = this.getString(info);
if(str.matches("\\d+")){
temp =Integer.parseInt(str) ;
flag = false ; // 更改标志位,将退出循环
}else{
System.out.println(err);
}
}
return temp ;
}
};
操作类实现:
publicclass Operate{
private Student stu[] = {newStudent(1,"张三",0),new Student(2,"李四",0),
new Student(3,"王五",0),new Student(4,"赵六",0)} ;// 侯选人信息
private boolean flag = true ;
public Operate(){
this.printInfo() ; // 先输出候选人信息
while(flag){
this.vote() ; // 循环调用投票
}
this.printInfo() ; // 输出投票之后的侯选人信息
this.getResult() ; // 得到结果
}
private void getResult(){ // 得到最终的投票结果
java.util.Arrays.sort(this.stu) ; // 排序
System.out.println("投票最终结果:" + this.stu[0].getName()+"同学,最后以"+this.stu[0].getVote()+"票当选班长!") ;
}
public void vote(){ // 此方法完成投票功能
InputData input = new InputData(); // 输入数据
int num = input.getInt("请输入班长侯选人代号(数字0结束):","此选票无效,请输入正确的侯选人代号!") ;
switch(num){
case 0:{
this.flag = false ; // 中断循环
break ;
}
case 1:{
this.stu[0].setVote(this.stu[0].getVote()+ 1) ;
break ;
}
case 2:{
this.stu[1].setVote(this.stu[1].getVote()+ 1) ;
break ;
}
case 3:{
this.stu[2].setVote(this.stu[2].getVote()+ 1) ;
break ;
}
case 4:{
this.stu[3].setVote(this.stu[3].getVote()+ 1) ;
break ;
}
default:{
System.out.println("此选票无效,请输入正确的候选人代号!") ;
}
}
}
public void printInfo(){
for(int i=0;i<stu.length;i++){
System.out.println(this.stu[i].getStuNo()+ ":"
+this.stu[i].getName() + "【"+this.stu[i].getVote()+"】") ;
}
}
};
主类:
publicclass ExecDemo{
public static void main(String args[]){
new Operate() ;
}
};