黑马程序员--- 学习笔记(第二十一天)

 —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————
ObjectInputStream
ObjectOutputStream


流构造的时候,必须有一个目的


直接操作对象数据的流


对象序列化(持久化)
要被流操作的对象必须实现Serialziable接口,否则会抛
NOSerializableException 没有序列化异常,
同时应该自定义SerivalVersionUID,给类一个固定标识符
public static final ServialVersionUID=78L;


InvaildClassException 无效类异常


静态不能被序列化,只能序列化堆内存的,不能序列化方法区的
,不想成员变量被序列化可以加上transient关键字


建议输出流的文件命名: 类名.Object


接口中没有方法称为标志接口


常用方法:
writeObject(); //写入对象
readObject(); //读取返回Object

/*
人类  对象持久化
*/
import java.io.Serializable;
public class   Person implements Serializable
{
	private static final long  serialVersionUID=1314L;
	private String name;
	transient private int age; //被transient修饰不能序列化
	static String city;	//静态不能序列化
	public void setName(String name){
	   this.name=name;
	}
	public String getName(){
		   return name;
	}
	public void setAge(int age){
		 this.age=age;
	}
	public int getAge(){
		return age;
	}
	public Person(String name, int age,String city){
		this.name=name;
		this.age=age;
		this.city=city;
	}
}


/*
 ObjectInputStream
 ObjectOutputStream

 直接操作对象数据的流

 演示两个特殊方法:
 writeObject();
 readObject();
*/
import java.io.*;
class Demo1 
{
	public static void main(String[] args) throws Exception
	{
		//write();
		read();
	}
	public static void read()throws Exception{
		//从Person.object 中读取对象数据
		ObjectInputStream ois=new ObjectInputStream(new FileInputStream("Person.object"));
		//返回Object需要强转
		Person p=(Person)ois.readObject();
		Person p1=(Person)ois.readObject();

	  //无法读取static数据 所以返回null
	//	System.out.println(p.getName()+""+p.city);
	//被transient修饰的变量 返回0 
		System.out.println(p.getName()+""+p.getAge());

		ois.close();
	}
	public static void write()throws IOException{
		//写入对象数据 到Person.object
		ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("Person.object"));
		oos.writeObject(new Person("张三",15,"张角"));
		oos.writeObject(new Person("李四",50,"捏么"));

		oos.close();
	}
}



管道流:
PipedInputStream
PipedOutputStream
输入和输出可以直接进行连接,涉及到多线程


connect();连接流


集合中涉及到IO的是Properties
IO中涉及到多线程的是PipeInputStream,PipeOutputStream


/*
管道流 

PipeInputStream 
PipeOutputStream

演示 
connect() 连接流

  涉及到多线程
*/
import java.io.*;
class Demo2 
{
	public static void main(String[] args)throws Exception 
	{
		PipedInputStream pis=new PipedInputStream();
		PipedOutputStream pos=new PipedOutputStream();

		pis.connect(pos);

		new Thread(new Read(pis)).start();
		Thread.sleep(6000);
		new Thread(new Write(pos)).start();
	}
}
class Read implements Runnable
{
	private PipedInputStream pis;
	public Read(PipedInputStream pis)throws IOException{
		this.pis=pis;
	}
	public void run(){
		
		 try
		{
			byte []buf=new byte[1024];
			int len=0;
			while((len=pis.read(buf))!=-1){
				System.out.println(new String(buf,0,len));
			}
		}
		catch (IOException e)
		{
			System.out.println(e.getMessage());
		}finally
		{
			try
			{
				if(pis!=null)
				pis.close();	
			}
			catch (IOException e)
			{
				System.out.println(e.getMessage());
			}
		}
	}
}
class Write	implements Runnable
{
	private PipedOutputStream pos;
	public Write(PipedOutputStream pos){
		this.pos=pos;
	}
	public void run(){
		try
		{
			pos.write("我是管道流 我来le ".getBytes());

		}
		catch (IOException e)
		{
			System.out.println(e.getMessage());
		}finally
		{
			try
			{
				if(pos!=null)
				pos.close();	
			}
			catch (IOException e)
			{
				System.out.println(e.getMessage());
			}
		}
		
	}
}



RandomAccessFile类
随机访问文件的读取和写入


该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包中的
成员,因为他具备读和写功能,内部封装了一个数组,而是通过指针对数组
元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek
改变指针位置.
其实完成读的原理就是内部封装了输入流和输出流,通过构造函数可以看出
该类只能操作文件,而且操作文件还有模式
r 只读
wr可读可写等


