流动方向:一般分为输入流(InputStream:System.in)和输出流 (PrintStream:System.out)两类。程序可以用输出流从文件中读取数据。而针对键盘只有输入流,针对屏幕只有输出流。
读取类型: 一般分为字节流(InputStream:System.in)和字符流 (字符流对象:new InputStreamReader(System.in))。字节流是从InputStream和OutputStream派生出来的一个系列类,它以字节(byte)为基本处理单位。它们的继承关系如下(缩进的层次表示继承关系):
java.io.InputStream
java.io.FileInputStream
java.io.PipedInputStream
java.io.ObjectInputStream
java.io.ByteArrayInputStream
java.io.SequenceInputStream
java.io.FilterInputStream
java.io.DataInputStream
java.io.BufferedInputStream
java.io.PushbackInputStream
java.io.OutputStream
发生源头: 分为节点流(直接操作目标设备对应的流,如文件流,标准输入输出流)和过滤流类(继承带有关键字Filter的流用于包装操作节点流,方便读写各种类型的数据)
(1)AudioInputStream :音频输入流是具有指定音频格式和长度的输入流。
e.g. 获取音频输入流的方式:
AudioInputStream a = NULL;
a = AudioSystem.getAudioInputStream(new File(fileName));//获取音频输入流
(2)ByteArrayInputStream&ByteArrayOutputStream :A ByteArrayInputStream包含一个内部缓冲区,其中包含可以从流中读取的字节。 内部计数器跟踪read方法要提供的下一个字节。
关闭ByteArrayInputStream没有任何效果。 在关闭流之后,可以调用此类中的方法,而不生成IOException 。
该类实现了将数据写入字节数组的输出流。 当数据写入缓冲区时,缓冲区会自动增长。 数据可以使用toByteArray()和toString() 。
关闭ByteArrayOutputStream没有任何效果。 该流中的方法可以在流关闭后调用,而不生成IOException 。
e.g.
import java.io.*;
public class ByteArrayStream {
public static void main(String[] args){
byte[] b = "hello".getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(b);
int n =0;
while((n = bais.read())!=-1){
System.out.print((char)n); //hello
}
}
}
import java.io.*;
public class ByteArrayStream {
public static void main(String[] args){
byte[] b = "hello".getBytes();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(b, 0, b.length);
System.out.println(new String(baos.toByteArray()));
}
}
e.g. https://www.runoob.com/java/java-bytearrayinputstream.html
(3)FileInputStream(FileReader)& FileOutputStream(FileWriter) :
A FileInputStream从文件系统中的文件获取输入字节。 什么文件可用取决于主机环境。
FileInputStream用于读取诸如图像数据的原始字节流。 要阅读字符串,请考虑使用FileReader 。
文件输出流是用于将数据写入到输出流File或一个FileDescriptor 。 文件是否可用或可能被创建取决于底层平台。 特别是某些平台允许一次只能打开一个文件来写入一个FileOutputStream (或其他文件写入对象)。 在这种情况下,如果所涉及的文件已经打开,则此类中的构造函数将失败。
FileOutputStream用于写入诸如图像数据的原始字节流。 对于写入字符流,请考虑使用FileWriter 。
e.g.
package chap14_2;
import java.io.*;
public class OpenFile {
public static void main(String args[]) throws IOException{
try{
//创建文件输入流对象
FileInputStream rf = new FileInputStream("OpenFile.java");
int n=512,c=0;
byte buffer[] = new byte[n];
while ((c=rf.read(buffer,0,n))!=-1 ){
//读取输入流
System.out.print(new String(buffer,0,c));
}
rf.close(); //关闭输入流
}
catch (FileNotFoundException ffe){
System.out.println(ffe);}
catch (IOException ioe){
System.out.println(ioe);
}
}
}
import java.io.*;
public class Write1 {
public static void main(String args[]){
try{
System.out.print("Input: ");
int count,n=512;
byte buffer[] = new byte[n];
count = System.in.read(buffer); //读取标准输入流
FileOutputStream wf = new FileOutputStream("Write1.txt");
//创建文件输出流对象
wf.write(buffer,0,count); //写入输出流
wf.close(); //关闭输出流
System.out.println("Save to Write1.txt!");
}
catch (FileNotFoundException ffe){
System.out.println(ffe);}
catch (IOException ioe){
System.out.println(ioe);} }
}
(4)FilterInputStream(FilterReader)&FilterOutputStream(FilterWriter) :
FilterInputStream包含一些其他输入流,它用作其基本的数据源,可能会沿途转换数据或提供附加功能。 FilterInputStream本身简单地覆盖了所有InputStream的方法, InputStream版本将所有请求传递给包含的输入流。 FilterInputStream的FilterInputStream可以进一步覆盖这些方法中的一些,并且还可以提供附加的方法和领域。
这个类是过滤输出流的所有类的超类。 这些流位于已经存在的输出流( 底层输出流) 之上 ,它使用它作为数据的基本接收器,但是可能沿着数据方向转换或提供附加功能。
类FilterOutputStream本身就简单地覆盖了所有OutputStream的方法, OutputStream版本将所有请求传递给底层输出流。 FilterOutputStream的FilterOutputStream可以进一步覆盖这些方法中的一些,并提供其他方法和字段。
注:不能访问 FilterInputStream 的构造方法,它是受保护的构造方法,但可以使用它的子类FilterInputStream filter=new BufferedInputStream(fis);
(5)ObjectInputStream&ObjectOutputStream :
序列化&反序列化 :将实现了Seriallizable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
使用ObjectInputStream类和ObjectOutputStream类
e.g.
import java.io.*;
public class Student implements Serializable {
//序列化
int number=1;
String name;
Student(int number,String n1) {
this.number = number;
this.name = n1;
}
public static void main(String arg[]) {
String fname = "Student.obj"; //文件名
Student s1 = new Student(1,"Wang");
s1.save(fname);
s1.display(fname);
}
void save(String fname) {
try{
FileOutputStream fout = new FileOutputStream(fname);
ObjectOutputStream out = new ObjectOutputStream(fout);
out.writeObject(this); //对象序列化
out.close();
}
catch (FileNotFoundException fe){
}
catch (IOException ioe){
}
}
void display(String fname) {
try{
FileInputStream fin = new FileInputStream(fname);
ObjectInputStream in = new ObjectInputStream(fin);
Student u1 = (Student)in.readObject(); //对象反序列化
System.out.println(u1.getClass().getName()+" "+
u1.getClass().getInterfaces()[0]);
System.out.println(" "+u1.number+" "+u1.name);
in.close();
}
catch (FileNotFoundException fe){
}
catch (IOException ioe){
}
catch (ClassNotFoundException ioe) {
}
}
(6)PipedInputStream(PipedReader)&PipedOutputStream(PipedWriter) :
管道输入流应连接到管道输出流; 管道输入流然后提供写入管道输出流的任何数据字节。 典型地,数据被从一个读PipedInputStream对象由一个线程并且数据被写入到对应的PipedOutputStream通过一些其它线程。 不建议尝试从单个线程使用这两个对象,因为它可能会使线程死锁。 管道输入流包含一个缓冲区,在读取操作中将读取操作与限制内的操作相分离。 的管道被认为是broken如果正在提供的数据字节到连接的管道输出流中的线程不再存活。
管道输出流可以连接到管道输入流以创建通信管道。 管道输出流是管道的发送端。 典型地,数据被写入到一个PipedOutputStream由一个线程对象和数据被从连接读取PipedInputStream通过一些其它线程。 不建议尝试从单个线程使用这两个对象,因为它可能会使线程死锁。 管被说成是broken如果从连接读取数据字节的螺纹管道输入流不再存活。
e.g.
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipedStream {
public static void main(String[] args) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
new Thread(new Input(in)).start();
new Thread(new Output(out)).start();
}
}
class Input implements Runnable{
private PipedInputStream in;
public Input(PipedInputStream in) {
this.in = in;
}
public void run() {
byte []buf = new byte[1024];
int len;
try {
len = in.read(buf);
String s = new String(buf,0,len);
System.out.println("in "+s);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
public Output(PipedOutputStream out)
{
this.out = out;
}
public void run() {
try {
out.write("hello".getBytes());
}
catch (IOException e) {
e.printStackTrace();
}
}
}
(7)PrintStream(PrintWriter) :
可以向该字符流中写入Java基本数据类型,用于包装输出字符流类对象
局限性:没有对应的输入流类用于恢复写入的Java基本类型数据
import java.io.*;
public class PrintWrit {
public static void main(String[] args)throws Exception{
PrintWriter out = new PrintWriter(new BufferedWriter(new
FileWriter("foo.txt")));
//等价于PrintWriter out = new PrintWriter(“foo.txt”); //JDK5引入,简化编码,仍然具有缓存功能
out.println(“hello”); //写入字符串
out.println(3); //写入整型
out.close(); //关闭流,系统自动将缓冲区内容flush
}
}
(8)DataInputStream&DataOutputStream :
可从字节流中写入、读取Java基本数据类型,不依赖于机器的具体数据类型,方便存储和恢复数据
import java.io.*;
public class DataStream {
public static void main(String[] args)throws Exception{
try {
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new
FileOutputStream("test.txt")));
dos.writeInt(3);//写入整型
dos.writeDouble(3.14);//写入浮点型
dos.writeUTF(“hello”);//写入字符串
dos.close();
DataInputStream dis = new DataInputStream(new BufferedInputStream(new
FileInputStream("test.txt")));
System.out.println(dis.readInt()); //读取整型,输出3
System.out.println(dis.readDouble()); //读取浮点型,输出3.14
System.out.println(dis.readUTF()); //读取字符串,输出hello
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
(9)StringBufferInputStream :已弃用
(10)BufferedInputStream(BufferedReader)&BufferedOutputStream(BufferedWriter) : 缓存作用,用于装配文件磁盘、网络设备、终端等读写开销大的节点流,提高读写性能
import java.io.*;
public class inDataSortMaxMinIn {
public static void main(String args[]) {
try{
BufferedReader keyin = new BufferedReader(new
InputStreamReader(System.in));
String c1;
int i=0;
int[] e = new int[10];
while(i<10){
try{
c1 = keyin.readLine();
e[i] = Integer.parseInt(c1);
i++;
}
catch(NumberFormatException ee){
System.out.println("请输入正确的数字!");
}
}
}
catch(Exception e){
System.out.println("系统有错误");
}
}
}
(11)LineNumberInputStream(LineNumberReader) :这个类是一个输入流过滤器,它提供了跟踪当前行号的附加功能。行是以回车符(’\r’)、换行符(’\n’)或紧跟换行符的回车字符结尾的字节序列。在所有三种情况下,行尾字符都作为一个换行符返回。行号从0开始,当读取返回换行符时,行号递增1。
(12)PushbackInputStream :回退流
(13)SequenceInputStream :A SequenceInputStream表示其他输入流的逻辑级联。 它从一个有序的输入流集合开始,从第一个读取到文件的结尾,然后从第二个文件读取,依此类推,直到最后一个输入流达到文件的结尾。
输入字节流转为字符流需要用到inputstreamReader的构造方法:
InputStreamReader(InputStream in)
输出字符流转为字节流用到OutputStreamWriter或PrintWriter的构造方法:
OutputStreamWriter(OutputStream out)
PrintWriter(OutputStream out)
(1)BufferedInputStream&BufferedOutputStream, 缓存作用,用于装配文件磁盘、网络设备、终端等读写开销大的节点流,提高读写性能
import java.io.*;
public class inDataSortMaxMinIn {
public static void main(String args[]) {
try{
BufferedReader keyin = new BufferedReader(new
InputStreamReader(System.in));
String c1;
int i=0;
int[] e = new int[10];
while(i<10){
try{
c1 = keyin.readLine();
e[i] = Integer.parseInt(c1);
i++;
}
catch(NumberFormatException ee){
System.out.println("请输入正确的数字!");
}
}
}
catch(Exception e){
System.out.println("系统有错误");
}}}
(2)DataInputStream和DataOutputStream
可从字节流中写入、读取Java基本数据类型,不依赖于机器的具体数据类型,方便存储和恢复数据
import java.io.*;
public class DataStream {
public static void main(String[] args)throws Exception{
try {
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new
FileOutputStream("test.txt")));
dos.writeInt(3);//写入整型
dos.writeDouble(3.14);//写入浮点型
dos.writeUTF(“hello”);//写入字符串
dos.close();
DataInputStream dis = new DataInputStream(new BufferedInputStream(new
FileInputStream("test.txt")));
System.out.println(dis.readInt()); //读取整型,输出3
System.out.println(dis.readDouble()); //读取浮点型,输出3.14
System.out.println(dis.readUTF()); //读取字符串,输出hello
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
(3)PrintWriter
可以向该字符流中写入Java基本数据类型,用于包装输出字符流类对象
局限性:没有对应的输入流类用于恢复写入的Java基本类型数据
import java.io.*;
public class PrintWrit {
public static void main(String[] args)throws Exception{
PrintWriter out = new PrintWriter(new BufferedWriter(new
FileWriter("foo.txt")));
//等价于PrintWriter out = new PrintWriter(“foo.txt”); //JDK5引入,简化编码,仍然具有缓存功能
out.println(“hello”); //写入字符串
out.println(3); //写入整型
out.close(); //关闭流,系统自动将缓冲区内容flush
}
}
序列化&反序列化 :将实现了Seriallizable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
使用ObjectInputStream类和ObjectOutputStream类
e.g.
import java.io.*;
public class Student implements Serializable {
//序列化
int number=1;
String name;
Student(int number,String n1) {
this.number = number;
this.name = n1;
}
public static void main(String arg[]) {
String fname = "Student.obj"; //文件名
Student s1 = new Student(1,"Wang");
s1.save(fname);
s1.display(fname);
}
void save(String fname) {
try{
FileOutputStream fout = new FileOutputStream(fname);
ObjectOutputStream out = new ObjectOutputStream(fout);
out.writeObject(this); //对象序列化
out.close();
}
catch (FileNotFoundException fe){
}
catch (IOException ioe){
}
}
void display(String fname) {
try{
FileInputStream fin = new FileInputStream(fname);
ObjectInputStream in = new ObjectInputStream(fin);
Student u1 = (Student)in.readObject(); //对象反序列化
System.out.println(u1.getClass().getName()+" "+
u1.getClass().getInterfaces()[0]);
System.out.println(" "+u1.number+" "+u1.name);
in.close();
}
catch (FileNotFoundException fe){
}
catch (IOException ioe){
}
catch (ClassNotFoundException ioe) {
}
}
File类不仅指系统中的文件,也指目录,因为目录也是特殊的文件。它的主要方法类型和说明见表。
类型 | 名称 | 说明 |
---|---|---|
构造方法 | public File(String pathname) | 根据字符串路径建立文件对象 |
public File(File parent,String child) | 根据父路径对象和子路径字符串建立文件对象 | |
public File(String parent parent,String child) | 根据父路径字符串和子路径字符串建立文件对象 | |
文件名的处理 | String getName(); | 得到一个文件的名称(不包括路径) |
String getPath(); | 得到一个文件的路径名 | |
String getAbsolutePath(); | 得到一个文件的绝对路径名 | |
String getParent(); | 得到一个文件的上一级目录名 | |
String renameTo(File newName); | 将当前文件更名为参数File所代表路径下的文件 | |
文件属性测试 | boolean exists() | 测试当前File对象所代表的文件是否存在 |
boolean canWrite() | 测试当前File对象所代表的文件是否可写 | |
boolean canRead() | 测试当前File对象所代表的文件是否可读 | |
boolean isFile() | 测试当前File对象是否是文件 | |
boolean isDirectory() | 测试当前File对象是否是目录 | |
文件信息和文件删除 | long lastModified() | 得到文件最近一次修改时间 |
long length() | 得到文件的长度,以字节为单位 | |
boolean delete() | 删除当前文件 | |
目录操作 | boolean mkdir() | 生成当前File对象所代表的目录 |
String list() | 列出当前目录下的文件 |
FileInputStream 以字节流的形式顺序读文件
FileReader以字符流的形式顺序读文件
FileOutputStream 以字节流的形式顺序写文件
FileWriter 以字符流的形式顺序写文件
RandomAccessFile 提供对文件的随机访问支持