------- android培训、java培训、期待与您交流! ----------
1 对象的存储ObjectInputStream(InputStream())和ObjectOutputStream(OutputStream())
/*例子1:对象的存储ObjectInputStream和ObjectOutputStream对象的存储,这两个类是要一起用的,用它写的就要用它去读
ObjectInputStream(InputStream());
ObjectOutputStream(OutputStream());
要实现Serializable的原因:
每个类都有一个标记,对象从这个类产生之后,对象的标记和类的标记是一样的,
可是当类里的变量或者方法改变之后,产生对象的类的标记就发生变化了,因为标记是根据类的成员而计算出来的
于是对象的标记跟类的标记就不同了,当流去读存储在文件里的对象时,对象要通过类才能编译,但是以前产生的对象跟现在的类标记不一样了,对象读不出来
被静态修饰了的成员,不会保存在文件上,因为你保存的对象是在堆内存的,而静态的成员或方法都是在方法区里的
存储对象的时候,某些文件不想写在文件上,可以用transient修饰,经过修饰的变量将不会随对象存储
*/
import java.io.*;
import java.util.*;
class Person implements Serializable//要实现Serializable接口,这个接口里面没有抽象方法, 不用复写操作
{
private String name;
private int age;
//transient private int age; 这个age不会随对象存储在文件上
//static private int age; 这个age不会随对象存储在文件上
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String toString()
{
return name+":"+age;
}
}
class ObjectDemo
{
public static void main(String[] args)throws Exception
{
writePerson();
readPerson();
}
public static void readPerson()throws Exception
{
ObjectInputStream obi=new ObjectInputStream(new FileInputStream("person.txt"));
Person p1=(Person)obi.readObject();
Person p2=(Person)obi.readObject();
Person p3=(Person)obi.readObject();
sop(p1);
sop(p2);
sop(p3);
}
public static void writePerson()throws IOException
{
ObjectOutputStream obo=new ObjectOutputStream(new FileOutputStream("person.txt"));
obo.writeObject(new Person("zhangsan01",30));
obo.writeObject(new Person("zhangsan02",31));
obo.writeObject(new Person("zhangsan03",32));
obo.close();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
2 管道流:PipedInputStream和PipedOutputStream
connect()方法
in.connect(out);//把两个流关联起来
read()是阻塞方法,当没有数据可读时,会等待,知道写入数据,才会执行
/*
这是管道流写入和读取的例子
*/
import java.io.*;
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in=in;
}
public void run()
{
try
{
byte[] bt=new byte[1024];
System.out.println("没有数据可读,阻塞");
int len=in.read(bt);
System.out.println("有数据可读,解除阻塞");
String s=new String(bt,0,len);
System.out.println(s);
in.close();
}
catch(Exception e)
{
throw new RuntimeException("管道流读取失败");
}
}
}
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out=out;
}
public void run()
{
try
{
Thread.sleep(6000);
System.out.println("正在写入数据");
out.write("我是输出流,大爷我来啦".getBytes());
out.close();
}
catch(Exception e)
{
throw new RuntimeException("管道流写入失败");
}
}
}
class PipedDemo
{
public static void main(String[] args)throws Exception
{
PipedInputStream in=new PipedInputStream();
PipedOutputStream out=new PipedOutputStream();
in.connect(out);//把两个流关联起来
Read r=new Read(in);
Write w=new Write(out);
Thread t1=new Thread(r);
Thread t2=new Thread(w);
t1.start();
t2.start();
}
}
3 RandomAccessFile随机访问文件的功能演示:
这个类既能读又能写
它是直接继承于Object的,不是IO流的子类,但是RandomAccessFile类是属于io包的,因为它有读写功能,其实它里面封装了流对象,原理是里面封装了一个数组,数组里存的都是字节
一个汉字等于一个字符,一个字符等于两个字节,一个int类型的数字等于4个字节
3.1)主要功能:
能够改变指针,来读取或者写入字节:
seek(int x);//可以随意改变数组的指针大小
skip(int x);//也是改变数组的指针来读写,但是指针只能越来越大
3.2)构造方法:
RandomAccessFile raf=new RandomAccessFile("1.txt","mode");
1传入要读写的文本文件
2mode模式:r 只能写 rw既能读又能写 rws rwd
如果模式是r,当传入的文件不存在,程序会报异常,
如果模式是rw,当传入的文件存在,写入数据将不会覆盖整个文件,而只是覆盖写入数据对应的指针位置的数据,不像以前那些,如果指定文件存在了就把整个文件完全覆盖掉,当指定的文件不存在,会新建一个文件
/*
例子:随机访问文件的例子
*/
import java.io.*;
class RandomAccessFileDemo
{
public static void main(String[] args)throws Exception
{
RandomAccessFile raf=new RandomAccessFile("raf.txt","rw");
raf.write("张三".getBytes());
raf.writeInt(97);
byte[] buf=new byte[4];
raf.read(buf);
String s=new String(buf);
System.out.println(s);
}
}
4 操作基本数据类型的流对象 DataInputStream()和DataOutputStream(); 4.1)功能
writeInt()
writeBoolean()
writeDouble()
writeUTF()
/*
例子:操作基本数据类型的流对象 DataInputStream()和DataOutputStream()的例子
*/
import java.io.*;
class DataStreamDemo
{
public static void main(String[ ] args)
{
outD();
intD();
}
public static void intD()throws Exception
{
DataInputStream das=new DataInputStream(new FileInputStream("haha.txt"));
sop(das.readInt());
sop(das.readBoolean());
sop(das.readDouble());
}
public static void outD()throws Exception
{
DataOutputStream dao=new DataOutputStream(new FileOutputStream("haha.txt"));
dao.writeInt(13);//int类型是4个字节的所以用writeInt(int x);
dao.writeBoolean(true);//Boolean是一个字节,用writBoolean;
dao.writeDouble(111.222);//Double类型是8个字节,用writeDouble;
/*
还有这个功能
dao.writeUTF("您好");//这是采用新的utf-8编译的
*/
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
现在源和目的都是内存
把数组跟流结合起来了
ByteArrayInputStream(byte[])//源传入一个字节数组
ByteArrayOutputStream();//目的,里面自动封装一个可变长度的字节数组,把传进来的字节数组,存到字节数组里面
把数组变成字符串打印数组里的东西:
Arrays.toString(byt[] buf);操作字符数组
CharArrayReader(char[])//传入一个字符数组
CharArrayReader()
操作字符串
StringReader(String s)
StringWriter()
/*
例子:数组跟流结合的例子ByteArrayInputStream(byte[])和ByteArrayOutputStream()
*/
import java.io.*;
class ByteDemo
{
public static void main(String[] args)throws IOException
{
ByteArrayInputStream bis=new ByteArrayInputStream("abcde".getBytes());
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int a=0;
while((a=bis.read())!=-1)
{
bos.write(a);
}
System.out.println(bos.size());//打印数组输出流中的size方法可以把存储在内存里
的数组大小打印出来
System.out.println(bos); //直接打印数组输出流可以把存储在内存里的字节打印出来
}
}
/*
例子:有个5个学生,每个学生有3门课的成绩
从键盘输入以上数据,包括姓名和三门课成绩
输入格式:zhangsan,20,40,60
并把学生的信息和计算出的总分数高低顺序存放在磁盘文件
*/
import java.io.*;
import java.util.*;
//定义一个学生类
class Student implements Comparable<Student>
{
private String name; //姓名
private double ma,cn,en; //三门课程的分数
private double sum; //总分
Student(String name,double ma,double cn,double en) //构造函数初始化
{
this.name=name;
this.ma=ma;
this.en=en;
this.cn=cn;
sum=ma+cn+en; //总分
}
public void setName(String s) //函数修改学生姓名
{
this.name=name;
}
public String getName() //获取学生姓名
{
return this.name;
}
public double getSum() //获取总分
{
return this.sum;
}
public int compareTo(Student s) //覆盖compareTo()方法
{
int num=new Double(this.sum).compareTo(new Double(s.sum));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
public int hashCode() //覆盖hashCode()方法
{
return this.name.hashCode()+(int)sum*31;
}
public boolean equals(Object obj)//覆盖equals方法
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student stu=(Student)obj;
return this.name.equals(stu.name)&&this.sum==stu.sum;
}
public String toString()//覆盖toString方法
{
return "Student["+name+", "+ma+", "+cn+", "+en+"]";
}
}
class StudentTool
{
public static Set<Student> getStudents()//这个得到的是自然排序的集合
{
return getStudents(null);
}
//这个是有比较器的集合
public static Set<Student> getStudents(Comparator<Student> cmp)
{
Set<Student> stus=null;
if(cmp==null)
stus=new TreeSet<Student>(); //定义一个自然排序的treeSet集合
else
stus=new TreeSet<Student>(cmp);//定义一个自定义排序的集合
//创建一个字符流,以便键盘录入
BufferedReader bufr=null;
try
{
bufr=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bufr.readLine())!=null)
{
if(line.equals("over"))//键盘录入的退出条件
break;
String[] str=line.split(","); //用","切割从键盘读取到的字符串
//创建学生对象
Student stu=new Student(str[0],new Double(str[1]),new Double(str[2]),new Double(str[3]));
stus.add(stu);//把学生对象添加到集合
}
}
//异常处理
catch(Exception e)
{
throw new RuntimeException("键盘录入失败");
}
finally
{
if(bufr!=null)
try
{
bufr.close();
}
catch(Exception e)
{
throw new RuntimeException("键盘录入关闭失败");
}
}
return stus; //返回一个学生集合
}
//定义一个功能把学生集合,得到相应文件
public static void write2File(Set<Student> stus)
{
//创建一个字符输出流
BufferedWriter bufw=null;
try
{
bufw=new BufferedWriter(new FileWriter("student.txt"));
for(Student stu:stus)//遍历接受进来的集合
{
bufw.write(stu.toString()+"\t");//把学生信息写进目的文件
bufw.write(stu.getSum()+""); //把总分写进目的文件
bufw.newLine(); //换行
bufw.flush();//刷新流
}
}
//处理异常
catch(Exception e)
{
throw new RuntimeException("文件写入失败");
}
finally
{
if(bufw!=null)
try
{
bufw.close();
}
catch(Exception e)
{
throw new RuntimeException("文件关闭失败");
}
}
}
}
class StudentTest
{
public static void main(String[] args)
{
Comparator<Student> cmp=Collections.reverseOrder();//逆转比较器
//调用静态方法取得学生集合
Set<Student> stus=StudentTool.getStudents(cmp);
//调用静态方法把集合中的学生写到目的文件
StudentTool.write2File(stus);
}
}