黑马程序员 IO流(3)

-------android培训、java培训、期待与您交流! ----------

第一节  对象序列化

一.概述.

ObjectOutputStreamObjectInputStream

 

作用:ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。

注意:只能将支持 java.io.Serializable 接口的对象写入流中。就是每个要写入流中的对象要实现serializable接口.

若一个类实现了serializable接口。会使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联。版本号是根据类的成员算出来的。也包括类的修饰符,静态成员是不能被序列化的。要想非静态成员也不实现序列化则可以在成员家修饰符transien

没有方法的接口通常称之为标记接口

实例:

package itcast;

import java.io.*;

public class ObjStreaDemo {
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{
		    readObj();
	}
	     public static void readObj() throws FileNotFoundException, IOException, ClassNotFoundException{
	    	 ObjectInputStream os = new ObjectInputStream(new FileInputStream("obj.txt"));
	    	 Person p = (Person)os.readObject();
	    	 System.out.println(p);
	     }
		 public static void writeObj() throws FileNotFoundException, IOException{
			   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
			   oos.writeObject(new Person("fenfen",19));
			   oos.close();
		 }
	

}

                  第二节 管道流

一.概述

PipedInputStreamPipedOutputStream

输入输出可以直接进行连接,通过结合线程使用。

IO流中和集合结合使用的是properties,和多线程结合使用的是PipedInputStreamPipedOutputStream

构造方法:

1.PipedInputStream()
          创建尚未连接的 PipedInputStream。

2.PipedInputStream(PipedOutputStream src)
          创建 PipedInputStream,使其连接到管道输出流 src。

方法:

 void

connect(PipedOutputStream src)
          使此管道输入流连接到管道输出流 src。

实例:

package itcast;

