流的分类
按操作数据单位不同分为:字节流(8bit)二进制文件,字符流(按字符)
按数据流的流向不同分为:输入流、输出流
按流的角色不同分为:节点流,处理流/包装流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
字节输入流(InputStream )
相关子类
FileInputStream:文件输入流
BufferedInputStream:缓冲字节输入流
ObjectInputStream:对象字节输入流
FileInputStream文件输入流
以字节形式处理流,主要是处理二进制文件。
@Test
public void reader01() throws IOException {
String url = "C:\\Users\\lenovo\\Desktop\\hello.txt"; //文件地址
int readData = 0;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(url); //创建流
while ((readData = fileInputStream.read()) != -1) { // 数为-1时则表示读取完
System.out.print((char) readData);
}
} catch (IOException e) {
log.error(e.getMessage());
} finally {
fileInputStream.close(); // 关闭流
}
}
上述代码是进行单字节进行读取所以速度相对较慢,也可以指定一次读取的字节数量。
fileInputStream = new FileInputStream(url); //创建流
byte[] bytes = new byte[15]; //一次读取的字节数量
// 数为-1时则表示读取完
// 如果读取正常readData值为读取字符数量
while ((readData = fileInputStream.read(bytes)) != -1) {
System.out.print(new String(bytes, 0, readData));
}
字节输出流(OutputStream)
相关子类:FileOutputStream字节输入流
@Test
public void write01() throws IOException {
FileOutputStream fileOutputStream = null;
String url = "C:\\Users\\lenovo\\Desktop\\a.txt"; //文件地址
String text = "123456789"; //需要写入的数据
try {
// new FileOutputStream(url)这种方式写入文件是覆盖的方式
// new FileOutputStream(url, true);这种方式写入文件是追加的方式
fileOutputStream = new FileOutputStream(url, true);
// write(byte b[], int off, int len)
// write(byte b[])
fileOutputStream.write(text.getBytes(), 1, 4); //将文件写入
} catch (FileNotFoundException e) {
log.error(e.getMessage());
} finally {
fileOutputStream.close(); //关闭连接
}
}
字符输入流(FileWriter)
FileWriter常用方法
1、 new FileWriter(File/String):覆盖模式,相当于流的指针在首端
2、new FileWriter(File/String,trule):追加模式,相当于流的指针在尾端’
3、 write(int):写入单个字符
4、write(char[]):写入指定数组
5、write(char[],off,len):写入指定数组的指定部分
6、write (string) :写入整个字符串
7、write(string,off, len):写入字符串的指定部分
注意!!!FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!
@Test
public void write() throws IOException {
FileWriter fileWriter = null;
String url = "C:\\Users\\lenovo\\Desktop\\note.txt"; //文件地址
try {
String text = "风雨过后,能见彩虹。";//写入文件内容
fileWriter = new FileWriter(url);//开启流
//表示写入位置0-5的字符
fileWriter.write(text,0,5);
System.out.println("程序结束");
} catch (FileNotFoundException e) {
log.error(e.getMessage());
} finally {
//关闭流
if (fileWriter != null) {
fileWriter.close();
}
}
}
字符输入流(FileReader)
@Test
public void read01() throws Exception {
FileReader fileReader = null;
String Url = "C:\\Users\\lenovo\\Desktop\\hello.txt";//文件地址
int readData = 0;
try {
fileReader = new FileReader(Url); //启动流
char[] chars = new char[24]; //流每次读取文件大小
//fileReader.read(chars)等于-1表示文件读取完成
//readData的值为读取的文件大小
//fileReader.read如果写入读取大小则每次读取一个字符
while ((readData = fileReader.read(chars)) != -1) {
System.out.print(new String(chars, 0, readData));
}
} catch (FileNotFoundException e) {
log.error(e.Message);
} finally {
//关闭流
if (fileReader!= null) {
fileReader.close();
}
}
}
缓冲流
缓冲流的作用就是对字节、字符流更高效的读写。字符缓冲流(BufferedWriter、BufferedReader)和字节缓冲流(BufferedInputStream、BufferedOutputStream)
缓冲流中使用了修饰模式。修饰模式大致思想如下。
创建抽象类Reader_
public abstract class Reader_ {
public void fileReader(){}
public void stringReader(){}
}
分别创建FileReader_、StringReader_继承Reader_并实现方法
public class StringReader_ extends Reader_{
public void stringReader() {
System.out.println("stringReader");
}
}
public class FileReader_ extends Reader_{
public void fileReader() {
System.out.println("fileReader");
}
}
在BufferedReader_中定义属性Reader_,通过构造器传入的reader属性对FileReader、StringReader_中的方法调用
public class BufferedReader_ {
private Reader_ reader;
public BufferedReader_(Reader_ reader) {
this.reader = reader;
}
public void fileReader() {
reader.fileReader();
}
public void stringReader() {
reader.stringReader();
}
}
测试
public class demo {
public static void main(String[] args) {
BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());
bufferedReader_.fileReader();
bufferedReader_1.stringReader();
}
}
字符缓冲流
注意:
1、BufferedWriter和BufferedReader是按照字符操作的
2、不要去操作二进制文件(视频、录音等),不然可能造成文件损坏
字符缓冲输出流BufferedWriter
//文件输出流
@Test
public void write() throws IOException {
// 文件地址
String url = "C:\\Users\\lenovo\\Desktop\\note.txt";
// 将FileWriter转换成BufferedWriter
// new FileWriter(url, true)中的true表示以追加形式写入,没有true则为清空写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(url, true));
String text = "风雨过后";
//写入
bufferedWriter.write(text);
// 关闭流
System.out.println("写入成功");
bufferedWriter.close();
}
字符缓冲输入流BufferedReader
//文件输入流
public static void main(String[] args) throws Exception {
String url = "C:\\Users\\lenovo\\Desktop\\note.txt";
// 创建BufferedReader
BufferedReader br = new BufferedReader(new FileReader(url));
String s; //按行读取
// s为null则表示读取完
while ((s = br.readLine()) != null) {
System.out.println(s);
}
// 关闭流
br.close();
}
字节缓冲流
想要操作二进制文件则使用BufferedInputStream和BufferedOutputStream来操作。他们既可以操作二进制文件也可以操作文本文件。因为二进制是根本。
public class BufferedCopy02 {
public static void main(String[] args) throws IOException {
String url = "C:\\Users\\lenovo\\Desktop\\1527.wav";
String newUrl = "C:\\Users\\lenovo\\Desktop\\海贼王.wav";
//字节缓冲输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(url));
//字节缓冲输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(newUrl));
//每次读取字节大小
byte[] buffer = new byte[1024];
int len;
while ((len = bufferedInputStream.read(buffer))!= -1) { //读取并写入 -1读取完成
bufferedOutputStream.write(buffer, 0, len);
}
// 关闭流
bufferedOutputStream.flush();
bufferedInputStream.close();
}
}
节点流/处理流
通过序列化和反序列化的方式将数据和数据类型保存到文件中。ObjectOutputStream输出流和ObjectInputStream输入流
注意事项和细节说明
1)读写顺序要一致
2)要求实现序列化或反序列化对象,需要实现 Serializable
3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
5)序列化对象时,要求里面属性的类型也需要实现序列化接口
6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
ObjectOutputStream输出流
public class ObjectOutputStream_ {
public static void main(String[] args) throws IOException {
String url = "C:\\Users\\lenovo\\Desktop\\data.dat"; //文件地址
ObjectOutputStream oos = null;
try {
// 创建流
oos = new ObjectOutputStream(new FileOutputStream(url));
//根据对应的类型写入数据
oos.writeChar(1);
oos.writeDouble(1.1);
oos.writeUTF("username");
oos.writeObject(new Dog());
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
// 关闭流
oos.close();
}
}
}
// Serializable序列化
class Dog implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
}
ObjectInputStream输入流
@Slf4j
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException {
String url = "C:\\Users\\lenovo\\Desktop\\data.dat"; //文件地址
ObjectInputStream ois = null;
try {
// 开启输入流
ois = new ObjectInputStream(new FileInputStream(url));
// 数据类型要与写入数据类型一致
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
System.out.println(ois.readObject());
} catch (IOException | ClassNotFoundException e) {
log.error("Error reading fileReader_", e.getMessage());
} finally {
ois.close();
}
}
}