基本IO操作:
1、 IS与OS
2、 文件流
3、 缓冲流
扩展性强,可以一下读取很多字节,比如读取照片,指针是单向的。
IS与OS:
1、 流式API非常适合扩展,java提供了非常丰富的扩展。
2、输入与输出:
输入:是一个从外界进入到程序的方向,通常我们需要“读取”外界的数据时,使用输入。所以输入是用来读取数据的。
输出:是一个从程序发送到外界的方向,通常我们需要“写出”数据到外界时,使用输出。所以输出是用来写出数据的。
3、节点流与处理流:
1、按照流是否直接与特定的地方(如磁盘、内存、设备)相连,分为节点流和处理流。
2、节点流:可以从或向一个特定的地方(节点)读写数据。基本的。一次只能读取一个byte。
3、处理流(扩展流、装饰流):是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。是扩展 的。 一次可以读取一张照片。
4、处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
4、IS与OS常用方法:
1、InputStream:
InputStream是所有字节输入流的父类,其定义了基础的读取方法,常用的方法如下:
---int read()
读取一个字节,以int形式返回,该int值的“低八位”有效,若返回-1则是EOF.
---int read(byte[])
尝试最多读取给定数组的length个字节并存入该数组,返回值为实际读取到的字节量。
2、OutputStream:
OutputStream是所有字节输出类的父类,其定义了基础的写出方法,常用的方法如下:
---void write(int d)
写出一个字节,写的是给定的int的“低八位”。
---void write(byte[] d)
将给定的字节数组中的所有字节全部写出。
文件流:
1、创建FOS对象(重写模式)
FileOutputStream是文件的字节输出流,我们使用该流可以以字节为单位将数据写入文件。
构造方法:
---FileOutputStream(File file):
创建一个向指定File对象表示的文件中写出数据的文件输出流。
---FileOutputStream(Stream filename):
创建一个向具有指定名称的文件中写出数据的文件输出流。
这里需要注意的是,若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。
2、创建FOS对象(追加模式)
若想在文件的原有数据之后追加新数据则需要以下构造方法:
---FileOutputStream(File file,boolean append):
创建一个向指定File对象表示的文件中写出数据的文件输出流。
---FileOutputStream(Stream filename,boolean append):
创建一个向具有指定名称的文件中写出数据的文件输出流。
以上两个构造方法,如果第二个参数为true,则表示写出的数据是在文件末尾追加的。
public void testAppend() throws Exception {
//使用追加方法打开文件并且写出内容
//文件长度会不断增加
File file=new File("demo5.dat");
//在末尾追加
BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(file,true));
out.write(50);
out.flush();//刷出(倾倒)缓冲区,强行写入硬盘,缓冲区此时并没有满,但是没有关闭文件
out.close();//先刷出缓冲,再关闭文件
System.out.println("文件长度:"+file.length());//每运行一次文件长度+1
}
3、创建FIS对象
FileInputStream是文件的字节输入流,我们使用该流可以以字节为单位从文件中读取数据。
构造方法:
---FileOutputStream(File file)
创建一个从指定File对象表示的文件中读取数据的文件输入流。
---FileOutputStream(String name)
创建用于读取给定的文件系统中的路径名name所指定的文件的文件输入流
4、read()和write(int d)方法:
FileInputStream继承自InputStream,其提供了以字节为单位读取文件数据的方法read。
---int read()
从此输入流中读取一个数据字节,若返回-1则表示EOF
public void testFileInputStream() throws Exception {
//使用文件输入流读文件
FileInputStream in=new FileInputStream("out.dat");
int b;
while((b=in.read())!=-1) {
System.out.println(b);
}
in.close();
}
FileOutputStream继承自OutputStream,其提供了以字节为单位向文件写数据的方法write。
---void write(int d)
将指定字节写入此文件输出流。这里只写给定的int值的“低八位”。
public void testFileOutputStream() throws Exception {
//使用文件输出流写文件
FileOutputStream out=new FileOutputStream("out.dat");
out.write(50);
out.write(80);
byte[] buf= {50,60,70};
out.write(buf);//写入一个字节数组
out.close();
}
public void testCopy() throws Exception {
//使用文件流实现文件的复制
//1、输入流in打开源文件
//2、输出流out打开目标文件
//3、使用循环从in读取,写出到out
//4、关闭文件
FileInputStream in=new FileInputStream("E:/1.rar");
FileOutputStream out=new FileOutputStream("E:/2.rar");
int b;
while((b=in.read())!=-1) {
//b就是文件中的每个byte
out.write(b);//将每个byte写入到out文件中
}
in.close();
out.close();
System.out.println("复制文件结束!");
}
public void testCopy1() throws Exception {
FileInputStream in=new FileInputStream("E:/1.rar");
FileOutputStream out=new FileOutputStream("E:/2.rar");
byte[] buf=new byte[1024*8];//每次读取8k
int n;
while((n=in.read(buf))!=-1) {//将读取到的数据写入到buf中
System.out.println(n);
out.write(buf, 0, n);
}
in.close();
out.close();
System.out.println("复制文件结束!");
}
public void testCopy2() throws Exception {
FileInputStream in=new FileInputStream("E:/1.rar");
//创建缓冲字节输入流
BufferedInputStream bos=new BufferedInputStream(in);
//上面两句写成一句
BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream("E:/2.rar"));
int b;
while((b=bos.read())!=-1) {//将读取到的数据写入到buf中
out.write(b);
}
bos.close();
out.close();
System.out.println("复制文件结束!");
}
缓冲流:
1、BOS基本工作原理:
与缓冲输入流类似,在向硬件设备做写出操作时,增大写出次数无疑也会降低写出效率,为此我们可以使用缓冲输出流来一 次 性批量写出若干数据减少写出次数来提高写出效率。
BufferedOutputStream缓冲输出流内部也维护着一个缓冲区,每当我们向该流写数据时,都会先将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。缓冲区大小默认是8k。
2、 BufferedOutputStream缓冲输出流不能单独工作,必须依赖一个节点流。会自动维护一个缓冲区。
对象流:
1、对象流属于处理流,不能单独工作。
2、使用OOS实现对象序列化
ObjectOutputStream是用来对对象进行序列化的输出流。
方法:
---void writeObject(Object o)
该方法可以将给定的对象转换为一个字节序列后写出。
3、使用OIS实现对象反序列化
ObjectInputStream是用来对对象进行反序列化的输入流。
方法:
---Object readObject()
该方法可以从流中读取字节并转换为对应的对象。
4、Serializable接口
ObjectOutputStream在对对象进行序列化时有一个要求,就是需要序列化的对象所属于的类必须实现Serializable接口。实现该接口不需要重写任何方法。其只是作为可序列化的标志。通常实现该接口的类需要提供一个常量serialVersionUID,表明该类的版本。
5、transient关键字
对象在序列化后得到的字节序列往往比较大,有时我们在对一个对象进行序列化时,可以忽略某些不必要的属性,从而对序列化后得到的字节序列进行“瘦身”。
关键字:transient瞬态的属性
被该关键字修饰的属性在序列化时其值将会被忽略。
public void testWriteObject() throws Exception{
//创建对象输出流
//创建一个Contact对象
//将对象写出到文件中
//关闭文件
ObjectOutputStream out=new ObjectOutputStream(//创建对象输出流
new BufferedOutputStream(//每次取8k,依赖于节点流FileOutputStream
new FileOutputStream("obj.dat")));
//创建Contact对象
Contact c1=new Contact(1,new Date(),"张三","112");
Contact c2=new Contact(2,new Date(),"李四","113");
//将对象写出到文件中
out.writeObject(c1);
out.writeObject(c2);
out.close();
}
public void testReadObject() throws Exception{
//创建对象输入流
//读取对象
//关闭文件
ObjectInputStream in=new ObjectInputStream(
new BufferedInputStream(
new FileInputStream("obj.dat")));
Contact c1=(Contact)in.readObject();
Contact c2=(Contact)in.readObject();
in.close();
System.out.println(c1.toString());
//1,Wed Apr 25 16:19:32 CST 2018,张三,null
System.out.println(c2.toString());
//2,Wed Apr 25 16:19:32 CST 2018,李四,null
//电话号码使用了transient瞬态的属性,不会被序列化写到硬盘上
}
class Contact implements Serializable{
int id;
Date time;
String name;
transient String mobile;//电话号码使用了transient瞬态的属性,不会被序列化写到硬盘上
//构造方法:右击->source->generate constructor using filed
public Contact(int id, Date time, String name, String mobile) {
super();
this.id = id;
this.time = time;
this.name = name;
this.mobile = mobile;
}
public String toString() {
return id+","+time+","+name+","+mobile;
}
}
6、对象序列化和对象反序列化
对象是存在于内存中的。
将对象转换为一个字节序列,这个过程称为对象序列化。
将一个字节序列转换为对应的对象,这个过程称为对象的反序列化。
JavaBean
1、 都实现序列化接口
2、 都有无参构造器
3、 属性一般是私有的,有共有的访问方法,get和set
4、 重写三个方法:hashCode、toString、equals