黑马程序员——JavaIO包中的其他类

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

自学Java第十一天笔记。本人是根据毕向东老师的JavaSE视频学习的。



JavaIO包中的其他类



一.打印流。

1.理解:
该流提供了打印方法,可将各种类型的数据都原样打印。


2.分类:
1)、字节打印流(PrintStream)。
2)、字符打印流(PrintWriter)。


3.字节打印流:PrintStream。
构造函数可以接收的参数类型:
1)、file对象。File
2)、字符串路径。String
3)、字节输出流。OutputStream


4.字符打印流:PrintWriter。
构造函数可以接收的参数类型:
1)、file对象。File
2)、字符串路径。String
3)、字节输出流。OutputStream
4)、字符输出流。Writer


注意:开发时尽量使用PrintWriter。


5.练习:
(代码 PrintDemo.java):
//打印流练习:
//键盘录入到a.txt文件中。
import java.io.*;
class PrintDemo
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter pw = new PrintWriter(new FileWriter("a.txt"),true);//传入true,会自动刷新
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			pw.println(line.toUpperCase());//写入数据
		}
		pw.close();
		bufr.close();
	}
}



二.序列流(SequenceInputStream)。

1.理解:
对多个流进行合并。也被称为合并流。(将多个读取流合并为一个读取流)


2.例子:(合并文件)
(代码 SequenceDemo.java):
//例子:将1.txt和2.txt合并为一个文件3.txt。
/*
思路:
1,先创建一个vector集合,把文件1.txt和2.txt加载到集合中。
2,创建枚举(Enumeration)对象,把集合加入。
3,确定源,创建序列流(合并流),用来接收枚举对象。
4,确定目的,创建字节输出流对象,用来关联3.txt。
5,利用SequenceInputStream对象和FileOutputStream对象进行反复读写操作。
*/
import java.io.*;
import java.util.*;
class SequenceDemo 
{
	public static void main(String[] args) throws IOException
	{
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(new FileInputStream("1.txt"));
		v.add(new FileInputStream("2.txt"));
		Enumeration<FileInputStream> e = v.elements();
		SequenceInputStream sis = new SequenceInputStream(e);
		FileOutputStream fos = new FileOutputStream("3.txt");
		byte[] buf = new byte[1024];
		int num = 0;
		while((num=sis.read(buf))!=-1)
		{
			fos.write(buf,0,num);
		}
		fos.close();
		sis.close();
	}
}


3.练习:(切割文件)
(代码 SplitFile.java):
import java.io.*;
class SplitFile 
{
	public static void main(String[] args) throws IOException
	{
		FileInputStream fis = new FileInputStream("1.bmp");
		FileOutputStream fos = null;
		byte[] buf = new byte[1024*1024];
		int num = 0;
		int count = 1;
		while((num=fis.read(buf))!=-1)
		{
			fos = new FileOutputStream((count++)+".part");
			fos.write(buf,0,num);
			fos.close();
		}
		fis.close();
	}
}



三.操作对象的流(对象的序列化)。

1.理解:
将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化)。


2.分类:
ObjectOutputStream和ObjectInputStream。


3.特有方法练习:
(代码 ObjectStreamDemo.java 和 Person.java):
import java.io.*;
class ObjectStreamDemo 
{
	public static void main(String[] args) throws Exception
	{
		//writeObj();
		readObj();
	}
	//把对象持久的存入到文件中。
	public static void writeObj() throws Exception
	{
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
		oos.writeObject(new Person("lisi",39));//先定义一个Person类。
		oos.close();
	}
	//读取文件中的对象。
	public static void readObj() throws Exception
	{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
		Person p = (Person)ois.readObject();
		System.out.println(p);
		ois.close();
	}
}
import java.io.*;  
//创建Person类,实现Serializable接口.
//接口Serializable中没有方法,称之为标记接口.
class Person implements Serializable  
{  
	//自定义serialVersionUID版本号  
    public final static long serialVersionUID=42L;
    private String name;  
    private int age;  
    Person(String name,int age)  
    {  
        this.name=name;  
        this.age=age;  
    }  
    //复写toString方法  
    public String toString()  
    {  
        return name+":"+age;   
    }  
}
/*
注意:
1、静态成员不能被序列化。因为静态在方法区里面。
2、非静态成员要不被序列化,可以用关键字transient修饰,
保证非静态成员保存在堆内存中,不能存入文件中。
*/



