1、流的概念:Java对流是用对象方式处理的,具体的说,流对象就是数据传输的管道。
2、输入流和输出流
内部—可以是内存,可以是数组、变量、对象等
外部:可以是文件、键盘、网络等
流一般分为输入流和输出流两类,但这种划分不是绝对的。例如,一个文件,在读取它的数据时,它就是输入流;而在保存数据到文件时,它就是一个输出流
4、文本文件和二进制文件
优点:可见
缺点:由于文件的数据存储方式和内存不同需要转换,影响效率
优点:由于二进制文件的数据存储方式和内存相同不需要转换,执行效率较高
缺点:不可见
1、流对象的种类:从整体可以划分为字节流和字符流
2、基类
Java中每一个字节流的基本功能依赖于基本类 InputStream 和 OutputStream ,它们都是抽象类,不能直接使用。
read():从流中读入数据
skip():跳过流中若干字节数
available() : 返回流中可用字节数
mark() : 在流中标记一个位置
reset() : 返回标记过的位置
markSupport() : 是否支持标记和复位操作
close() : 关闭流
write() : 将数据输出到流中
flush(): 刷空输出流,并将缓冲区中的数据强制送出
close():关闭流
1、使用代码:
从file1.text读取内容写入到file2.text
import java.io.*;
public class Filestream
{
public static void main(String args[])
{
try
{
File inFile=new File("file1.txt");
File outFile=new File("file2.txt");
FileInputStream fis=new FileInputStream(inFile);
FileOutputStream fos=new FileOutputStream(outFile);
int c;
while((c=fis.read())!=-1)
{System.err.println(c);
fos.write(c);
}
fis.close();
fos.close();
}catch(FileNotFoundException e) {//InputStream用来打开一个输入文件,若要打开文件不存在,会产生异常
System.out.println("FileStreamsTest: "+e);
}catch(IOException e) {//在进行读/写操作时可能会有IO异常发生,必须捕获
System.err.println("FileStreamsTest: "+e);
}
}
}
File inFile=new File(“file1.txt”);
创建文件对象
FileInputStream fis=new FileInputStream(inFile);
创建文件输入流,用来打开指定的输入文件。当输入文件不存在时会报异常
FileOutputStream fos=new FileOutputStream(outFile);
创建文件输出流,用来打开指定的输出文件。当输出文件不存在时,会新建这个名字的输出文件
fis.read()
读取输入文件的数据
fos.write©;
将数据写入到文件中
2、随机流
对于InputStream和OutputStream来说,它们的实例都是顺序访问流,即只能进行顺序读/写。而类RandomAccessFile则允许对文件内容同时完成读和写操作,它直接继承object ,并且同时实现了接口DataInput和DataOutput,提供了支持随机文件操作的方法:
在生成一个随机文件对象时,除了要指明文件对象和文件名之外,还需要指明访问文件的模式。
import java.io.*;
public class random_file
{
public static void main(String args[])
{
int[] data_arr = {12,31,56,23,27,1,43,65,4,99};
try //99,4,65,43,1,27,23,56,31,12
{
RandomAccessFile randf = new RandomAccessFile("temp.dat","rw");
for (int i = 0; i < data_arr.length; i++) {
//将数组元素写到二进制文件
randf.writeInt(data_arr[i]);
}
for(int i=data_arr.length-1; i>=0; i--)
{
//调节指针位置 一个元素占用4个字节 ,读的是二进制文件
randf.seek(i*4);//9*4=36,从最后一个元素开始读,这就是倒着把数组读出来
System.out.println(randf.readInt());
}
//读完后指针指向12
randf.seek(8); //12 指针调8个字节---2个元素
System.out.println(randf.readInt());//56
System.out.println(randf.readInt());//23
randf.skipBytes(8);//23,跳过八个字节,跳过两个元素
System.out.println(randf.readInt()); //43
randf.close();
}catch (IOException e){
System.out.println("File access error: "+e);
}
}
}
也就是套接流,需要套接其他的流才能使用
1、缓冲流
BufferedInputStream 和 BufferedOutputStream
为输入和输出流创建和维持缓冲
缓冲是一种提高读写效率的机制
将缓冲流与文件流相接
字节缓冲流采用了装饰器模式来增强InputStream、OutputStream子类对象的功能
例如,通过BufferedInputStream增强FileInputStream的功能
BufferedInputStream bufferedInputStream = new BufferedInputStream(newFileInputStream("input.txt"));
主要体现在调用write()和read()方法的时候,由于字节缓冲流内部有缓冲区(字节数组),因此,字节缓冲流会先将读取到的字节存放在缓冲区,大幅减少io操作,提高读取效率。
FileInputStream in = new FileInputStream(“file1.txt”);
FileOutputStream out = new FileOutputStream (“file2.txt”);
//套接。将文件流in套接缓存流,还可以设置缓冲区的大小
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中得到的是数据
2、数据流
数据流类DataInputStream和DataOutputStream的处理对象除了是字节或字节数组外,还可以实现对文件的不同数据类型的读写。
FileInputStream fis = new FileInputStream("file1.txt");
FileOutputStream fos = new FileOutputStream("file2.txt");
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
可以用readLine()方法读取一行信息。适合于文本文件。
1、标准流
java.lang包中的System类管理标准输入/输出流和错误流
每当main方法被执行,就自动生成上述三个对象
//类 System字段 In “标准”输入流。
class System{
public static final InputStream in //“标准”输入流。
public static final PrintStream out //"标准”输出流
public static final PrintStream err //“标准”错误流
}
System类中,是用静态final修饰,输入流、输出流、错误流
创建InputStream对象,通过底层,将对象set进变量in里,所以in里包含InputStream对象
1、对象流
能够记录自己的状态以便将来再生的能力,叫对象的持续性
对象通过写出描述自己状态的数值来记录自己的过程叫串行化。
能够输入输出对象的流称为对象流。可以将对象串行化后通过输入输出流写入文件或传送到其他地方
只有实现Serializable接口的类才能被串行化,Serializable接口中没有任何方法,当一个类声明实现Seriazable接口时,只是表明该类加入对象串行化协议。
如:
public class Student implements Serializable
{
int id;
String name;
int age;
String department;
public Student()
{System.out.println("无参构造方法被调用");}
public Student(int id, String name, int age, String department)
{ System.out.println("有参构造方法被调用");
this.id = id;
this.name = name;
this.age = age;
this.department = department;
}
@Override
public String toString(){
return "id = " + id + " name = " + name+" age = " + age+" department = " + department;
}
}
Student类实现了Serializable接口 ,表明该类可以被序列化----保存对象的状态
2、序列化
代码如下:
public class TestStudent
{
public static void main(String[] args){
Student t = new Student(123, "李华", 23, "开发部门");
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){//传输过程中io问题抛出异常
System.out.println("I/O Error!");
}
}
}
将把对象的状态保存到网络或者二进制文件中: 条件如下
序列化就是将对象的状态通过输出流写入到一个二进制文件的过程
3、反序列化
代码如下:
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!");
}
}
}
从二进制文件中读取对象的状态(属性值)
反序列化就是指从流所指的文件中读取对象的状态
4、注意:
5、目前学到的三种创建对象方法:
1、管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。java.io中提供了类PipedInputStream和PipedOutputStream 作为管道的输入/输出流。
2、实现生产者和消费者模式
/**
* 用管道模拟生产者和消费者线程
*/
public class ThreadWork {
public static void main(String[] args) throws IOException {
//创建管道输出流
PipedOutputStream pos = new PipedOutputStream();
//创建管道输入流,并和输出流管道连接
PipedInputStream pis = new PipedInputStream(pos);
//创建两个线程
PipeProducer producer = new PipeProducer(pos, "生产者线程");
PipeConsumer consumer = new PipeConsumer(pis, "消费者线程");
producer.start();
consumer.start();
}
}
/**
* 生产者线程,与输出流有关
*/
class PipeProducer extends Thread{
private PipedOutputStream pos;
public PipeProducer(PipedOutputStream pos,String name){
super(name);
this.pos = pos;
}
@Override
public void run(){
int i = 0;
try {
while (true){
Thread.sleep(2000);
if (i==0){
i=1;
System.out.println(Thread.currentThread().getName()+"生产:"+i);
pos.write(i);
}else {
pos.close();
break;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 消费者线程(与管道输入流)
*/
class PipeConsumer extends Thread{
private PipedInputStream pis;
public PipeConsumer(PipedInputStream pis,String name){
super(name);
this.pis = pis;
}
@Override
public void run(){
try{
while (true){
int i = pis.read();
if (i==1){
System.out.println(Thread.currentThread().getName()+"消费了"+i);
i=0;
}else {
pis.close();
break;
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
将多个不同的输入流统一为一个输入流。
FileInputStream f1,f2;
String s;
f1 = new FileInputStream(“file1.txt”);
f2 = new FileInputStream(“file2.txt”);
SequenceInputStream fs = new SequenceInputStream(f1, f2);
DataInputStream ds = new DataInputStream(fs);
while( (s = ds.readLine()) != null )
System.out.println(s);
只适用于连接多个文件输入流
为什么I/O操作要分字节流和字符流?
因此直接加入用于字符流处理的类
1、从jdk1.1开始,java.io包中加入了专门用于字符流处理的类,它们是以Reader和Writer为基础派生的一系列类
2、InputStreamReader和OutputStreamWriter 是java.io包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介。
3、同样提供了字符流的缓冲流。java.io中也提供了缓冲流BufferedReader和BufferedWriter。其构造方法与BufferedInputStream和BufferedOutputStream相类似。另外,除了read()和write()方法外,它还提供了整行字符处理方法。
class FileTOUnicode
{
public static void main(String args[])
{
try
{
//文件输入流
FileInputStream fis = new FileInputStream(“file1.txt");
//字符输入流
InputStreamReader dis = new InputStreamReader(fis);
// InputStreamReader dis = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(dis);
String s;
while( (s = reader.readLine()) != null )
{
System.out.println("read: "+s);
}
dis.close();
}catch(IOException e)
{
System.out.println(e);
}
}//main()
}//class
4、其他字符流
1、装饰器模式
装饰器模式通过组合替代继承来扩展原始类的功能 ,在一些继承关系比较复杂的场景(IO 这一场景各种类的继承关系就比较复杂)更加实用。
如,对于字节流来说,FilterInputStream和FilterOutStream是装饰器的核心,分别用于增强InputStream和OutputStream子类对象的功能
例如,字节缓冲流、对象流等都是用来增强InputStream和OutputStream子类对象的功能
BufferedInputStream bufferedInputStream = new BufferedInputStream(newFileInputStream("input.txt"));
IO操作中像这样用到装饰器模式的地方还有很多。
2、适配器模式
适配器(Adapter Pattern)模式 主要用于接口互不兼容的类的协调工作,你可以将其联想到我们日常经常使用的电源适配器。
适配器模式中存在被适配的对象或者类称为 适配者(Adaptee) ,作用于适配者的对象或者类称为适配器(Adapter) 。适配器分为对象适配器和类适配器。类适配器使用继承关系来实现,对象适配器使用组合关系来实现。
//InputStreamReader是适配器,FileInputStream是被适配的类--适配者
InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName),"UTF-8");
1、在Java中有数据传输的地方都用到I/O流(通常是文件,网络,内存和标准输入输出等)。
2、InputStream 和OutputStream是所有字节流的祖先(只有RandomAccessFile类是一个例外 ),read和write是它们最基本的方法,读写单位是字节。
3、Reader 和Writer是所有字符流的祖先,read和write是它们最基本的方法,读写单位是字符。
4、File, File(Input/Output)Stream, RandomAccessFile是处理本地文件的类。
5、Data(Input/Output)Stream是一个过滤流的子类(套接流),借此可以读写各种基本数据 ,在文件和网络中经常使用。如: readByte, writeBoolean等。