对象的存储和读取
对象的存储和读取使用ObjectOutputStream和ObjectInputStream,这两个读写流是成对出现的。
/*
对象的存储和读取
对象存储时使用ObjectOutputStream,当读取时,只能使用ObjectInputStream读取。
*/
import java.io.*;
class ObjectStreamDemo
{
public static void main(String[] args)
{
try{
//写对象。
writeObj();
//读对象。
readObj();
}
catch(Exception e){
throw new RuntimeException("读写失败。");
}
}
public static void readObj()throws Exception{
//读取Object对象。
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.txt"));
//依次读取两个。
Person p1=(Person)ois.readObject();
Person p2=(Person)ois.readObject();
System.out.println(p1);
System.out.println(p2);
//资源使用完毕后关闭
ois.close();
}
public static void writeObj()throws Exception{
//存储Object对象。
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("obj.txt"));
//依次存储两个。
oos.writeObject(new Person("cs00",100));
oos.writeObject(new Person("cs01",222));
//资源使用完毕后关闭
oos.close();
}
}
输入和输出管道
主要用到两个流:PipedInputStream和PipedOutputStream
思路:
1.建立读和写两个(单线程易死锁)线程(继承Runnable,重写run方法)
2.读线程从输入管道中读取字符串数据(字符串转化为字节)
3.写线程向输出管道写入字节数据(字节转化为字符串)
4.建立输入和输出管道之间的联系。
5.启动输入和输出管道线程。
import java.io.*;
import java.util.*;
class PipedStreamDemo
{
public static void main(String[] args) throws Exception
{
//建立输入和输出管道。
PipedInputStream pipedIn=new PipedInputStream();
PipedOutputStream pipedOut=new PipedOutputStream();
//搭建输入和输出管道的桥梁。
pipedIn.connect(pipedOut);
//启动输入和输出管道线程。
new Thread(new Write(pipedOut)).start();
new Thread(new Read(pipedIn)).start();
}
}
class Read implements Runnable
{
//对象一旦建立即初始化输入管道。
private PipedInputStream in;
Read(PipedInputStream in){
this.in=in;
}
//重写run方法。
public void run(){
try{
//建立读取缓冲,存读取的数据。
byte[] buf=new byte[1024];
//从输入管道读取字节数据,并返回读取长度。
int len=in.read(buf);
//将读取到的字节数据转化为字符串并输出。
String s=new String(buf,0,len);
System.out.println(s);
in.close();
}
catch(Exception e){
throw new RuntimeException("管道读取失败");
}
}
}
class Write implements Runnable
{
//Write一旦建立即初始化输出管道。
private PipedOutputStream out;
Write(PipedOutputStream out){
this.out=out;
}
public void run(){
try{
//将要写的数据转化为字节。
out.write("管道开始写数据".getBytes());
//关闭管道流。
out.close();
}
catch(Exception e){
throw new RuntimeException("管道写数据失败。");
}
}
}
RandomAccessFile
此类的实例支持对随机访问文件的读取和写入。可分段实现读写操作,如多线程下载。通过构造函数可以看出,该类只能操作文件,并且有模式,如r,rw等,倘若对象的构造函数操作的文件不存在,会自动创建,如果存在则不会覆盖。
流的操作规律
源设备:
键盘:System.in 硬盘:FileStream 内存:ArrayStream
目的设备:
键盘:System.out 硬盘:FileStream 内存:ArrayStream
字符编码
字符流的出现方便了字符操作,更重要的是加入了编码转换,字符和字节的转换通过子类转换流来完成:InputStreamReader和OutputStreamWriter,在两个对象进行构造的时候可以加入字符集
编码解码
编码:字符串转为字节数组 String.getBytes()
解码:字节数组转为字符串 new String(Byte[])
UTF-8根据编码头的数值,确定依次读取几个字节。
“联通”编码时采用gbk码,但打开时由于“联通”的码符合UTF-8格式,所以会按照UTF-8解码。解决方法:在“联通”字前加任意中文即可。
打印学生信息(解码,排序,集合,文本,存储)
思路:
1.创建学生类对象,该对象具有比较性,需重写hashCode(),equals(),compareTo()方法。
2.创建集合容器,依次逐行读取从键盘输入的学生信息
3.将读取到的学生信息存储到集合容器
4.对结合容器按照学生成绩总和从大到小排序
5.将排序好的数据输出到文本文件
/*
五个学生对象,每个学生有三门课成绩
从键盘输入以上数据(姓名,成绩1,成绩2,成绩3)
将学生和计算的总分数按照分数大小排列保存到文本文件。
*/
import java.io.*;
import java.util.*;
class StudentInfoDemo
{
public static void main(String[] args) throws Exception
{
//反转比较器排序
Comparator compStu=Collections.reverseOrder();
//获得学生信息,存储在Set集合容器中。
Set stu=StudentInfoTool.getStudent(compStu);
//将Set集合容器中的信息存储到文本文件中。
StudentInfoTool.write2File(stu);
}
}
class Student implements Comparable{
private String name;
private int cj1;
private int cj2;
private int cj3;
private int sum;
//构造函数,初始化学生信息,并直接统计成绩总和。
Student(String name,int cj1,int cj2,int cj3){
this.name=name;
this.cj1=cj1;
this.cj2=cj2;
this.cj3=cj3;
this.sum=cj1+cj2+cj3;
}
public String getName(){
return this.name;
}
public int getSum(){
return this.sum;
}
//重写toString()方法。
public String toString(){
return "{Name:"+this.name+","+this.cj1+","+this.cj2+","+this.cj3+"}\t";
}
//重写Comparable中的compareTo方法。
public int compareTo(Student s){
//先比较成绩大小,若成绩相等再比较姓名
int num=new Integer(this.sum).compareTo(new Integer(s.sum));
if(num==0){
return this.name.compareTo(s.name);
}
return num;
}
//重写hash值。
public int hashCode(){
return name.hashCode()+sum;
}
//重写equals方法,当姓名和总成绩相同则为同一个人。
public boolean equals(Object obj){
if(!(obj instanceof Student))
throw new ClassCastException("Student 类型不匹配");
Student s=(Student)obj;
return (this.name.equals(s.name)) && (this.sum==s.sum);
}
}
class StudentInfoTool
{
//重载函数,一个有参,一个无参。
public static Set getStudent() throws Exception{
return getStudent(null);
}
//默认成绩总和从小到大,若使成绩从大到小,可传递比较器参数
//该方法保留了顺排序和逆排序。
public static Set getStudent(Comparator cmp) throws Exception{
//创建缓冲区接收键盘输入学生信息。
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
String str=null;
//创建集合容器,该集合容器盛装Student
Set s=null;
//若按照默认排序,则TreeSet无需传递新的比较器。
if(cmp==null){
s=new TreeSet();
}
else{
s=new TreeSet(cmp);
}
//依次循环读行数据。
while((str=bufr.readLine())!=null){
//行数据为over终止。
if("over".equals(str)){
break;
}
//使用”,“分割字符串并存储到字符串数组。
String[] Stus=str.split(",");
//创建学生对象并初始化。
Student stu=new Student(Stus[0],
Integer.parseInt(Stus[1]),
Integer.parseInt(Stus[2]),
Integer.parseInt(Stus[3]));
//将初始化的学生对象装到集合容器中。
s.add(stu);
}
bufr.close();
//返回集合容器。
return s;
}
//将装有学生信息的集合容器数据存储到文本文件中。
public static void write2File(Set stus)throws Exception{
BufferedWriter bufw=new BufferedWriter(new FileWriter("stu.info"));
//遍历集合中的学生对象,并取出学生信息存储到文本文件。
for(Student s:stus){
bufw.write(s.toString());
//学生总成绩为int型,需转化为字符串。
//BufferedWriter中的write方法为写入单个字符
//若传递的小于128的整数,则会按照ascii码表查询该整数对应的字符。
//若大于128,则返回"?"
bufw.write(s.getSum()+"");
//换行
bufw.newLine();
//使用了缓冲技术,需即时刷新。
bufw.flush();
}
bufw.close();
}
}
在上述函数中,默认排序是按照学生成绩从小到大排序,在不改变原有排序的基础上,通过传递比较器参数,利用重载实现从大到小排序,值得注意。