四.管道流。

1.理解:
输入输出可以直接进行连接,通过结合多线程使用。
管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。
注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据的read方法会让线程等待。


2.分类:
PipedInputStream和PipedOutputStream。


3.演示:
(代码 PipedStreamDemo.java):
/*
先创建一个读和写的两个类,实现Runnable接口,
因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。
*/
import java.io.*;
class read implements Runnable
{
	private PipedInputStream in;
	read(PipedInputStream in)
	{
		this.in =in;
	}
	public void run()
	{
		try
		{
			byte[] buf = new byte[1024];
			int num = in.read(buf);
			System.out.println(new String(buf,0,num));
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道读取流失败");
		}
	}
}

class write implements Runnable
{
	private PipedOutputStream out;
	write(PipedOutputStream out)
	{
		this.out = out;
	}
	public void run()
	{
		try
		{
			out.write("piped".getBytes());
			out.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道输出流失败");
		}
	}
}
class PipedStreamDemo 
{
	public static void main(String[] args) 
	{
		try  
        {  
            //创建管道流对象,并关联.
            PipedInputStream in = new PipedInputStream(); 
            PipedOutputStream out = new PipedOutputStream();
            in.connect(out);//用connect()方法将两个流连接.
  
            //启动线程.
            new Thread(new read(in)).start();
            new Thread(new write(out)).start();
        }  
        catch (IOException e)
        {  
            throw new RuntimeException("管道流关联失败");
        }         

	}
}


五.RandomAccessFile类。

1.理解:
该类不算是IO体系中子类。而是直接继承自Object。
但是它是IO包中成员,因为它具备读和写功能。其实完成读写的原理就是内部封装了字节流。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
通过getFilePointer获取指针位置。通过seek改变指针位置。
通过构造函数可以看出,该类只能操作文件。而且操作文件还有模式:只读“r”、读写“rw”等四种模式。
且该对象的构造函数要操作的文件不存在,会自动创建;如果存在,则不会覆盖。
注意:实现随机访问文件,自身具备读写的方法。最好是数据有规律。


2.演示:
(代码 RandomAccessFile.java):
//使用RandomAccessFile进行读写操作.
import java.io.*;
class RandomAccessFileDemo 
{
	public static void main(String[] args) throws IOException
	{
		//writeFile();
		readFile();
	}
	public static void writeFile() throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.write("李四".getBytes());
		raf.writeInt(97);//按四个字节将int写入该文件.
		raf.write("王五".getBytes());
		raf.writeInt(99);
		raf.close();
	}
	public static void readFile() throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
		raf.seek(8*1);//调整对象中的指针。
		//raf.skipBytes(8);//跳过指定的字节数。
		byte[] buf = new byte[4];
		raf.read(buf);
		String name = new String(buf);
		System.out.println(name);
		int age = raf.readInt();
		System.out.println(age);
		raf.close();
	}
}



六.操作基本数据类型的流对象。

1.理解:
专门用于操作基本数据类型数据的对象。


2.分类:
DataInputStream和DataOutputStream。


3.特有方法:
byte型        readbyte()          writebyte()
int型         readInt()           writeInt()
boolean型     readBoolean()       writeBoolean()
double型      readDouble()        writeDouble()
String型      readUTF()           writeUTF()


例如:
DataOutputStream dos =  new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(256);
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
System.out.println(num);
dis.close();



七.内存为源和目的的操作。

1.操作字节数组的流对象。

1)、理解:
这个流对象不涉及底层资源调用,操作的都是内存中数组,所以不需要关闭资源。
用流的思想操作数组。

2)、分类:
ByteArrayInputStream和ByteArrayOutputStream。

