Java-文件流和I/O
文件
概念
- 文件是保存数据的地方。
- 文件流:文件在程序中以流的形式操作。
- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据从数据源(文件)到程序(内存)的路径
- 输出流:数据从程序(内存)到数据源(文件)的路径
常用操作
创建文件
new File(String pathname) // 根据路径构建一个File对象
new File(File parent, String child) // 根据父目录文件+子路径 构建
new File(String parent, String child) // 根据父目录+字路径 构建
createNewFile 创建新文件
@Test
public void creatFile01() {
File file = new File("/Users/xinyu/Desktop/自学/Java/newFile.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void createFile02() {
File parentPath = new File("/Users/xinyu/Desktop/自学/Java");
String childName = "newFile01.txt";
File file = new File(parentPath, childName);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void createFile03() {
String parentPath = "/Users/xinyu/Desktop/自学/Java";
String childName = "newFile02.txt";
File file = new File(parentPath, childName);
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
获取文件信息
getName
getAbsolutePath
getParent
length
exists
isFile
isDirectory
// 获取文件信息
public static void info() {
File file = new File("/Users/xinyu/Desktop/自学/Java/newFile.txt");
// 调用相应的文件方法和属性
System.out.println("文件名字:" + file.getName());
System.out.println("文件的绝对路径:" + file.getAbsolutePath());
System.out.println("文件的父目录:" + file.getParent());
System.out.println("文件大小(字节):" + file.length());
System.out.println("文件是否存在:" + file.exists());
System.out.println("文件是否是文件:" + file.isFile());
System.out.println("文件是否是目录:" + file.isDirectory());
}
其他操作
mkdir
创建一级目录mkdirs
创建多级目录delete
删除空目录或文件
@Test
public void f1() {
String path = "/Users/xinyu/Desktop/自学/Java/newFile.txt";
File file = new File(path);
if (file.exists()) {
boolean delete = file.delete();
if (delete) {
System.out.println("文件删除成功");
} else {
System.out.println("文件删除失败");
}
} else {
System.out.println("该文件不存在");
}
}
@Test
public void f2() {
String path = "/Users/xinyu/Desktop/自学/Java/JavaTest";
File file = new File(path);
if (file.exists()) {
System.out.println("该目录已存在");
} else {
if (file.mkdirs()) { // 创建多级目录 mkdir 创建一级目录
System.out.println("目录创建成功");
} else {
System.out.println("目录创建失败");
}
}
}
IO流原理及流的分类
-
按操作数据单位不同分为:字节流(8bit)-- 二进制文件,字符流(字符)-- 文本文件
-
按数据流的流向不同分为:输入流,输出流
-
按流的角色的不同分为:节点流,处理流/包装流
-
抽象基类 字节流 字符流 输入流 InputStream Reader 输出流 OutputStream Writer
节点流和处理(包装)流
- 节点流:可以从一个特点的数据源读取数据。例如:FileReader、FileWriter、FileInputStream、FileOutputStream
- 处理流:“连接”已经存在的流(处理流或节点流)之上,为程序提供更为强大的读写功能。例如:BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream、ObjectReader、ObjectWriter、ObjectInputStream、ObjectOutputStream
- 数据源主要是针对放数据的地方,若是文件选用节点流,若是其他形式选用处理流。
- BufferedReader中有属性Reader,因此可以包装或封装一个节点流,该节点流可以是任意的Reader子类。
区别和联系
- 节点流是底层流 / 低级流,直接和数据源相接
- 处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更多方便的方法来实现输入输出
- 处理流对节点流进行包装,使用了修饰器设计模式,不会与数据源直接相接
- 处理流增加缓存的方式提高性能,提高输入输出的效率
- 处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
输入流
InputStream
FileInputStream 文件字节输入流
// 单个字节的读取,效率较低
@Test
public void readFile01() {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test01.txt"; // 文件路径
FileInputStream fileInputStream = null;
int readData = 0;
try {
// 创建FileInputStream 用于读取文件
fileInputStream = new FileInputStream(filePath);
while ((readData = fileInputStream.read()) != -1) {
System.out.print((char) readData);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void readFile02() {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test01.txt"; // 文件路径
FileInputStream fileInputStream = null;
// 字节数组定义
byte[] buf = new byte[8]; // 一次读取8个字节
int readLen = 0;
try {
// 创建FileInputStream 用于读取文件
fileInputStream = new FileInputStream(filePath);
while ((readLen = fileInputStream.read(buf)) != -1) {
String readDate = new String(buf, 0, readLen); // 注意:转换时,buf会出现不清空数组的问题,所以需要加入Len
System.out.print(readDate);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream 缓冲字节输入流
ObjectInputStream 对象字节输入流
Reader
FileReader
@Test
public void readFile01() {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test01.txt";
FileReader fileReader = null;
char ch = ' ';
try {
fileReader = new FileReader(filePath);
// 单个字符读取
while ((ch = (char) fileReader.read()) != -1) {
System.out.print(ch);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void readFile02() {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test01.txt";
FileReader fileReader = null;
char[] cbuf = new char[8];
int readLen = 0;
try {
fileReader = new FileReader(filePath);
// 多个字符读取
while ((readLen = fileReader.read(cbuf)) != -1) {
System.out.print(new String(cbuf, 0, readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader
ObjectReader
public class ObjectInputStream01 {
public static void main(String[] args) {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test04.dat";
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
// 1. 读取(反序列化)的顺序需要和保存数据(序列化)的顺序一致
// 2. 否者会出现异常
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readDouble());
System.out.println(objectInputStream.readUTF());
try {
Object obj = objectInputStream.readObject();
System.out.println("运行类型=" + obj.getClass());
System.out.println(obj);
// 若需要进行调用对象Object(Dog) 的方法, 需要进行向下转行,因此需要Dog类的使用
// 需要共同应用Dog类
/*
Dog dog = (Dog) obj;
*/
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
InputStreamReader
- InputStreamReader:Reader子类,可以将InputStream(字节流)包装(转换)成Reader(字符流)
public static void main(String[] args) throws IOException {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test03.txt";
FileInputStream fileInputStream = new FileInputStream(filePath);
// 1. 将FileInputStream字节流转换为InputStreamReader字节流,
// 2. 增加编码格式
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
// InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
// 3. 将InputStreamReader 传入 BufferedReader
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
System.out.println(bufferedReader.readLine());
bufferedReader.close(); // 只需要关闭外层流即可
// inputStreamReader.close();
// fileInputStream.close();
}
输出流
OutputStream
FileOutputStream 文件字节输出流
@Test
public void writeFile01() {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test02.txt"; // 文件路径
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(filePath);
fileOutputStream.write('a');
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void writeFile02() {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test02.txt"; // 文件路径
FileOutputStream fileOutputStream = null;
String data = "hello world";
byte[] bytes = data.getBytes();
try {
// 1. 这样的创建方式,在写入时 会覆盖 new FileOutputStream(filePath)
// 2. new FileOutputStream(filePath, true) 这种方式是 在本文件后进行追加
fileOutputStream = new FileOutputStream(filePath, true);
fileOutputStream.write(bytes);
fileOutputStream.write(bytes, 1, 5); // 偏移量 写入
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedOutputStream 缓冲字节输出流
ObjectOutputStream 对象字节输出流
public class ObjectOutputStream01 {
public static void main(String[] args) {
// .dat 序列化后,不是纯文本文件,而是按照本身文件内容格式
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test04.dat";
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeInt(100); //int -> Integer 实现了 Serializable接口
objectOutputStream.writeBoolean(true);
objectOutputStream.writeChar('c');
objectOutputStream.writeDouble(99.321);
objectOutputStream.writeUTF("wxywxywxy");
// 保存对象
Dog dog = new Dog("wangcai", 3);
objectOutputStream.writeObject(dog);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Writer
FileWriter
@Test
public void writeFile01() {
FileWriter fileWriter = null;
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test02.txt";
try {
fileWriter = new FileWriter(filePath, true);
String str = "风雨之后,必有彩虹吗?";
fileWriter.write(str);
fileWriter.write(str, 1, 6);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileWriter.close(); // 必须编写关闭或者刷新,否则不会写入
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void writeFile02() {
FileWriter fileWriter = null;
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test02.txt";
try {
fileWriter = new FileWriter(filePath, true);
String str = " 风雨之后,必有彩虹吗?";
fileWriter.write(str.toCharArray(), 0, 10);
fileWriter.write(str.toCharArray());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileWriter.close(); // 必须编写关闭或者刷新flush(),否则不会写入 !!!
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedWriter
ObjectWriter
public class ObjectOutputStream01 {
public static void main(String[] args) {
// .dat 序列化后,不是纯文本文件,而是按照本身文件内容格式
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test04.dat";
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.write(100); //int -> Integer 实现了 Serializable接口
objectOutputStream.writeBoolean(true);
objectOutputStream.writeChar('c');
objectOutputStream.writeDouble(99.321);
objectOutputStream.writeUTF("wxywxywxy");
// 保存对象
Dog dog = new Dog("wangcai", 3);
objectOutputStream.writeObject(dog);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
对象处理流的注意事项
- 读写顺序要一致
- 要求实现序列化或反序列化现象,需要实现Serializable接口
- 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
- 序列化对象时,默认将里面所有属性都进行序列化,但除了static修饰或transient修饰的成员
- 序列化对象时,要求里面属性的数据类型也需要实现序列化接口
- 序列化具备继承性,也就是如果某类已经实现了序列化,则它的所有子类都默认实现了序列化
拷贝
拷贝二进制文件
public class FileCopy {
/*
文件拷贝思路分析:
1. 创建文件的输入流,读取文件到程序中
2. 创建文件的输出流,将读取的文件写入到文件中
*/
public static void main(String[] args) {
String filePath = "/Users/xinyu/Desktop/111.jpg";
String targetPath = "/Users/xinyu/Desktop/自学/Java/JavaTest/wxy.jpg";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream(filePath);
fileOutputStream = new FileOutputStream(targetPath);
// 定义一个字节数组,提高读取效率
byte[] bytes = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(bytes)) != -1) {
// 注意:使用偏移写入,防止bytes中的缓存未情况
fileOutputStream.write(bytes, 0, readLen); // 边读边写
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Buffered拷贝文本文件
public static void main(String[] args) {
String srcPath = "/Users/xinyu/Desktop/test03.txt";
String targetPath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test03.txt";
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try {
bufferedReader = new BufferedReader(new FileReader(srcPath));
bufferedWriter = new BufferedWriter(new FileWriter(targetPath));
String data = null;
// readLine() 读取一行内容,但没有换行
while ((data = bufferedReader.readLine()) != null) {
bufferedWriter.write(data);
bufferedWriter.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Buffered拷贝二进制文件
public static void main(String[] args) {
String srcPath = "/Users/xinyu/Desktop/111.jpg";
String targetPath = "/Users/xinyu/Desktop/自学/Java/JavaTest/wxy1.jpg";
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(srcPath));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(targetPath));
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = bufferedInputStream.read(buf)) != -1) {
bufferedOutputStream.write(buf, 0, readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedInputStream.close();
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStreamWriter
- OutputStreamWriter:Writer子类,可以将OutputStream(字节流)包装(转换)成Writer(字符流)
public static void main(String[] args) throws IOException {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test05.txt";
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("asdasdasdas啊实打实");
bufferedWriter.close();
}
打印流
- 打印流只有输出流,没有输入流
PrintStream 字节流
public static void main(String[] args) throws IOException {
PrintStream out = System.out;
// 默认情况下为标准输出,显示在控制台中
out.println("hello world");
// 因为print()方法的底层就是write()方法,则可以直接调用write方法进行打印
out.write("hello world".getBytes());
// 修改打印或者写入的数据位置
// 1. 创建方式
// String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test06.txt";
// PrintStream printStream = new PrintStream(filePath);
// printStream.write("hello world".getBytes());
// 2. 设置方式
System.setOut(new PrintStream("/Users/xinyu/Desktop/自学/Java/JavaTest/test06.txt"));
System.out.println("hello, world");
out.close();
}
PrintWriter 字符流
public static void main(String[] args) throws IOException {
PrintWriter printWriter = new PrintWriter(System.out);
// 标准输出,在控制器中显示
printWriter.println("hello, world");
printWriter.close();
PrintWriter pt = new PrintWriter(
new FileWriter("/Users/xinyu/Desktop/自学/Java/JavaTest/test06.txt", true));
pt.println("hello, wxy");
pt.close();
}
Properties类
Properties常见的方法:
- load:加载配置文件的键值对到Properties对象
- list:将数据显示到指定设备
- getProperty(key):根据键获取值
- setProperty(key, value):设置键值对到对象Properties
- store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,若含有中文,会存储为Unicode码
读取Properties文件
public static void main(String[] args) throws IOException {
String filePath = "/Users/xinyu/IdeaProjects/IdeaWorkspace/Study_Java/Study_Java_ten/src/mysql.properties";
// 1. 创建Properties对象
Properties properties = new Properties();
// 2. 加载指定配置文件
properties.load(new FileReader(filePath));
// 3. 显示键值对到控制台
properties.list(System.out);
// 4. 根据key获取value
String user = properties.getProperty("user");
String pwd = properties.getProperty("pwd");
System.out.println(user);
System.out.println(pwd);
}
修改Properties文件
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
// 创建
// 1. 若key不汆子啊 就创建
// 2. 若key存在 就修改
/*
Properties 父类是 HashTable,底层就是HashTable 核心方法
*/
properties.setProperty("id", "001");
properties.setProperty("user", "汤姆"); // 注意:保存中文,会保存Unicode码
properties.setProperty("pwd", "04281023");
// 第一个参数可以是 字符流或字节流的输出,第二个参数为 注释内容
properties.store(new FileOutputStream("Study_Java_ten/src/mysql2.properties"), null);
}
Homework
Homework01
public static void main(String[] args) throws IOException {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest";
File file = new File(filePath);
if (!file.exists()){
if (file.mkdirs()) {
System.out.println("该目录不存在,创建成功");
}
} else {
System.out.println("创建失败,该目录已存在");
}
file = new File(filePath, "test001.txt");
if (file.createNewFile()) {
System.out.println("test001创建成功");
} else {
System.out.println("test001创建失败");
}
FileWriter fileWriter = new FileWriter(filePath + "/test001.txt");
fileWriter.write("hello, world");
fileWriter.close();
}
}
Homework02
public static void main(String[] args) throws IOException {
String filePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/test03.txt";
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
for (int i = 1; (line = bufferedReader.readLine()) != null; i++) {
System.out.print(i + " ");
System.out.println(line);
}
bufferedReader.close();
}
Homework03
public class Homework03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String filePath = "Study_Java_ten/src/dog.properties";
String dogFilePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/dog.dat";
Properties properties = new Properties();
properties.load(new FileReader(filePath));
String name = properties.getProperty("name");
int age = Integer.parseInt(properties.getProperty("age"));
String master = properties.getProperty("master");
Dog dog = new Dog(name, age, master);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(dogFilePath));
objectOutputStream.writeObject(dog);
objectOutputStream.close();
readDogDat();
}
public static void readDogDat() throws IOException, ClassNotFoundException {
String dogFilePath = "/Users/xinyu/Desktop/自学/Java/JavaTest/dog.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(dogFilePath));
Dog dog = (Dog)objectInputStream.readObject();
System.out.println(dog);
objectInputStream.close();
}
}
class Dog implements Serializable {
private String name;
private int age;
private String master;
public Dog(String name, int age, String master) {
this.name = name;
this.age = age;
this.master = master;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", master='" + master + '\'' +
'}';
}
}