import java.io.*;

 class PipedStreamDemo {
	 public static void main(String[] args){
		 //创建管道输入流
		  PipedInputStream in  =  new PipedInputStream();
		  //创建管道输出流
		  PipedOutputStream out = new PipedOutputStream();
		  try {
			  //利用connect()方法把管道输入流和输出流连接在一起
			in.connect(out);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		  Read r = new Read(in);
		  Write w = new Write(out);
		  new Thread(r).start();
		  new Thread(w).start();
	 }

}
 
 //创建管道输入流线程
 class Read implements Runnable{
     private PipedInputStream in;
     //创建构造方法传入管道输入流
     Read(PipedInputStream in){
    	   this.in=in;
     }
	@Override
	public void run() {
		try{
			byte[] b = new byte[1024];
			System.out.println("读取前.......没有数据堵塞");
			int len=in.read(b);
			System.out.println("读到数据......堵塞结束");
			String s = new String(b,0,len);
			System.out.println(s);
			in.close();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
	}
	 
 }
 //创建管道输出流 
 class Write implements Runnable{
     private PipedOutputStream out;
   //创建构造方法传入管道输出流
     Write(PipedOutputStream out){
    	 this.out=out;
     }
	@Override
	public void run() {
		
	     try {
	    	 System.out.println("开始写入数据,等待6秒后");
	    	 try {
				Thread.sleep(6000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			out.write("piped lai la".getBytes());
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	 

  
  
}

第三节  RandomAccessFile

一.概述

1.此类的实例支持对随机访问文件的读取和写入。

2.该类不是IO体系中的子类,而是直接继承自Object。但是它是IO包中成员,因为它具备读和写功能。内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。

3.该类能完成读写的原理就是内部封装了字节输入流和输出流。

4.通过构造函数可以看出,该类只能操作文件。而且操作文件还有模式:

RandomAccessFile(File file, String mode)
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

RandomAccessFile(String name, String mode)
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

mode 参数指定用以打开文件的访问模式。允许的值及其含意为:

含意

"r"

以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException

"rw"

打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。

"rws"

打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。

"rwd"  

打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。

 

如果模式为只读 r。不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常,如果模式为rw,操作文件不存在,会自动创建。如果存在则不会覆盖。

方法:

void seek(long pos);  设置读写指针,可往前也可往后。

void skipBytes(int n); 尝试跳过输入的n个字节,只可往后不能往前。

实例:

package itcast;
import java.io.*;
public class RandomAccessDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
        // writerFile();
		readFile();
		//writerFile_2();
	}
	
	public static void readFile() throws IOException{
		RandomAccessFile raf = new RandomAccessFile("obj.txt","r");
		byte[] b = new byte[4];
		int len=0;
		raf.seek(8*3);
		len = raf.read(b);
		String name = new String(b,0,len);
		System.out.println(name);
		int age =raf.readInt();
		System.out.println(age);
	}
	public static void writerFile() throws IOException{
		//创建随机访问流对象
		RandomAccessFile raf = new RandomAccessFile("obj.txt","rw");
		//向obj.txt文件写入数据
		raf.write("李四".getBytes());
		raf.writeInt(97);
		raf.write("王五".getBytes());
		raf.writeInt(102);
		//关闭流
		raf.close();
	}
	public static void writerFile_2() throws IOException{
		RandomAccessFile raf = new RandomAccessFile("obj.txt","rw");
		raf.seek(8*3);
		raf.write("周七".getBytes());
		raf.writeInt(128);
		raf.close();
	}

}

 第四节  操作基本数据类型类

一.概述

DataOutputStreamDataInputStream

构造函数:

DataInputStream(InputStream in) ;  可以看到在构造函数时就要传递基类InputStream

 

特有方法:

DataInputStream:

  int read();  读取一个Int类型数据

  double readDouble(); 读取一个Double类型数据

  boolean readBoolean(); 读取一个boolean类型数据

  String readUTF(); 以特有的方式读取数据。

DataOutputStream

  WriteInt(int v) ;将一个int值以4个字节形式写入基础输出流,先写入高字节。

  WriteDouble(double d) ;使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。

  WriteBoolean(boolean b) ;将一个 boolean 值以 1-byte 值形式写入基础输出流。


第五节  操作数组和字符串

ByteArrayInputStream:在构造的时候,需要接收数据源。而且数据源是一个字节数组。

ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。这就是数据目的地。

因为这两个流对向都操作的数组,并没有使用系统资源。所以。不用进行close关闭。

特有方法:

 byte[] toByteArray();创建一个新分配的byte数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中。

 String toString();  以字符串形式返回缓冲区的内容

在流操作规律讲解时:

源设备:键盘(System.in),硬盘(FileStream),内存(ArrayStream)

目的设备:控制台(System.out),硬盘,内存

用流的思想来操作数组。

字符数组流对象:CharArrayReaderCharArrayWriter

字符串流对象:   StringReaderStringWriter

第六节  字符编码

字符流的出现为了方便操作字符。更重要是加入了编码转换。

通过子类转换流来完成。InputStreamReader OutputStreamWriter

在两个对象进行构造的时候可以加入字符集。

编码表的由来:

  计算机只能识别二进制数据,早期由来是电信号。

  为了方便应用计算机,让它可以识别各个国家的文字。

就将各个国家的文字用数字来表示,并一一对应,形成一张表。

这就是编码表。

ASCII:美国标准信息交换码。用一个字节的7位可以表示。

ISO8859-1:拉丁码表。欧洲码表。用一个字节的8位表示。

GB2312:中国的中文编码表。

GBK:中国的中文编码表升级,融合了更多地中文文字符号。

Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-8:最多用三个字节来表示一个字符。

编码:字符串变成字节数组。

解码:字节数组变成字符串。

String--> byte[];  str,getBytes();

 

byte[]--> string ;  new String(byte[])

 

三、对于编码和解码的字符集转换

1、如果编码失败,解码就没意义了。

2、如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。

3、如果用的是GBK编码,UTF-8解码,那么再通过2的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。

package itcast;

import java.io.*;
import java.util.Arrays;

public class EncodeDemo {
	public static void main(String[] args) throws Exception{
		  //编码 把字符串编码成字节
         //  byte[] by = "你好".getBytes();  //系统默认使用gbk编码
           //也可以自己指定编码形式
		  String s = "你好";
           byte[] by = s.getBytes("gbk");
           System.out.println(Arrays.toString(by));
           
           String s1 = new String(by,"gbk"); //以utf-8解码
           System.out.println(s1);
           //要是解码接错了,该怎么办呢? 
           //把解错码的字符串重新编码,在用对的解码形式重新解码就可以解决了。
           //这种方法只适用于以iso8859-1的解码形式。
           String s2 = new String(by,"iso8859-1");
           System.out.println(s2);
           
           byte[] by2 = s2.getBytes("iso8859-1");  //重新编码
           System.out.println(Arrays.toString(by2));
           String s3 = new String(by2,"gbk");  //重新解码
           System.out.println(s3);
	}

}

package itcast;

import java.io.*;
public class EncodeText {
	 public static void main(String[] args) throws IOException{
		 writeTxt();
	 }
	 public static void writeTxt() throws IOException{
		   //创建字符转换流,把你好以gbk的编码形式写入到gbk.txt的文件中
		   OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"utf-8");
		   osw.write("你好");
		   osw.close();
	 }
	 public static void readTxt() throws IOException{
		 //创建输入转换流,以gbk的编码表读取
		 InputStreamReader  isr = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");
		 char[] c = new char[10];
	     int len = isr.read(c);
	     String s = new String(c,0,len);
	     System.out.println(s);
	 }

}

第七节  练习

有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩),输入的格式如:zhangsan,30,40,60计算出总成绩,并把学生的信息和计算出的总分高低顺序存放在磁盘文件“stud.txt”中。

 

1.描述学生对象。
2.定义一个可操作学生对象的工具类。

思想:

1.通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。

2.因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。所以可以使用TreeSet

3.将集合的信息写入到一个文件中。

package itcast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
  class IoText {
	public static void main(String[] args) throws IOException{
		 Comparator<Student> cmp = Collections.reverseOrder();
		  Set<Student> s =StudentInfoTool.getStudent(cmp);
		  StudentInfoTool.Write2File(s);
	}
  }
//创建学生类
class Student implements Comparable<Student>{
	 private String name;
	 private int ma,cn,en;
	 private int sum;
	 //定义构造方法,在学生创建时就赋予它基本信息(名字,成绩,总成绩)
	 Student(String name,int ma,int cn,int en){
		 this.name=name;
		 this.ma=ma;
		 this.cn=cn;
		 this.en=en;
		 this.sum= ma + cn + en;
	 }
	 //向外部提供获取学生姓名的方法
	 public String getName(){
		 return this.name;
	 }
	 //向外部提供获取学生总成绩的方法
	 public int getSum(){
		 return this.sum;
	 }
	 
	 //覆盖hashcode方法
	 public int hashCode(){
		return name.hashCode()+sum*78;
	 }
	@Override
	public int compareTo(Student o) {
		// TODO Auto-generated method stub
		int num = new Integer(this.sum).compareTo(new Integer(o.sum));
		if(num==0)
			return this.name.compareTo(o.name);
		return num;
	}
	public boolean equals(Object s){
		if(!(s instanceof Student)){
			 throw new ClassCastException("类型不匹配");
		}
		Student st = (Student)s;
		return this.name.equals(st.name)&&this.sum==st.sum;
	}
	public String toString(){
		return "Student["+name+", "+ma+", "+cn+","+en+"]";
	}
}

class StudentInfoTool{
	public static Set<Student> getStudent() throws IOException{
		  return getStudent(null);
	}
	 public static Set<Student> getStudent(Comparator<Student> cmp) throws IOException{
		 Set<Student> st =null;
		 if(cmp==null)
			 st = new TreeSet<Student>();
		 else
			 st=new TreeSet<Student>(cmp);
		 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		 String len ="";
		 while((len=br.readLine())!=null){
			 if(len.equals("over"))
				 break;
			  String[] s = len.split(",");
			  Student stu = new Student(s[0],Integer.parseInt(s[1]),Integer.parseInt(s[2]),Integer.parseInt(s[3]));
			  st.add(stu);
		 }
		 return st;
	 }
	 public static  void Write2File(Set<Student> s) throws IOException{
		    BufferedWriter bw = new BufferedWriter(new FileWriter("stu.txt"));
		    for(Student ss:s){
		           bw.write(ss.toString()+"\t");
		           bw.write(ss.getSum()+" ");
		           bw.newLine();
		           bw.flush();
		    	}
		    bw.close();
	 }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值