3)、例子:
import java .io.*;  
class ByteArrayStreamDemo   
{  
    public static void main(String[] args)   
    {  
        //创建一个byte数组输入流,数据源  
        ByteArrayInputStream bais=new ByteArrayInputStream("ABCDEFG".getBytes());  
          
        //创建一个新的byte数组输出流,数据目的  
        ByteArrayOutputStream baos=new ByteArrayOutputStream();  
          
        int by=0;  
        while ((by=bais.read())!=-1)  
        {  
            //写入数据  
            baos.write(by);  
        }  
          
        //输出数据长度  
        System.out.println(baos.size());  
  
        //以字符串输出数据  
        System.out.println(baos.toString());  
  
        try  
        {  
            //因为这个方法用到了字节输出流,需要抛IO异常。
            //这也是字节数组流中唯一需要抛异常的方法。
            baos.writeTo(new FileOutputStream("writeTo.txt"));  
        }  
        catch (IOException e)  
        {  
            throw new RuntimeException("数据写入文件失败");  
        }  
    }  
}  


2.操作字符数组的流对象:
CharArrayReader和CharArrayWrite。


3.操作字符串的流对象:
StringReader和StringWriter。



八.字符编码。

1.理解:
字符流的出现为了方便操作字符。
更重要是的加入了编码转换。
通过子类转换流来完成。InputStreamReader和OutputStreamWriter。


2.常见的编码表:
GBK:中国的中文编码表升级,融合了更多的中文文字字符。打头的是两个高位为1的两个字节编码。为负数。
UTF-8:最多用三个字节表示一个字符的编码表,根据字符所占内存空间不同,分别用一个、两个、三个字节来编码。


3.编码和解码:
编码:字符串-->字节数组。String-->byte[]: .getBytes();
解码:字节数组-->字符串。byte[]-->String: new String();


4.编码和解码注意事项:
1)、如果编码失败,解码就没意义了。
2)、如果编码成功,解码出来的是乱码,则需对乱码通过再次编码,然后再通过正确的编码表解码。针对于IOS8859-1是通用的。
3)、如果用的是GBK编码,UTF-8解码,此时通过再次编码后解码的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。


5.特别注意:
对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,所以在文本文件中,如果单独写“联通”或者和满足UTF-8编码格式的字符一起保存时,记事本就会用UTF-8来进行解码动作,这样显示的就会是乱码。



练习:
用到集合与IO技术。
(代码 StudentInfoTest.java):
/* 
有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩), 
输入的格式:如:张三,30,40,60 
计算出总成绩,并把学生的信息和计算出的总分数高低顺序存放在磁盘文件“stuinfo.txt”中。 
*/
import java.io.*;
import java.util.*;
class StudentInfoTest
{
	public static void main(String[] args) throws IOException
	{
		Set<Student> stus = StudentInfoTool.getStudentInfo();
		StudentInfoTool.writeFile(stus);
	}
}
//定义一个学生类。
class Student implements Comparable<Student>
{
	private String name;
	private int yw,sx,yy;
	private int sum;
	Student(String name,int yw,int sx,int yy)
	{
		this.name = name;
		this.yw = yw;
		this.sx = sx;
		this.yy = yy;
		sum = yw+sx+yy;
	}
	public String getName()
	{
		return name;
	}
	public int getSum()
	{
		return sum;
	}
	public int compareTo(Student s)
	{
		int num = new Integer(s.sum).compareTo(new Integer(this.sum));
		if(num==0)
			return this.name.compareTo(s.name);
		return num;
	}
	public int hashCode()
	{
		return name.hashCode()+sum*33;
	}
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");
		Student s = (Student)obj;
		return this.name.equals(s.name) && this.sum==s.sum;
	}
	public String toString()
	{
		return "Student["+name+","+yw+","+sx+","+yy+"]";
	}
}
//定义操作学生的工具类。
class StudentInfoTool
{
	public static Set<Student> getStudentInfo() throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
	    Set<Student> stus = new TreeSet<Student>();
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			String[] in = line.split(",");
            stus.add(new Student(in[0],Integer.parseInt(in[1]),  
                                    Integer.parseInt(in[2]),  
                                    Integer.parseInt(in[3])));
		}
		bufr.close();
	    return stus;
	}
	public static void writeFile(Set<Student> stus) throws IOException
	{
		BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt"));
		for(Student stu : stus)
		{
			bufw.write(stu.toString()+"\t");
			bufw.write(stu.getSum()+"");
			bufw.newLine();
			bufw.flush();
		}
		bufw.close();
	}
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值