1、流的概念
在Java中,把这些不同类型的输入、输出源抽象为流(Stream),而其中输入或输出的数据则称为数据流(Data Stream),用统一的接口来表示,从而使程序设计简单明了。
java对流是用对对象方式处理
2、输入流InStream
把数据从外部通过流对象传输到内部
3、输出流OutStream
把数据从内部通过流对象传输到外部
在Java开发环境中,主要是由包java.io中提供的一系列的类和接口来实现输入/输出处理。标准输入/输出处理则是由包java.lang中提供的类来处理的,但这些类又都是从包java.io中的类继承而来。
I/O流的概述
在JDK1.1之前,java.io包中的流只有普通的字节流(以byte为基本处理单位的流),这种流对于以16位的Unicode码表示的字符流处理很不方便。
从JDK1.1开始, java.io包中加入了专门用于字符流处理的类(以Reader和Writer为基础派生的一系列类)。 另外,为了使对象的状态能够方便地永久保存下来, JDK1.1以后的java.io包中提供了以字节流为基础的用于对象的永久化保存状态的机制(通过实现ObjectInput和ObjectOutput接口)。
字节流
—基类
1、
Java中每一种字节流的基本功能依赖于基本类InputStream和OutputStream,它们是抽象类,不能直接使用。
属于InputStream类的方法有:
read():从流中读入数据
skip():跳过流中若干字节数
available():返回流中可用字节数
mark():在流中标记一个位置
reset():返回标记过得位置
markSupport():是否支持标记和复位操作
close():关闭流
2、
在InputStream类中,方法read()提供了三种从流中读数据的方法:
int read():从输入流中读一个字节,形成一个0~255之间的整数返回(是一个抽象方法)。
int read(byte b[]):读多个字节到数组中,填满整个数组。
int read(byte b[], int off, int len):从输入流中读取长度为len的数据,写入数组b中从索引off开始的位置,并返回读取得字节数。
对于这三个方法,若返回-1,表明流结束
3、
属于OutputStream类的方法有:
write(int b):将一个整数输出到流中(只输出低位字节,为抽象方法)
write(byte b[]):将字节数组中的数据输出到流中
write(byte b[], int off, int len):将数组b中从off指定的位置开始,长度为len的数据输出到流中
flush():刷空输出流,并将缓冲区中的数据强制送出
close():关闭流
Writer的方法:
write(String s), write(String s, int off, int len)
4、
在I/O处理中,最常见的就是对文件的操作。java.io包中所提供的文件操作类包括:
File:
FileDescriptor:
FilenameFilter:接口,主要用于实现文件名查找模式的匹配。
FileInputStream:
FileOutputStream:
RandomAccessFile:提供对本地文件系统中文件的随机访问支持。
5、在I/O处理中,最常见的就是对文件的操作。java.io包中所提供的文件操作类包括:
File:
FileDescriptor:
FilenameFilter:接口,主要用于实现文件名查找模式的匹配。
FileInputStream:
FileOutputStream:
RandomAccessFile:提供对本地文件系统中文件的随机访问支持
。
6、使用文件类File可以获取文件的各种信息。
File f=new File(“data\temp.dat”);
f.getName():返回文件名 temp.dat
f.getParent():返回文件所在目录名 data
f.getPath():返回文件路径 data\temp.dat
f.getAbsolutePath():返回绝对路径 …\data\temp.dat
f.exists():文件是否存在
f.canWrite(), f.canRead():文件是否可写、读
f.isFile(), f.isDirectory():是否为文件或目录
f.lastModified(), f.length(), f.delete():
文件的最后修改日期、长度;删除文件
f.mkdir(), f.list():创建一个目录;列出目录下所有的文件
由于文件的数据与内存的形式不一样
用一个字节表示一个字符,内部和外部不一样。以内存的形式存储,但是不可见。外部以字符的形式,可见的。
7、 FileInputStream类用来打开一个输入文件,若要打开的文件不存在,则会产生例外FileNotFoundException,这是一个非运行时例外,必须捕获或声明抛弃;
FileOutputStream类用来打开一个输出文件,若要打开的文件不存在,则会创建一个新的文件,否则原文件的内容会被新写入的内容所覆盖。
在进行文件的读/写操作时,会产生非运行时例外IOException,必须捕获或声明抛弃(其它的输入/输出流处理时也同样需要进行输入/输出例外处理)
8、文件流的建立:
File f1 = new File(“file1.txt”);
File f2 = new File(“file2.txt”);
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
FileOutputStream out=new FileOutputStream(“file3.txt”);
输入流的参数是用于指定输入的文件名,输出流的参数则是用于指定输出的文件名。
文本文件:
把内存的数据以字符的形式存放的叫文本文件
文本文件的优点:可见
文本文件的缺点:转换效率不高
二进制文件:
直接把内存中的数据存放在文件中
优点:转化效率高
缺点:不可见
标准字节输入流和输出流在java.lang.system
一般的流在java.io
java.io中提供类FilterInputStream和FilterOutputStream分别对其他输入/输出流进行特殊处理,它们在读/写数据的同时可以对数据进行特殊处理。另外还提供了同步机制,使得某一时刻只有一个线程可以访问一个输入/输出流。
类FilterInputStream和FilterOutputStream分别重写了父类InputStream和OutputStream的所有方法,同时,它们的子类也应该重写它们的方法以满足特定的需要。
要使用过滤流,首先必须把它连接到某个输入/输出流上,通常在构造方法的参数中指定所要连接的流:
FilterInputStream(InputStream in);
FilterOutputStream(OutputStream out);
字节流
–过滤流,Filter流
特点:一次以读写一个字节从文件输入,需要转换,效率低效
在字节流的基础上扩大叫Filter流,又叫过滤流,套件流
特点:自动保证线程安全,自有一条线程访问
例如 过滤流BufferInputStream
特点:一次读写若干个字节
FileInputStream in = new FileInputStream(“file1.txt”);
FileOutputStream out = new FileOutputStream (“file2.txt”);
BufferedInputStream bin = new BufferedInputStream(in,256)
BufferedOutputStream bout = new BufferedOutputStream(out,256);
int len;
byte bArray[]=new byte[256];
len=bin.read(bArray); //len中得到是长度, bArray中得到的是数据
对于BufferedOutputStream,只有缓冲区满时,才会将数据真正送到输出流,但可以使用flush()方法人为地将尚未填满的缓冲区中的数据送出。
文本文件包括回车换行字符
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) {
try {
FileInputStream fileInputStream=new FileInputStream(".//date1.txt");
BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
FileOutputStream fileOutputStream=new FileOutputStream(".//date2.txt");
BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(fileOutputStream);
byte[] array=new byte[512];
int c=bufferedInputStream.read(array,0,512);
while(c!=-1) {
System.out.println("c:"+c);
bufferedOutputStream.write(array, 0, c);
}
bufferedInputStream.close();
bufferedOutputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
数据流类DataInputStream和DataOutputStream的处理对象除了是字节或字节数组外,还可以实现对文件的不同数据类型的读写。它们分别实现了接口DataInput和DataOutput(与RandomAccessFile类似),提供了一种较为高级的数据输入输出方式:除了可处理字节和字节数组外,还可以处理int、float、boolean等基本数据类型,这些数据在文件中的表示方式和它们在内存中的一样,无须转换,如read(),
readInt(), readByte() …;write(), writeChar(),
writeBoolean()…。此外,还可以用readLine()方法读取一行信息
。
数据输出流可以是一个已经建立好的输入数据流对象,例如网络的连结,文件等。数据流可通过如下方式建立:
FileInputStream fis = new FileInputStream("file1.txt");
FileOutputStream fos = new FileOutputStream("file2.txt");
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
过滤流—数据流
特点:读写字符串,在读写过程可以编程
以字节的形式读入内存(网络编程使用date流)
创建一个 date输入流,就必须创建一个标准字节输入流
1、数据流可以处理二进制文件(BufferInputStream不能处理二进制文件 )
2、读到内存不需要转换
3、以什么二进制形式顺序写入内存,就以什么二进制形式读出
DateInputStream DateOutStream
特点:自动创建String 对象,按行读取
主要用在网络上:汉字编码,从网络中读取字节流,传送一次以字节字符,还可以进行编码
语言包java.lang中的System类管理标准输入/输出流和错误流。
System.in,从PrintStream中继承而来,用于从标准输入设备中获取输入数据(通常是键盘)。
System.out,从PrintStream中继承而来,把输出送到缺省的显示设备(通常是显示器)。
System.err,也是从PrintStream中继承而来,把错误信息送到缺省的显示设备(通常是显示器)。
每当main方法被执行时,就自动生成上述三个对象。
当主线程创建而时候,就会创建标准流
对象的持续性(persistence)
能够纪录自己的状态以便将来再生的能力,叫对象的持续性。
对象的串行化(Serialization)
对象通过写出描述自己状态的的数值来记录自己的过程叫串行化。串行化的主要任务是写出对象实例变量的数值,如果变量是另一个对象的引用,则引用的对象也要串行化。这个过程是递归的。
对象流
能够输入输出对象的流称为对象流。
可以将对象串行化后通过对象输入输出流写入文件或传送到其它地方
在java中,允许可串行化的对象在通过对象流进行传输。只有实现Serializable接口的类才能被串行化, Serializable接口中没有任何方法,当一个类声明实现Serializable接口时,只是表明该类加入对象串行化协议。
public 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 = departmernt;
}
}
import java.io.*;
public class TestStudent
{
public static void main(String[] args){
Student t = new Student(123, "张三", 23, "Java47班");
try{
FileOutputStream fout = new FileOutputStream("student.data");
ObjectOutputStream out = new ObjectOutputStream(fout);
out.writeObject(t);
out.close();
fout.close();
}catch(FileNotFoundException e){
System.out.println("File Not Found!");
}catch(IOException e){
System.out.println("I/O Error!");
}
}
}
I/O流概述
字节流
对象流
套件流
要串行化一个对象,必须与一定的对象输出/输入流联系起来,通过对象输出流将对象状态保存下来(将对象保存到文件中,或者通过网络传送到其他地方) ,再通过对象输入流将对象状态恢复
。
类ObjectOutputStream和ObjectInputStream分别继承了接口ObjectOutput和ObjectInput,将数据流功能扩展到可以读写对象,前者用writeObject()方法可以直接将对象保存到输出流中,而后者用readObject()方法可以直接从输入流中读取一个对象。
对象的形态进行保存叫对象的串行,拿到对象的形态进行创建对象叫对象的反序列化
1、首先这个对象的类进入串行化序列 class Student implements Serializable
2、创建该类的对象,并对属性进行赋值 (该类具有状态)
3、传送(创建一个文件字节输出流,嵌入到对象输出流)
4、完成输出,Out.writeObject(t);
创建对象的方式
1、通过new
2、反射
3、反序列
4、克隆
首先创建对象输入流,文件字节输入流(存放二进制文件)
对象输入流所指的对象文件输入流
创建文件对象状态的文件输入流
public 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 = departmernt;
}
}
import java.io.*;
public class TestStudent1
{
public static void main(String[] args){
try{
FileInputStream fin = new FileInputStream("student.data");
ObjectInputStream in = new ObjectInputStream(fin);
Student t = (Student)in.readObject();
System.out.println("Student : " + t);
in.close();
fin.close();
}catch(FileNotFoundException e){
System.out.println("File Not Found!");
}catch(ClassNotFoundException e){
System.out.println("ClassNotFoundException!");
}catch(IOException e){
System.out.println("I/O Error!");
}catch(Exception e){
System.out.println("I/O Error!");
}
}
}
串行化只能保存对象的非静态成员变量,而不能保存任何成员方法和静态成员变量,并且保存的只是变量的值,对于变量的任何修饰符都不能保存。
对于某些类型的对象,其状态是瞬时的,这样的对象是无法保存其状态的,如Thread对象或流对象。对于这样的成员变量,必须用transient关键字标明,否则编译器将报错。任何用transient关键字标明的成员变量,都不会被保存。
另外,串行化可能涉及将对象存放到磁盘上或在网络上发送数据,这时会产生安全问题。对于一些需要保密的数据,不应保存在永久介质中(或者不应简单地不加处理地保存下来),为了保证安全,应在这些变量前加上transient关键字。