基本IO操作
节点流和处理流
节点流:可以从或向一个特定的地方(结点读取数据)
处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写
import java.io.*;
/**
* java标准的IO,可以利用相同的读写方式不同的设备。
* java将IO比喻为"流",可以理解为是连接程序与设备之间的"管道",管道
* 里面是按照一个方向顺序流动的字节。
*
* java将流的方向划分为两个操作
* 输入:用来读取,是从设备到程序的方向,是获取的数据使用的。
* 输出:用来写出,是从程序到设备的方向,用来发送数据使用的。
*
* java.io.InputStream是所有字节输入流的超类,里面定义了读取字节的方法
* java.io.OutputStream是所有字节输出流的超类,里面定义了写出字节的方法
*
* java将流分为两类:节点流和处理流
* 节点流:也称低级流,是实际连接程序与设备的管道,负责实际读取字节的流。
* 读写一定是建立在节点流的基础上进行的,操作不同的设备有对应的低级流。例如读写文件有文件流。
* 处理流:也称高级流,不能独立存在,必须连接在其他流上,目的是当数据"流经"当前流时对其做某些加工处理
* 简化我们的操作。
* 实际开发中我们总是会串联一组高级流最终连接到低级流上,在数据进行读写的
* 过程中对数据做流水线式的加工处理,这也成为流连接,也是IO的精髓。
*
* 文件流
* 文件流是一对低级流,用于读写文件的流,功能上与RandomAccessFile一致
* java.io.FileInputStream和FileOutputStream
*/
public class FOSDemo {
public static void main(String[] args) throws IOException {
/*
文件输出流构造方法:
FileOutputStream(String path)
FileOutputStream(File file)
以上两种构造器创建的文件流为覆盖写模式
即:创建文件流时如果指定的文件已经存在,则会将该文件内容清空。
然后使用这个流写出的数据会顺序写入文件作为新数据保存。
注:RAF则是从头开始写多少覆盖多少。(在不操作指针的情况下)
文件流重载的构造方法
FileOutputStream(String path,boolean append)
FileOutputStream(File file,boolean append)
如果第二个参数指定,并且指定的值为true时,则当前文件流为
追加模式。即:创建文件流时如果文件存在,那么文件原有数据保留
通过这个流写入的数据都会被追加到文件中。
*/
FileOutputStream fos = new FileOutputStream("fos.txt");
String line = "我能习惯远距离";
byte[] data = line.getBytes("UTF-8");
fos.write(data);
line = "多远都要在一起";
fos.write(line.getBytes("UTF-8"));
System.out.println("写出完毕");
fos.close();
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* 使用文件输入流读取文件数据
*/
public class FISDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("fos.txt");
byte[] data = new byte[1000];
int len = fis.read(data);
System.out.println("实际读取了"+len+"字节");
/*
将给定的字节数组从下表offset处的连续len个字节按照UTF-8
编码转换为字符串。
*/
String line = new String(data,0,len,"UTF-8");
System.out.println(line);
System.out.println(line.length());
fis.close();
}
}
/**
* 使用文件流完成文件的复制操作
*/
public class CopyDemo {
public static void main(String[] args) throws IOException {
/*
1.创建文件输入流读取原文件
2.创建文件输出流写入复制文件
3.循环块读写完成复制
4.关闭两个流
*/
FileInputStream fis = new FileInputStream("fos.txt");
FileOutputStream fos = new FileOutputStream("fos_cp.txt");
int len;
byte[] data = new byte[1024*10];
while((len = fis.read(data))!=-1){
fos.write(data,0,len);
}
System.out.println("复制完毕");
fis.close();
fos.close();
}
}
/**
* 使用缓冲流完成文件复制。
*
* 缓冲流:java.io.BufferedInputStream和BufferedOutputStream
* 它们是一对高级流,在流连接中的作用是提高读写效率。
*/
public class CopyDemo2 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("love.jpg");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("love_3.jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int d;
long start = System.currentTimeMillis();
/*
缓冲流内部维护着一个字节数组,默认为8k。无论我们读写时用哪种方式,
最终都会被缓冲流转化为块读写8k8k的进行来保证读写效率。
*/
while((d = bis.read())!=-1){
bos.write(d);
}
long end = System.currentTimeMillis();
System.out.println("复制完毕,耗时"+(end-start)+"ms");
bis.close();
bos.close();
}
}
/**
* 使用缓冲输出流写出数据的缓冲区问题
*/
public class BOS_flushDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("bos.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
String line = "让我再看你一眼,从南到北。";
byte[] data = line.getBytes("UTF-8");
bos.write(data);
/*
void flush()
将缓冲流中已经缓存的数据一次性写出。
频繁的调用flush会增加实际写出数据的次数,写出次数
多则写出效率差。但是可以提高写出数据的即时性。
*/
bos.flush();
System.out.println("写出完毕!");
/*
缓冲流的close方法中会执行一次flush
*/
bos.close();
}
}
/**
* 使用当前类测试对象流的对象读写操作
*
* 当一个类的实例希望被对象流进行读写时,该类必须实现接口:
* java.io.Serializable
*
* Serializable接口中没有任何抽象方法,这是一个签名接口,该接口是编译器
* 敏感的结构,当编译器编译一个类时如果这个类实现了序列化接口则会在编译后
* 的class文件中添加一个方法,作用是按照该类结构转换为一组字节(对象流就是依靠
* 这个方法做对象序列化的)
*/
public class Person implements Serializable {
private String name;
private int age;
private String gender;
/*
transient关键字可以在对象序列化时忽略该属性的值
忽略不重要的属性可以达到对象序列化时的瘦身操作,减少资源开销
*/
private transient String[] otherInfo;
public Person(String name, int age, String gender, String[] otherInfo) {
this.name = name;
this.age = age;
this.gender = gender;
this.otherInfo = otherInfo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String[] getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(String[] otherInfo) {
this.otherInfo = otherInfo;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", otherInfo=" + Arrays.toString(otherInfo) +
'}';
}
}
/**
* 将Person对象写入文件
*
* 对象流:java.io.ObjectOutputStream和ObjectInputStream
* 对象流是一种高级流,作用是进行对象的序列化与反序列化
*/
public class OOSDemo {
public static void main(String[] args) throws IOException {
String name = "亚索";
int age = 26;
String gender = "男";
String[] otherInfo = {"是一个英雄","来自艾欧尼亚","促进快乐","快乐风男"};
Person person = new Person(name,age,gender,otherInfo);
FileOutputStream fos = new FileOutputStream("person.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
/*
对象输出流提供了一个独有的方法:
void writeObject(Object obj)
该方法可以将给定的对象按照其结构转化为一组字节后写出。
需要注意,该方法要求写出的对象必须实现了序列化结构,
否则会抛出异常,java.io.NotSerializableException
将一个对象按照其结构转换为一组字节的过程称为对象序列化
反之则称为对象反序列化
*/
oos.writeObject(person);
System.out.println("对象写出完毕!");
oos.close();
}
}
/**
* 对象输入流
*/
public class OISDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//读取person.obj文件中的Person对象
FileInputStream fis = new FileInputStream("person.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
/*
对象输入流提供的readObject方法可以将读取的字节还原为
对应的java对象,前提是读取的字节应当是对象输出流将一个
对象转换的一组字节。返回时统一一Object类型返回,因此
接收到该对象后要造型。
*/
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
}