seek();//设置指针,前后都能跳
skipBytes();//跳过字节,只能往后跳


而且该对象的构造函数要操作的文件不存在会自动创建,如果存在则
不会覆盖,如果模式为r只读,不会创建文件,会去读取一个已存在的文件
如果该文件不存在,则会出现异常.如果模式为rw,文件不存在,会自动
创建,不会覆盖文件


可以实现数据的分段写入


/*
RandomAccessFile 类
getFilePointer();//获取指针
skipBytes();//跳过字节
seek(); 设置指针 

实现多线程分段输出
*/
import java.io.*;
class Demo3 
{
	public static void main(String[] args)throws Exception 
	{
		//读取
		RandomAccessFile raf=new RandomAccessFile("g.mp3","rw");
		//写入
		RandomAccessFile raf1=new RandomAccessFile("gg.mp3","rw");
		//三个线程进行分段写入
		//seek 设置指针位置 实现分段功能
		new Thread(new Thread1(raf,raf1,0)).start();

		new Thread(new Thread1(raf,raf1,2097152)).start();
		
		new Thread(new Thread1(raf,raf1,4194304)).start();
	}
}
//多线程
class Thread1 implements Runnable
{
	private RandomAccessFile raf;
	private RandomAccessFile raf1;
	private int skip;
	public Thread1(RandomAccessFile raf,RandomAccessFile raf1,int skip){
		this.raf=raf;
		this.raf1=raf1;
		this.skip=skip;
	}
	//run方法
	public void run(){
	   try
	   {
		   byte []buf=new byte[1024*1024*2];
		   int len=0;
			len=raf.read(buf);
			raf1.write(buf,0,len);
	   }
	   catch (IOException e)
	   {
		   System.out.println(e.getMessage());
	   }
	   finally
	   {
			try
			{
				if(raf!=null)
					raf.close();
				if(raf1!=null)
					raf1.close();
			}
			catch (IOException e)
		   {
			   System.out.println(e.getMessage());
		   }
	   }
	}
}



DataInputStream与DataOutputStream
可以用来操作基本数据类类型的流对象
//注意, 写入的UTF-8修改版, 正常UTF-8无法读取
writeUTF();
readUTF();


/*
DataInputStream
DataOutputStream
操作基本数据类型的流对象
*/
import java.io.*;
class Demo4 
{
	public static void main(String[] args)throws Exception 
	{	
		//write();
	   //read();
	   
	   DataOutputStream dos=new DataOutputStream(new FileOutputStream("utf.txt"));
	  	 //使用utf-7修改版写输入
		 dos.writeUTF("你好");
		 dos.close();
	   DataInputStream dis=new DataInputStream(new FileInputStream("utf.txt"));
		 /*
		 //不能使用默认GBK的编码读 会乱码
		 byte bu[]=new byte[10];
		 int len=dis.read(bu);
		 sop(new String(bu,0,len));
		 */
		 //只能使用ReadUTF才能读出来
		 sop(dis.readUTF());
		 dis.close();
	}
	public static void read()throws IOException{
		DataInputStream dis=new DataInputStream(new FileInputStream("type.txt"));
		//读的时候要按照写的顺序
		sop(dis.readBoolean());
		sop(dis.readByte());
		//等等
		dis.close();
	}
	public static void write()throws IOException{
				DataOutputStream dos=new DataOutputStream(new FileOutputStream("type.txt"));
//		 void writeBoolean(boolean v) 
//          将一个 boolean 值以 1-byte 值形式写入基础输出流。 
			dos.writeBoolean(true);
//		 void writeByte(int v) 
//          将一个 byte 值以 1-byte 值形式写出到基础输出流中。 
			 dos.writeByte(102);
//		void writeBytes(String s) 
//          将字符串按字节顺序写出到基础输出流中。
			dos.writeBytes("bytes");
//		void writeChar(int v) 
//          将一个 char 值以 2-byte 值形式写入基础输出流中,先写入高字节。 
			dos.writeChar(97);
//		void writeChars(String s) 
//          将字符串按字符顺序写入基础输出流。 
			dos.writeChars("chars");
//		void writeDouble(double v) 
//          使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。 
			dos.writeDouble(4454.12);
//		void writeFloat(float v) 
//          使用 Float 类中的 floatToIntBits 方法将 float 参数转换为一个 int 值,然后将该 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。 
			dos.writeFloat(12.14f);
//		void writeInt(int v) 
//          将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。 
			dos.writeInt(12121);
//		void writeLong(long v)  
//   将一个 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。
			dos.writeLong(4444444);
		dos.close();
	}
	public static void sop(Object o){
		System.out.println(o);
	}
}



