一、File 类
Java 中通过 java.util.File 类来对一个文件(包括目录)进行抽象的描述;
File 类构造方法
常用其他方法
代码示例
1. 创建一个 .txt文件
File file = new File("d:/testFile.txt");
boolean newFile = file.createNewFile();
System.out.println(newFile);
2. 获取文件名和文件路径
String name = file.getName();
String path = file.getPath();
System.out.println(name + "\n" + path);
3. 判断该文件是否存在并且是否是一个目录
boolean exists = file.exists();
boolean directory = file.isDirectory();
System.out.println(exists + "\n" + directory);
4. 执行代码
二、对文件内容的操作
Java 中通过流对象来实现对文件内容的操作,流对象可分为字节流和字符流
字节流:每次读/写的最小单位是字节(1字节 = 8 bit)
字符流:每次读/写的最小单位是字符(1个字符对应多个字节,跟编码方式有关,其中 GBK:1 中文字符 -> 2 字节,UTF8:1 中文字符 -> 3字节,Unicode:1 中文字符 -> 2 字节)
对文件的操作可分为读(输入)和写(输出),因此就构成了 Java IO 流的四个抽象基类,分别为:
输入 | 输出 | |
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
上述四个类都是抽象类,具体实现是由具体的子类完成的
1. 字节流
1. FileInputStream
构造方法:
常用其他方法:
代码示例:
public class TestInputStream {
public static void main(String[] args) {
try (FileInputStream file = new FileInputStream("d:/test.txt")){
int tmp;
byte[] bytes = new byte[10];
while((tmp = file.read(bytes)) != -1){
System.out.print(new String(bytes, 0, tmp));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
注意:在使用字节流读取文本文件的时候,可能会出现乱码问题;
2. FileOutputStream
构造方法:
在构造方法中,若 append 为 true,则会在文件后面继续写(追加写),否则写操作会替换掉原来的内容(覆盖写);
常用其他方法:
代码示例:
public class TestOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("d:/test.txt", true);
String str = "2024/7/10,你好,我在学IO";
fileOutputStream.write(str.getBytes());
fileOutputStream.close();
}
}
3. 使用 FileOutputStream 和 FileInputStream 完成图片文件复制
public class TestFileCopy {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("d:/dog.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("d:/dog2.jpg");
byte[] bytes = new byte[1024];
int tmp;
while((tmp = fileInputStream.read(bytes)) != -1){
fileOutputStream.write(bytes, 0, tmp);
}
System.out.println("复制完成");
fileOutputStream.close();
fileInputStream.close();
}
}
2. 字符流
1. FileReader
构造方法:
常用其他方法:
示例代码:
public class TestReader {
public static void main(String[] args) {
try(FileReader reader = new FileReader("d:/test.txt")){
char[] chars = new char[8];
int tmp;
while((tmp = reader.read(chars)) != -1){
System.out.print(new String(chars, 0, tmp));
}
}catch (IOException e){
e.printStackTrace();
}
}
}
2. FileWriter
构造方法:
常用其他方法:
示例代码:
public class TestWriter {
public static void main(String[] args) {
try(FileWriter fileWriter = new FileWriter("d:/test.txt")) {
fileWriter.write("fileWriter 的 write 方法");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
3. 使用 FileReader 和 FileWriter 完成文件复制
public class TestFileCopy2 {
public static void main(String[] args) {
try (FileReader reader = new FileReader("d:/test.txt");
FileWriter writer = new FileWriter("d:/test2.txt")){
char[] chars = new char[16];
int tmp;
while((tmp = reader.read(chars)) != -1){
writer.write(new String(chars, 0, tmp));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
3. 带缓冲的字节处理流
1. BufferedInputStream
构造方法:
其他常用方法:
2. BufferedOutputStream
构造方法:
其他常用方法:
在向文件中写入数据后,需要调用 flush 方法或者 close 方法刷新缓冲区, 才会生效;
4. 带缓冲的字符处理流
1. BufferedReader
构造方法:
其他常用方法:
代码示例:
public class TestBufferedReader {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("d:/test.txt"));
String string = reader.readLine();
System.out.println(string);
reader.close();
}
}
释放流资源时,只需释放最外层即可;
2. BufferedWriter
构造方法:
其他常用方法:
代码示例:
public class TestBufferedWriter {
public static void main(String[] args) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter("d:/test.txt", true));
writer.write("今天星期四");
writer.write("今天天气不错", 2, 4);
writer.close();
}
}
在使用完之后,要使用 flush 或 close 刷新缓冲区,这样数据才会写入设备中,同样在关闭时,只需关闭外层流即可;
5. 用于转换的字符流
1. InputStreamReader
可将字节输入流转换成字符输入流
构造方法:
其他常用方法:
2. OutputStreamWriter
可将字节输出流转换为字符输出流
构造方法:
其他常用方法:
6. 打印输出流
1. PrintStream
构造方法:
标准输出流 System 类中的对象 out 的编译类型就是 PrintStream;
2. PrintWriter
构造方法:
三、笔试题(实现 ObjectCloner 类)
在实际的 java 开发中,常常需要克隆一个对象,请编写一个工具类 ObjectCloner 实现 clone 方法来克隆指定对象,需满足以下要求:
1. obj1 != obj2
2. obj1 和 obj2 是同一类型,具备相同的字段和方法
3. obj2 的字段值应于 obj1 保持一致,包括对基本数据类型和数组的字段进行深度克隆
4. ObjectClone 应该是一个通用的工具类,能够对任意类型的对象克隆
方法一:使用对象流的方式
package util;
import java.io.*;
public class ObjectCloner {
/**
* 克隆指定对象的方法
*
* @param <T> 对象类型
* @param obj 需要克隆的对象
* @return 克隆后的对象
* @throws IOException 如果在序列化过程中发生IO错误
* @throws ClassNotFoundException 如果类未找到
*/
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) throws IOException, ClassNotFoundException {
if (obj == null) {
throw new IllegalArgumentException("对象不能为空");
}
// 创建字节输出流
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
// 创建对象输出流
ObjectOutputStream outStream = new ObjectOutputStream(byteOutStream);
// 将对象写入输出流
outStream.writeObject(obj);
outStream.flush();
// 创建字节输入流,基于写入的数据
ByteArrayInputStream byteInStream = new ByteArrayInputStream(byteOutStream.toByteArray());
// 创建对象输入流
ObjectInputStream inStream = new ObjectInputStream(byteInStream);
// 读取克隆的对象并返回
return (T) inStream.readObject();
}
}
方法二:使用反序列化
package util;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
public class ObjectCloner2 {
// 克隆方法
public static <T> T clone(T obj) throws Exception {
// 获取对象的类类型
Class<?> clazz = obj.getClass();
// 创建新的实例
T clone = (T) clazz.getDeclaredConstructor().newInstance();
// 获取对象的所有字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true); // 设置字段可访问
// 判断字段类型
if(field.getType().isPrimitive() || field.getType().equals(String.class)){
// 对于基本数据类型和String类型,直接进行赋值
field.set(clone, field.get(obj));
} else if (field.getType().isArray()){
// 对于数组类型,通过Array的copy方法进行深度克隆
Object arrayObj = field.get(obj);
int length = Array.getLength(arrayObj);
Object newArrayObj = Array.newInstance(field.getType().getComponentType(), length);
System.arraycopy(arrayObj, 0, newArrayObj, 0, length);
field.set(clone, newArrayObj);
} else {
// 对于其他引用类型,递归调用克隆方法进行深度克隆(要求其他引用类型也能实现克隆方法)
field.set(clone, clone(field.get(obj)));
}
}
return clone;
}
}