------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();
}
}