字节数组流:
ByteArrayInputStream
在构造时需要接受数据源,数据源是一个字节数组
ByteArrayOutputStream
在构造时不用定义数据目的,因为该对象中内部已经封装了可变长度的字节数组


因为这两个对象操作的是数组,没有使用底层资源,所以不用进行close关闭
,不会抛任何IOException,除了writeTo(OutputStream);


toByteArray();//变成字节数组
size();//缓冲区大小
toString();//变成字符串形式
writeTo();//写出到字节输出流


设备:内存就是数组流


用流的读写思想操作数组,,


/*
ByteArrayInputStream
ByteArrayOutputStream

字节数组流

只要不使用WriteTo();
其他方法都不操作底层数据 不会发生异常
*/
import java.io.*;
class Demo5 
{
	public static void main(String[] args)
	{
		String s="不管还有多少明天";
		System.out.println("字节输入读取流\n");
		ByteArrayInputStream bis=new ByteArrayInputStream(s.getBytes());
		byte []bb=new byte[1024];
		int ch=0;
		while((ch=bis.read(bb,0,1024))!=-1){ //读取
			System.out.println(new String(bb,0,ch));
		}
		 System.out.println("\n字节数组写入流");
		ByteArrayOutputStream bos=new ByteArrayOutputStream();
		bos.write(12); //写入字节
		bos.write(5);
		bos.write(56);
		byte []bu=bos.toByteArray();//转成字节数组
		for (byte b : bu )
		{
			System.out.println(b);
		}
		System.out.println(bos.size());//获取缓冲区大小
	}
}



字符数组流:
CharArrayInputStream与CharArrayInputStream


字符串流:
StringReader与StringWriter


字符编码:
常见的编码表:
ASCII:美国标准信息交换码  一个字节7位表示
ISO8859-1:拉丁码表,欧洲码表  一个字节8位表示 最高位1
GB2312中国的中文编码表,两个字节表示 每个字节最高位1
GBK 中国的编码表升级,融合了更多的中文字符等
Unicode:国际标准码表,融合了多种文字,所有文字都有两个字节表示,
java使用的就是Unicode,  char字符
UTF-8:最多用三个字节表示


编码:字符串变成字节数组
str.getBytes();//可以指定编码
解码:字节数组变成字符串
new String();//构造时可以指定编码


例如:
String s="你好";
byte []b=s.getBytes("GBK");


如果指定的编码不存在会报UnsupportedEncodingException 不支持的编码异常


乱码,编一次,解一次


UTF-8标识头,标识一开始读几个字节,最多三个
一个字节:0
两个字节:110 0
三个字节:1110 10 10


/*
字符编码

编码 

解码
*/
import java.io.*;
import java.util.*;
class Demo6 
{
	public static void main(String[] args)throws Exception 
	{  /*
		String s="你好";
		byte []b=s.getBytes();
		byte []b1=s.getBytes("gbk");
		byte []b2=s.getBytes("iso8859-1");
		byte []b3=s.getBytes("utf-8");
		sop(Arrays.toString(b));
		//使用编码会引发UnsupportedEncodingException
				System.out.println("\n b的多种解码格式 \n");
		sop(new String(b));
		sop(new String(b,"gbk"));
		sop(new String(b,"utf-8"));	//no  ???
		sop(new String(b,"iso8859-1"));//no	 ????




	  		System.out.println("\n b1的多种解码格式 \n");
		sop(new String(b1));   
		sop(new String(b1,"gbk"));
		sop(new String(b1,"utf-8"));  //no ???
		sop(new String(b1,"iso8859-1"));//no  ????
	   		System.out.println("\n b2的多种解码格式 \n");
		sop(new String(b2));	//no ??
		sop(new String(b2,"gbk")); //no  ??
		sop(new String(b2,"utf-8"));//no ??
		sop(new String(b2,"iso8859-1"));//no ??
		System.out.println("\n b3的多种解码格式 \n");
		sop(new String(b3));	// no 浣犲ソ 
		sop(new String(b3,"gbk"));// no 浣犲ソ
		sop(new String(b3,"utf-8"));
		sop(new String(b3,"iso8859-1"));//no ??????
		*/
		/*
	
	
	
		默认字符串编码是gbk 使用的是系统默认的
		*/
		/*
		String s="你好";
		byte []b=s.getBytes("gbk");
		String str=new String(b,"utf-8");
		sop(str); // ??? 
		byte bb[]=str.getBytes("utf-8");
		sop(new String(bb,"gbk"));//锟斤拷锟?
		*/
		/*	*/
		 String s="你好";
		byte []b=s.getBytes("utf-8");
		String str=new String(b,"gbk");
		sop(str);	 // 浣犲ソ
		//在编一次,在解一次
		byte bb[]=str.getBytes("gbk");
		sop(new String(bb,"utf-8"));  //你好
		
		/*
		String s="你好";
		byte []b=s.getBytes("iso8859-1");
		String str=new String(b,"utf-8");
		sop(str); // ??
		byte bb[]=str.getBytes("utf-8");
		sop(new String(bb,"iso8859-1"));//??
		*/
	}
	public static void sop(Object o){
		System.out.println(o);
	}
}



