一、IO流的概述
1. 流的类型
- 操作数据单位:字节流、字符流
- 数据的流向:输入流、输出流
- 流的角色:节点流、处理流
图解
以字体颜色划分类别
2. 体系结构
重点学习蓝色框中的内容
3. 输入、输出的基本步骤
输入过程
- 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
- 创建相应的输入流,将File类的对象作为参数,传入流的构造器中
- 具体的读入过程: 创建相应的byte[] 或 char[]。
- 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。
输出过程
- 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)
- 创建相应的输出流,将File类的对象作为参数,传入流的构造器中
- 具体的写出过程: write(char[]/byte[] buffer,0,len)
- 关闭流资源
说明:程序中出现的异常应使用try-catch-finally处理。
二、字符流
字符流只能处理文本文件(例如:.txt,.java,.c,.cpp)。
1. 字符输入流
@Test public void testFileReader() {
FileReader fr = null;
try {
//1. File的实例化
File file = new File("testFileReader.txt");
//2. 实例化 FileReader流
fr = new FileReader(file);
//3. 进行读入操作
//read(char[] charbuffer):返回每次读入到数组中的字符个数,若达到文件末尾则返回-1
char[] charbuffer = new char[5];
int len;
while ((len = fr.read(charbuffer)) != -1) {
//方式一:
//for (int i = 0; i < len; i++) {
// System.out.print(charbuffer[i]);
//}
//方式二:
String str = new String(charbuffer, 0, len);
System.out.print(str);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//4. 流的关闭
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. 字符输出流
@Test public void testFileWriter() {
//1. File的实例化
File file = new File("testFileWriter.txt");
FileWriter fw = null;
try {
//2. FileWriter
fw = new FileWriter(file);
//3. 进行写出操作
fw.write("Hello, ");
fw.write("world ! ");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 流的关闭
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、字节流
字节流可处理所有文件
字节输入流/字节输出流
运用两种字节流进行文件复制操作
public void fileInputOutputStreamTest() throws IOException {
//1. 创建File类对象,指定读入与写出的文件
File srcFile = new File("img1.jpg");
File destFile = new File("copy.jpg");
//2. 创建输入输出流
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
//3. 数据的读入与写出操作
byte[] buffer = new byte[1024];
//记录字符个数
int len;
while ((len = fileInputStream.read(buffer)) != -1) {
//每次写出len个字符
fileOutputStream.write(buffer, 0, len);
}
//4.关闭流 - 建议从后向前关闭流
fileOutputStream.close();
fileInputStream.close();
}
四、缓冲流
- BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
缓冲流作用:提供流的读取、写入的速度
提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb
1. 字符缓冲流
@Test
public void testBufferedReaderWriter() throws IOException {
//1.实例化文件和流
BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("copy.txt")));
//2.进行数据读写
char[] charbuffer = new char[1024];
int len;
while((len = br.read(charbuffer)) != -1){
bw.write(charbuffer,0,len);
}
//3. 关闭资源
bw.close();
br.close();
}
2. 字节缓冲流
@Test
public void copyFileWithBuffered() throws IOException {
//1. 创建File类对象,指定读入与写出的文件
File srcFile = new File("img1.jpg");
File destFile = new File("copy.jpg");
//2. 创建输入输出流
InputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
//3. 创建缓冲流
BufferedInputStream bis = new BufferedInputStream(fileInputStream);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
//4. 数据的读入与写出操作
byte[] buffer = new byte[1024];
//记录字符个数
int len;
while ((len = fileInputStream.read(buffer)) != -1) {
//每次写出len个字符
bos.write(buffer, 0, len);
}
//5.关闭流 - 建议从后向前关闭流
bos.close();
bis.close();
}
五、字符转换流
由于字符存在编码问题,转换流用于解决字符转码问题。
1. 输入字符转换流
@Test public void inputStreamReaderTest() throws IOException {
FileInputStream fis = new FileInputStream("hello.txt");
//InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
//参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
//使用系统默认的字符集 默认为 UTF-8
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1) {
String str = new String(cbuf, 0, len);
System.out.print(str);
}
isr.close();
}
2. 输出字符转换流
该例子为综合输入和输出字符转换流
@Test
public void outputStreamWriterTest() throws Exception {
//1.造文件、造流
File file1 = new File("hello.txt");
File file2 = new File("hello_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
//2.读写过程
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1) {
osw.write(cbuf, 0, len);
}
//3.关闭资源
isr.close();
osw.close();
}
六、对象流
自定义类型的对象使用对象流的条件:
- 需要实现接口:Serializable
- 当前类提供一个全局常量:serialVersionUID
- 除了当前类需要实现Serializable接口之外,还必须保证其内部所属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
import org.junit.Test;
import java.io.*;
public class ObjectInputOutputStreamTest {
/**
* 对象输出流
*/
@Test
public void objectOutputStreamTest() {
ObjectOutputStream oos = null;
try {
//1.
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
//2.
oos.writeObject(new String("I like Java"));
oos.flush();//刷新操作
oos.writeObject(new Student("张三", 23));
oos.flush();
oos.writeObject(new Student("李四", 23, 1001));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
//3.
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 对象输入流
*/
@Test
public void objectInputStreamTest() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String)obj;
Student student = (Student)ois.readObject();
Student student1 = (Student)ois.readObject();
System.out.println(str);
System.out.println(student);
System.out.println(student1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//实体类/自定义类型
class Student implements Serializable{
private static final long serialVersionUID = -121294470754667710L;
private String name;
private int age;
private int score;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
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;
}
@Override public String toString() {
return "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}';
}
}
七、RandomAccessFile/随机存取文件流
- RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口。
- RandomAccessFile既可以作为一个输入流,又可以作为一个输出流。
- 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
如果写出到的文件存在,则会对原文件内容进行覆盖。(默认情况下,从头覆盖) - 可以通过seek(int pos) ,实现RandomAccessFile插入数据的效果。
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
/**
* 实现复制粘贴
* @throws IOException
*/
@Test public void randomAccessFileTest1() throws IOException {
//1.创建流
RandomAccessFile raf1 = new RandomAccessFile(new File("img.jpg"), "r");
RandomAccessFile raf2 = new RandomAccessFile(new File("img1.jpg"), "rw");
//2.创建缓冲区
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer, 0, len);
}
//3.关闭流
raf1.close();
raf2.close();
}
/**
* 使用RandomAccessFile实现数据的插入效果
*/
@Test public void randomAccessFileTest2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
//将指针调到角标为3的位置
raf1.seek(3);
//保存指针3后面的所数据到StringBuilder中
StringBuilder builder = new StringBuilder((int)new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while ((len = raf1.read(buffer)) != -1) {
builder.append(new String(buffer, 0, len));
}
//调回指针
raf1.seek(3);
raf1.write("AAA".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
}
}
八、Path、Paths、Files的使用
1. Path
Path用于替换原有的File类。
该接口的实现是不可变且安全的,可供多个并行线程使用。
2. Paths
此类仅由静态方法组成,通过转换路径字符串返回Path或URI 。
Paths类提供了get()方法用来获取Path对象。
Paths的常用方法
3. Files
主要用于操作文件或文件目录的工具类
常用方法
转载:https://blog.csdn.net/qq_26020387/article/details/106157373
查看评论