字节流类专用于处理字节,即以字节为输入输出基本单位的IO类
字符流类专用于处理字符,即以字符为输入输出基本单位的IO类
字节流类包装类用于包装字节流类对象
字符流类包装类用于包装字符流类对象
包装类应用于某些特定的场合需求,使需求更容易的得到实现
字节流类
InputStream与OutputStream类
InputStream和OutputStream类分别是所有字节输入流类和字节输出流类的抽象基类,程序中实际使用的是它们的各种子类对象。
InputStream类
程序可以从中连续读取字节的对象叫输入流,其基本方法如下:
int read() // 返回下一个字节的×××(int)表示,其实它每次只从数据源中读取一个字节的内
容,而将所读的内容放入(int) 4个字节的最低8位中,其余3个字节不变。
int read(byte[] b) //从输入流中最多读取b.length个字节存储在数组 b 中 ,并返回实际读
入的字节数
int read(byte[] b, int off, int len) //将输入流中最多 len 个数据字节读入到 byte 数组脚标
从off开始的以后的空间中
long skip(long n) //跳过和丢弃此输入流中数据的 n 个字节,并返回实际跳过的字节
数 (包装类)
int available() //返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或
跳过)估计字节数的
void mark(int readlimit) //在此输入流中标记当前的位置 ,允许最多再读入readlimit个字节
markSupported() //测试此输入流是否支持 mark 和 reset 方法
reset() //将此流重新定位到最后一次对此输入流调用 mark 方法时的位置
close() //关闭此输入流并释放与该流关联的所有系统资源
不是所有的子类都会支持InputStream中定义的某些方法如:skip ,mark, reset等,这些方法只对某些子类有用。
OutputStream类
程序可以向其中写入字节的对象叫输出流,其基本方法如下:
void write(byte[] b) //将 b.length 个字节从指定的 byte 数组写入此输出流 ,会自动调
用flush()方法
void write(int b) //将指定的字节写入此输出流 ,不会自动调用flush方法
void write(byte[] b, int off, int len) //将指定 byte 数组中从偏移量 off 开始的 len 个字节
写入此输出流
void flush() //刷新此输出流并强制写出所有缓冲的输出字节
void close() //关闭此输出流并释放与此流有关的所有系统资源
FileInputStream与FileOutputStream
它们分别是InputStream与OutputStream的子类,属于字节流类,用来创建磁盘文件的输入和输出流字节流对象,通过它们的构造函数来指定文件路征和文件名
创建FileInputStream实例对象时,指定的文件必须是存在和可读的。对同一个磁盘文件创建FileInputStream对象的两种方式:
(1)FileInputStream inOne = new FileInputStream("1.txt");
(2)File f = new File("1.txt");
FileInputStream inTwo = new FileInputStream(f);
创建FileOutStream实例对象时,也同样有这两种方式,但可以为其指定一个磁盘上还不存在的文件名,系统会为其自动生成一个对应的文件,如指定的文件已经存在,这个文件的原内容将被覆盖清除。
实例代码:
package test.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class TestFileInS{
public static void main(String[] args) {
try {
FileOutputStream out = new FileOutputStream("1.txt");
out.write("nice to meet you!".getBytes());//将转换的字节数组写入//1.txt
out.close();
byte[] buf = new byte[1024];
File f =new File("1.txt");
FileInputStream in = new FileInputStream(f);
int len = in.read(buf);
in.close();
System.out.println(new String(buf,0,len));
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:
nice to meet you!
PipedInputStream与PipedOutputStream类
它们分别是InputStream和OutputStream类的子类,属于字节流类,一个PipedInputStream对象必须和一个PipedOutputStream对象进行连接而产生一个通信管道,PipedOutputStream可以向管道中写入数据,PipedInputStream可以从管道中读取PipedOutputStream写入的数据,这两个类主要用来完成线程间的通信,一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据。
实例代码:
package test.io;
import java.io.*;
public class PipStreamTest
{
public static void main(String args[])
{
try
{
Sender t1=new Sender();
Receiver t2=new Receiver();
PipedOutputStream out = t1.getOutputStream();
PipedInputStream in = t2.getInputStream();
out.connect(in);
t1.start();
t2.start();
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
}
}
class Sender extends Thread
{
private PipedOutputStream out=new PipedOutputStream();
public PipedOutputStream getOutputStream()
{
return out;
}
public void run()
{
String s=new String("hello,receiver,how are you!");
try
{
out.write(s.getBytes());//因为out是字节流类,所以需要将s转换成字节数组
out.close();
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
}
}
class Receiver extends Thread
{
private PipedInputStream in=new PipedInputStream();
public PipedInputStream getInputStream()
{
return in;
}
public void run()
{
String s=null;
byte [] buf = new byte[1024];
try
{
int len =in.read(buf);
s = new String(buf,0,len);
System.out.println(
"the following message comes from sender:\n"+s);
in.close();
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
}
}
PipedWriter类和PipedReader类。(用于字符管道通信)
使用管道流类,可以实现各个程序模块之间的松耦合通信。
字节流类包装类
BufferedInputStream与BufferedInputStream
用于包装字节流类对象,属字节流类包装类
缓冲流为I/O流增加了内存缓冲区,增加缓冲区有两个基本的目的:
1、允许java程序一次不只操作一个字节,这样提高了程序的性能。
2、由于有了缓冲区,使得在流上执行skip、mark和reset方法都成为可能。
BufferedInputStream和BufferedOutputStream是java提供的两个缓冲区包装类,不管底层系统是否使用了缓冲区,这两个类在自己的实例对象中创建缓冲区。
BufferedInputStreamr的两个构造函数:
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int size)
第一个构造函数创建了一个带有32字节缓冲区的缓冲流,第二种形式的构造函数按指定的大小来创建缓冲区
BufferedOutputStream的两个构造函数:
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int size)
DataInputStream与DataOutputStream类
用于包装字节流类对象,属字节流类包装类
DataOutputStream类提供了三个写入字符的方法:
public final void writeBytes(String s)
public final void writeChars(String s)
public final void writeUTF(String s)
DataInputStream类中有一个readUTF方法,并没有“readBytes”和“readChars”方法。 (原因是读取编码不明确,只有writeUTF方法向目标设备中写入了字符串的长度,所以我们也只能准确地读回这个方法写入的字符串)
编程实例:分别使用DataOutputStream类的writeUTF、writeBytes和
writeChars方法,比较这几个方法的差异。程序中所使用的流栈如下:
关闭流栈中的最上层的流对象,将会自动关闭流栈中的所有底层流对象。
实例代码:
package test.io;
import java.io.*;
public class DataStreamTest {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("count.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF("ab 中国");
dos.writeBytes("ab 中国");
dos.writeChars("ab 中国");
dos.close();
FileInputStream fis = new FileInputStream("count.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
System.out.println(dis.readUTF());//之后指针定位到了第二个a上
byte[] buf = new byte[1024];
int len = dis.read(buf);
System.out.println(new String(buf,0,len));
dis.close();
}
}
结果:
ab 中国
ab -?a b N-v?
PrintStream类
PrintStream类提供了一系列的print和println方法,可以将基本数据类型的数据格式化成字符串输出。
格式化输出:例如,97被格式化输出的实际字节数据为0X39和0X37。 如将97打印到一个文件中该print方法会把’9’和’7’这两个字符对应的ASCII码即0X39和0X37两个字节写入到文件中,在记事本程序中显示’9’和’7’两个字符。如果我们用write方法把97这个整数写到一个文件中,会把97作为ASCII值写入文件中,正好是字符’a’的ASCII码,所以在记事本程序中显示为一个字符’a’.
PrintStream的3个构造函数:
PrintStream(OutputStrean out)
PrintStream(OutputStream out,boolean outoflush)
PrintStream(OutputStream out,noolean outoflush,String encoding)
autoflush控制在java中遇到换行符\n时是否自动清空缓冲区
与PrintStream对应的PrintWriter类,即使遇到了文本换行符(\n),PrintWriter类也不会自动清空缓冲区。只在设置了 autoflush模式下使用了println方法后才自动清空缓冲区。
PrintWrite的println方法能根据操作系统的不同而生成相应的文本换行标识符。在Windows下的文本换行标识符是“\r\n”,而Linux下的文本换行标识符是"\n";
ObjectInputStream与ObjectOutputStream类
用于包装字节流类对象,属字节流类包装类
ObjectInputStream和ObjectOutputStream这两个包装类,用于从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输出流。
ObjectInputStream与ObjectOutputStream类所读写的对象必须实现了Serializable接口。对象中的transient(临时变量)和static类型的成员变量不会被读取和写入。
实例代码:
package test.io;
import java.io.*;
public class serialization
{
public static void main(String args[])
throws IOException,ClassNotFoundException
{
Student stu=new Student(19,"zhangli",50,"shengwu");
FileOutputStream fos=new FileOutputStream("2.txt");
ObjectOutputStream os=new ObjectOutputStream(fos);
try
{
os.writeObject(stu);
os.close();
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
stu=null;
FileInputStream fi=new FileInputStream("2.txt");
ObjectInputStream si=new ObjectInputStream(fi);
try
{
stu=(Student)si.readObject();
si.close();
}catch(IOException e)
{
System.out.println(e.getMessage());
}
System.out.println("ID is:"+stu.id);
System.out.println("name is:"+stu.name);
System.out.println("age is:"+stu.age);
System.out.println("department is:"+stu.department);
}
}
class Student implements Serializable
{
int id;
String name;
int age;
String department;
public Student(int id,String name,int age,String department)
{
this.id=id;
this.name=name;
this.age=age;
this.department=department;
}
}
结果:
ID is:19
name is:zhangli
age is:50
department is:shengwu
字符流类
Reader与Writer类
Reader 类和Writer类分别是所有字符输入流类和字符输出流类的抽象基类,大体的功能和
InputStream、OutputStream两个类相同,但不是它们的替代者,只是在处理字符串时简化了我们的编程。程序中实际使用的是它们的各种子类对象
FileReader类与FileWriter类
它们是Reader类与Writer类的子类。属于字符流类,用来创建磁盘文件的输入和输出字符流对象,FileWriter类用于写入字符流 FileOutputStream 要写入的原始字节流。FileWriter中有方法Writer(String str);用于将字符串直接写入文件。
实例代码:
package test.io;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileStream{
public static void main(String[] args) {
try {
FileWriter out = new FileWriter("1.txt");
out.write("nice to meet you");//写入字符串
out.close();//方法内实际包含flush方法
char[] buf = new char[1024];
FileReader in = new FileReader("1.txt");
int len = in.read(buf);
System.out.println(new String(buf,0,len));
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符流类的包装类
BufferedWriter和BufferedReader类
与BufferedInputStream和BufferedOutputStream有类似功能,只是BufferedWriter和BufferedReader类用于包装字符流类对象,属字符流类包装类 BufferedWriter类有 readLine()方法,可一次从自身的缓冲区中读取一行文本,BufferedWriter类有write(String str)方法,用于向底层输出流输入字符串,newLine()方法用于换行。
PrintWriter类
同PrintStream类对应。其区别已在上面论述过。
字节流与字符流的转换
BufferedReader in = new BufferedReader(new InputStreamReader(System.in))读取键盘上输入的一行字符。
InputStreamReader和OutputStreamWriter,是用于将字节流转换成字符流来读写的两个类,InputStreamReader可以将一个字节流中的字节解码成字符后读取,OutputStreamWriter将字符编码成字节后写入到一个字节流中。
InputStreanReader的两个主要的构造函数:
InputStreamRead(InputStream in)
InputStreamRead(InputStream in,String CharsetName);
OutputStreanWriter的两个主要的构造函数:
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out,String CharsetName);
避免频繁地在字符与字节间进行转换,最好不要直接使用InputStreamReader和OutputStreamWriter类来读写数据,应尽量使用BufferedWrite类包装OutputStreamWriter类,用于BufferderReader类包装InputStreamrader.
如:
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String str=in.readLine();
字节输入流类
字节输出流类 字符输入流类 字符输出流类
Decorator设计模式
在程序中用一个对象(the Decorators)1包装另外的一个对象,这是一种被称为Decorator的设计模式。
如果要设计自己的IO包装类,这个类需要继承以FilterXXX命名的类,设计一个对输入输出包装类:
Exception类从Throwable类继承的三个PrintStackTrace方法的定义如下:
public void printStackTrace();
public void printStackTrace(PrintStream s)
public void printStackTrace(PrintWriter s)
实例:(将异常信息储存到字符串中)
package test.io;
import java.io.PrintWriter;
import java.io.StringWriter;
public class TestPrintWriter {
public static void main(String[] args) {
try{
throw new Exception("test");
}catch(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw =new PrintWriter(sw);
e.printStackTrace(pw);
System.out.println(e.getMessage());
System.out.println(sw.toString());
}
}
}
java程序与其它进程的数据通信
在java程序可以用Process类的实例对象来表示子进程,子进程的标准输入和输出不再连接到键盘和显示器,而是以管道流的形式连接到父进程的一个输出流和输入流对象上。(我把下图作为分析下面实例程序关系的流程图)
调用Process类的getOutputStream和getInputStream方法可以获得连接到子进程的父进程的输出流和输入流对象。子进程从标准输入读取的内容是父进程通过输出流对象写入管道1的数据,子进程写入标准输出的数据通过管道2传送到了父进程的输入流对象中,父进程从这个输入流对象中读取到得内容就是子进程写入到标准输出的数据。
编程实例:在TestInOut类中启动java.exe命令执行另外一个MyTest类,TestInOut和MyTest通过进程间的管道相互传递数据。
记住调用Process类的destroy方法结束子进程的运行。
package test.io;
import java.io.*;
public class TestInOut implements Runnable
{
Process p=null;
public TestInOut()
{
try
{
p=Runtime.getRuntime().exec("java MyTest");
new Thread(this).start(); /* 线程Thread-0不断的从通道2中读取数据并打印在屏幕上*/
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
public void send()
{
try
{
OutputStream ops=p.getOutputStream();
while(true)
{
ops.write("help\r\n".getBytes());
}
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
public static void main(String [] args)
{
TestInOut tio=new TestInOut ();
tio.send(); //main线程向管道1中写入数据
}
public void run()
{
try
{
InputStream in = p.getInputStream(); //in的数据源为通道2
BufferedReader bfr=new BufferedReader(
new InputStreamReader(in));
while(true)
{
String strLine=bfr.readLine();
System.out.println(strLine);
}
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}
class MyTest
{
public static void main(String [] args) throws IOException
{
BufferedReader bfr=new BufferedReader(new InputStreamReader(System.in)); //System.in不再对应键盘而是对应通道1
while(true)
{
System.out.println("hi:"+bfr.readLine()); //此处的println是将从管道1中读取的内容打印到通道2中
}
}
}