/*
练习题
*/
/*
练习

有五个学生,每个学生都有三门成绩

键盘录入
格式:张三,40,50,60
计算他们的总成绩, 按总分高低排序输出到stu.txt
*/
import java.util.*;
import java.io.*;
class Demo7 
{
	public static void main(String[] args)throws Exception 
	{	
	//反转比较器	
	Comparator<Student> cmp=Collections.reverseOrder();
		  //获取集合
		 TreeSet<Student> ts=set(cmp);
		toText(ts);	
	}
	//将数据录入存储到集合 不使用比较器
	public static TreeSet<Student> set()throws Exception{
		return set(null);
	}
	//将数据录入存储到集合 使用比较器
	public static TreeSet<Student> set(Comparator<Student> cmp)throws Exception{
		TreeSet<Student> ts=new TreeSet<Student>();
		if(cmp!=null)
			  ts=new TreeSet<Student>(cmp);
			
		//反转比较器 进行排序 Collection.reverseOrder()
		 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		 String line=null;
		 while((line=br.readLine())!=null){
			 if("over".equals(line))
				 break;
			 String info[]=line.split(",");
		    ts.add(new Student(info[0],new Integer(info[1]),new Integer(info[2]),new Integer(info[3])));
		 }
		br.close();

		return ts;
	}
	//写到硬盘文件 stud.txt
	public static void toText(TreeSet<Student> ts)throws IOException{
		//写入流
		PrintWriter pw=new PrintWriter(new FileOutputStream("stud.txt"));
		 Iterator<Student> it=ts.iterator();
		 while(it.hasNext()){
		 	Student s=it.next();
			pw.println(s.toString());//目的是流 所以自动刷新
		 }

		 pw.close();
	}
}
//学生类,自身具备成绩比较性
class Student implements Comparable<Student>
{
	private String name;  //姓名
	private int Yuwen;	  //语文
	private int Shuxue;	 //数学
	private int Yingyu;	 //英语
	private int sum;  //总分
	public void setName(String name){
		this.name=name;
	}
	public String getName(){
		return name;
	}
	public void setYuwen(int Yuwen){
		this.Yuwen=Yuwen;
	}
	public int getYuwen(){
		return Yuwen;
	}
	public void setShuxue(int Shuxue){
		 this.Shuxue=Shuxue;
	}
	public int getShuxue(){
	   return Shuxue;
	}
	public void setYingyu(int Yingyu){
		this.Yingyu=Yingyu;
	}
	public int getYingyu(){
		return Yingyu;
	}
	public int getSum(){
		 return Yuwen+Shuxue+Yingyu;
	}
	//构造函数
	public Student(String name, int Yuwen, int Shuxue, int Yingyu){
		this.name=name;
		this.Yuwen=Yuwen;
		this.Shuxue=Shuxue;
		this.Yingyu=Yingyu;
	}
	//复写 hashCode
	public int hashCode(){
		return (this.getName().hashCode())+(getSum()*13);
	}
	//复写 equals
	public boolean equals(Object obj){
	   if(! (obj instanceof Student))
		   throw new ClassCastException("类型转换异常");

	   Student s=(Student)obj;
	   return (this.getName().equals(s.getName()))&&this.getSum()==s.getSum();
	}
	//复写compareTo
	public int compareTo(Student s){
		int num=new Integer(this.getSum()).compareTo(new Integer(s.getSum()));
		if(num==0)
			return	this.getName().compareTo(s.getName());
			return num;
	}
	//复写
	public String toString(){
		return "Student["+name+" "+Yuwen+" "+Shuxue+" "+Yingyu+" "+getSum()+" ]";
	}
}

/*
lisi,10,20,30
wanwu,50,60,40
zhaoliu,100,50,60
wangwu,45,78,32
woziji,100,100,99
*/









 —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值