1. File类的使用
2. IO流原理及流的分类
原理
分类
3. 节点流(或文件流)
FileReader / FileWriter
package org.example;
import org.junit.Test;
import java.io.*;
/**
* 一、流的分类
* 1. 操作数据的单位:字节流、字符流
* 2. 数据的流向:输入流、输出流
* 3. 流的角色:节点流、处理流
* <p>
* 二、流的体系结构
* 抽象基类 节点流 缓冲流(处理流的一种)
* InputStream FileInputStream BufferedInputStream
* OutputStream FileOutputStream BufferedOutputStream
* Reader FileReader BufferedReader
* Writer FileWriter BufferedWriter
*
*
* 不能使用字符流处理图片等数据
* @author AmorFati
* @create 2020/10/8 9:11
*/
public class FileReaderWriterTest {
/*
将Hello.txt文件内容读入到程序中,并输出到控制台
说明点:
1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
2. 异常处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally来处理
3. 读入的文件一定要存在,否则就会报FileNotFoundException
*/
@Test
public void test() {
FileReader fr = null;
try {
//1. 实例化File类的对象,指明要操作的文件
File file = new File("Hello.txt");
//2. 提供具体的流
fr = new FileReader(file);
//3. 数据的读入
//read():返回读入的一个字符,如果达到文件末尾,返回-1
int data;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 流的关闭操作
try {
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//对read()操作的升级:使用read的重载方法
@Test
public void test1() {
FileReader fr = null;
try {
//1. File类的实例化
File file = new File("Hello.txt");
//2. FileReader流的实例化
fr = new FileReader(file);
//3. 读入的操作
//read(char[] cbuf):返回每次读入cbuf数组中的字符个数,如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while ((len = fr.read(cbuf)) != -1) {
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 资源的关闭
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
从内存中写出数据到硬盘的文件中
说明:
1. 输出操作,对应的File可以不存在
----如果不存在,在输入的过程中,会自动创建文件
----如果存在,
-----------如果流使用的构造器是:FileWriter(file,false)/ FileWriter(file):对原有文件的覆盖
-----------如果流使用的构造器是:FileWriter(file,true)不会对源文件覆盖,而是在原有文件内容后添加数据
*/
@Test
public void test2(){
FileWriter fw = null;
try {
//1. 提供File类的对象,指明写出的文件
File file = new File("He.txt");
//2. 提供FileWriter的对象,由于数据的写出
fw = new FileWriter(file);
//3. 写出的操作
fw.write("I have a dream\n");
fw.write("You need to have a dream");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 流资源的关闭
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test3() {
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类对象,指明读入和写出的数据
File srcFile = new File("hello.txt");
File destFile = new File("hello1.txt");
//2. 创建输入流输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3. 流的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cuf数组中的字符的个数
while ((len = fr.read(cbuf)) != -1) {
fw.write(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 关闭流资源
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream / FileOutputStream
package org.example;
import org.junit.Test;
import java.io.*;
/**
* 测试FileInputStream FileOutputStream的使用
*
*
* 结论:
* 对于文本文件(.txt,.java,.c,.cpp)使用字符流来处理
* 对于非文本文件(.jpg,.mp3,.doc,.ppt)使用字节流来处理
*(如果只是对文本文件进行复制,而不是读取出来进行操作,使用字节流也可以)
*
* tips: 一个汉字占三个字节
* @author AmorFati
* @create 2020/10/8 10:12
*/
public class FileInputOutputStreamTest {
/*
使用字节流处理文本文件可能出现乱码
*/
@Test
public void testFileInputStream() {
FileInputStream fis = null;
try {
//1. 造文件
File file = new File("Hello.txt");
//2. 造流
fis = new FileInputStream(file);
//3. 读数据
byte[] buffer = new byte[5];
int len;
while ((len = fis.read(buffer)) != -1) {
String str = new String(buffer, 0, len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
实现对图片的复制
*/
@Test
public void testFileInputOutputStream() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//造文件
File srcFile = new File("timg.jpg");
File destFile = new File("timg1.jpg");
//造流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//读写数据
byte[] buffer = new byte[5];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void testCopyFile() {
long start = System.currentTimeMillis();
copyFile("E:\\Downloads\\jdk-8u261-linux-x64.tar.gz","E:\\Downloads\\jdk-8u261-linux-x64.tar1.gz");
long end = System.currentTimeMillis();
System.out.println("复制时间:" + (end - start));
}
//指定路径下文件的复制
public void copyFile(String strPath, String destPath) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//造文件
File srcFile = new File(strPath);
File destFile = new File(destPath);
//造流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//读写数据
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4. 缓冲流
package org.example;
import org.junit.Test;
import java.io.*;
/**
* 处理流之一:缓冲流的使用
* BufferedInputStream
* BufferedOutputStream
* BufferedReader
* BufferedWriter
* <p>
* 2. 作用:提高流的读取、写入速度。
* 提高读写速度的原因:内部提供了一个缓冲区
* private static int DEFAULT_BUFFER_SIZE = 8192;
* <p>
* 3. 处理流:就是”套接“在已有的流的基础上
*
* @author AmorFati
* @create 2020/10/8 10:49
*/
public class BufferedTest {
/*
实现非文本文件的复制
*/
@Test
public void testBufferedStream() {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1. 造文件
File srcFile = new File("timg.jpg");
File destFile = new File("timg2.jpg");
//2.造流
//2.1 造节点流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//2.2 造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
// 3. 复制
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 关闭流
//要求:先关闭外层的流,再关闭内层的流
try {
if (bis != null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
//关闭外层流的同时,内层流也会自动进行关闭,所以可以省略
// fis.close();
// fos.close();
}
}
@Test
public void testCopyFileWithBuffered() {
long start = System.currentTimeMillis();
copyFileWithBuffered("E:\\Downloads\\jdk-8u261-linux-x64.tar.gz", "E:\\Downloads\\jdk-8u261-linux-x64.tar2.gz");
long end = System.currentTimeMillis();
System.out.println("复制时间:" + (end - start));
}
public void copyFileWithBuffered(String strPath, String destPath) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1. 造文件
File srcFile = new File(strPath);
File destFile = new File(destPath);
//2.造流
//2.1 造节点流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//2.2 造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
// 3. 复制
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 关闭流
//要求:先关闭外层的流,再关闭内层的流
try {
if (bis != null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
//关闭外层流的同时,内层流也会自动进行关闭,所以可以省略
// fis.close();
// fos.close();
}
}
/*
使用BufferedReader和BufferWriter实现文本文件的复制
*/
@Test
public void testBufferedReaderWriter() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(new File("Hello.txt")));
bw = new BufferedWriter(new FileWriter(new File("Hello1.txt")));
//方式1 使用char[]
// char[] cbuf = new char[1024];
// int len;
// while ((len = br.read(cbuf)) != -1) {
// bw.write(cbuf, 0, len);
// }
//方式2:使用String
String data;
while ((data = br.readLine()) != null) {
//方法一:
// bw.write(data + "\n");//data中不包含换行符
//方法二:
bw.write(data);
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bw != null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5. 转换流
package org.example;
import org.junit.Test;
import java.io.*;
/**
* 处理流之二:转换流的使用
* <p>
* 1. 转换流:属于字符流
* InputStreamReader:将字节的输入流转化为字符的输入流
* OutputStreamWriter:将一个字符的输出流转换为字节的输出流
* 2. 作用:提供字节流和字符流之间的转换
* <p>
* 3. 解码:字节、字节数组--->字符数组,字符串
* 编码:字符数组、字符串--->字节、字节数组
* <p>
* 4. 字符集
*
* @author AmorFati
* @create 2020/10/8 15:01
*/
public class InputStreamReaderTest {
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("wen.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");//使用系统默认的字符集
char[] cbuf = new char[1024];
int len;
while ((len = isr.read(cbuf)) != -1) {
String str = new String(cbuf, 0, len);
System.out.print(str);
}
isr.close();
}
/*
综合使用InputStreamReader和OutputStreamWriter
转码操作
*/
@Test
public void test2() {
InputStreamReader isr = null;
OutputStreamWriter osw = null;
try {
FileInputStream fis = new FileInputStream("wen.txt");
FileOutputStream fos = new FileOutputStream("wen1.txt");
isr = new InputStreamReader(fis, "UTF-8");
osw = new OutputStreamWriter(fos, "GBK");
char[] cbuf = new char[1024];
int len;
while ((len = isr.read(cbuf)) != -1) {
osw.write(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (isr != null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (osw != null)
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
最新的UTF-8有些字符需要6个字符表示。
6. 标准输入、输出流(了解)
package org.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 标准的输入、输出流
*
* @author AmorFati
* @create 2020/10/8 15:45
*/
public class SystemInOutStreamTest {
/*
1.1
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
1.2
System类中的SetIn(InputStream is),SetOut(PrintStream ps)方式重新指定输入输出设备。
1.3练习
从键盘输入字符串,要求读取到的整行字符串转成大写输出。
然后继续进行输入操作,直至当输入”e“或”exit“是,退出程序。
方法一:使用scanner实现
方法二:使用System.in实现,System.in--->BufferReader()的readLine()
*/
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("请输入:");
String data = br.readLine();
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println(upperCase);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
7. 打印流 (了解)
8. 数据流(了解)
package org.example;
import org.junit.Test;
import java.io.*;
/**
* 3. 数据流:
* 3.1 DataInputStream 和 DataOutputStream
* 3.2 作用:用于读取或写出基本数据类型的变量和字符串
*
* @author AmorFati
* @create 2020/10/8 16:21
*/
public class DataInputOutputStreamTest {
@Test
public void test1() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(3);
dos.flush();//刷新操作,将内存中已有的数据写入文件
dos.writeBoolean(true);
dos.flush();
dos.writeUTF("hello");
dos.flush();
dos.close();
}
@Test
public void test2() throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int a = dis.readInt();
boolean b = dis.readBoolean();
String c = dis.readUTF();
System.out.println(a);
System.out.println(b);
System.out.println(c);
dis.close();
}
}
dump structure and datadump structure and data
9. 对象流
serialVersionUID一定要显示声明
package org.example;
import org.junit.Test;
import java.io.*;
/**
* 对象流的使用
* 1. ObjectInputStream / ObjectOutputStream
* 2. 作用:用于存储和读取基本数据类型数据或对象的处理流。
*
* 3. 要想java对象可序列化,需要满足如下的要求:
* 1)实现接口:Serializable
* 2) 需要当前类提供一个全局常量:serialVersionUID
* 3) 除了当前的类需要实现Serializable接口外,还必须保证其内部所有属性
* 也必须是可序列化的。(默认情况下,基本数据类型可序列化)。
* 4) ObjectOutputStream 和 ObjectInputStream不能
* 序列化static和transient修饰的成员变量
*
* @author AmorFati
* @create 2020/10/8 21:49
*/
public class ObjectInputOutStreamTest {
/*
序列化过程:将内存中的java对象保存在磁盘中或通过网络传输出去
使用ObjectOutputStream实现
*/
@Test
public void testObjectOutputStream() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
oos.writeObject(new String("我爱北京天安门"));
oos.flush();
oos.writeObject(new Person("wang", 12));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
反序列化
*/
@Test
public void testObjectInputStream() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.txt"));
Object o = ois.readObject();
String str = (String) o;
System.out.println(str);
Person p = (Person) ois.readObject();
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (ois != null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Person implements Serializable {
private static final long serialVersionUID = 4232L;
private String name;
private int age;
private Account account;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, Account account) {
this.name = name;
this.age = age;
this.account = account;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
", account=" + account +
'}';
}
}
class Account implements Serializable {
private double price;
public Account() {
}
public Account(int price) {
this.price = price;
}
@Override
public String toString() {
return "Account{" +
"price=" + price +
'}';
}
}
10. 随机存取文件流(RandomAccessFile)
package org.example;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* RandomAccessFile的使用
* 1. 直接继承了Object类,实现了DataInput和DataOut接口
* 2. 既可以作为一个输入流,也可以作为一个输出流
* 3. 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建
* 如果写出到的文件存在,则会对原有文件内容进行覆盖。(重点)(默认情况下,从头覆盖)
* (其他的流都是对文件本身进行覆盖)
* 4.seek()方法
* @author AmorFati
* @create 2020/10/8 22:29
*/
public class RandomAccessFileTest {
@Test
public void test1() {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
raf1 = new RandomAccessFile("timg.jpg", "r");
raf2 = new RandomAccessFile("timg2.jpg", "rw");
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (raf1 != null)
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (raf2 != null)
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
对文件内容的覆盖
*/
@Test
public void test2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello2.txt", "rw");
raf1.seek(3L); //将指针调到角标3的位置
raf1.write("xyz".getBytes());
raf1.close();
}
/*
使用RandomAccessFile实现插入操作
*/
@Test
public void test3() {
RandomAccessFile raf1 = null;
try {
raf1 = new RandomAccessFile("Hello.txt", "rw");
raf1.seek(3L);
//保存指针3后面的所有数据到StringBuilder中
StringBuilder sb = new StringBuilder((int) new File("Hello.txt").length());
byte[] buffer = new byte[20];
int len;
while ((len = raf1.read(buffer)) != -1) {
sb.append(new String(buffer, 0, len));
}
//调回指针,写入xyz
raf1.seek(3);
raf1.write("xyz".getBytes());
raf1.write(sb.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (raf1 != null)
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
11. NIO.2中Path、Paths、Files类的使用
学习使用 commons-io.jar