文件
三种常用创建文件的代码:
// method1 new File(String pathname)
public static void create1() {
String filePath = "E:\\test.txt";
File file = new File(filePath); //这里的file在java程序中,只是一个对象
try {
file.createNewFile(); //这里才创建文件到磁盘
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
// method2 new File(File parent, String child) 根据父目录文件 + 子路径创建
public static void create2() {
File parentFile = new File("E:\\");
String fileName = "test2.txt";
File file = new File(parentFile, fileName);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
// method3 new File(String parentName, String childName)
public static void create3() {
String parentName = "E:\\";
String childName = "test3.txt";
File file = new File(parentName, childName);
try {
System.out.println("文件创建成功");
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
常用操作:
getName
、getAbsolutePath
、getParent
、length
(字节大小)、exists
、isFile
、isDirectory
、delete
等。
IO流
流的分类:
按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符) 文本文件
按数据流的流向不同分为:输入流,输出流
按流的角色的不同分为:节点流(FileReader、FileWriter等),处理流/包装流(BufferedReader、BufferedWriter等)
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputSream | Writer |
InputStream
InputStream
常用的子类:
FileInputStream
:文件输入流BufferedIputStream
:缓冲字节输入流ObjectInputStream
:对象字节输入流
FileInputStream
public static void main(String[] args) {
FileInputStream fileInputStream = null;
byte[] buf = new byte[8];
int readLen = 0;
try {
fileInputStream = new FileInputStream("E:\\test.txt");
// 可以read读字节,也可以read(byte[] byte)读一个字符数组
while ((readLen = fileInputStream.read(buf)) != -1) {
System.out.print(new String(buf, 0, readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStream
FileOutputStream
public static void main(String[] args) {
/**
* 注意:new FileOutputStream(filePath) 当写入内容时会覆盖原来的内容
* new FileOutputStream(filePath, true) 当写入内容时会追加到末尾
* */
String pathName = "E:\\test2.txt";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(pathName, true);
// 写入一个字节
fileOutputStream.write('a');
// 写入字符串
String str = "hello, world!";
fileOutputStream.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileReader
操作和FileInputStream
类似。
FileWriter
操作和FileOutputStream
类似。
new FilwWriter(File/String, true)
追加到文件末尾
注意:FileWriter
使用后,必须要关闭(close)或刷新(flush)!
BufferedInputStream
和FileInputStream
操作类似。
BufferedOutputStream
和FileOutputStream
操作类似。
BufferedReader
是Reader
的一个子类,是对节点流的包装。
例如:new BufferedReader(new FileReader(PathName))
bufferedReader.readLine()
按行读取文件,当返回null
时,表示文件读取完毕。
BufferedWriter
同BufferedReader
,是Writer
的一个子类,是对节点流的包装。
例如:new BufferedWriter(new FileWriter(PathName, true))
bufferWriter.write()
等。
对象处理流
序列化:保存数据的值和数据类型(必须实现Serializable接口(常用)或Externalizable接口)
反序列化:恢复数据的值和数据类型
ObjectOutputStream
提供序列化功能
ObjectInputStream
提供反序列化功能
和BufferedReader和BufferedWriter类似,是包装类。
public class ObjectOutputStream_ {
public static void main(String[] args) throws Exception {
String pathName = "E:\\test.txt";
// 序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(pathName));
objectOutputStream.writeInt(100);
objectOutputStream.writeBoolean(true);
objectOutputStream.writeObject(new Dog("小黄", 1));
objectOutputStream.writeObject(new Dog("小黑", 2));
objectOutputStream.close();
System.out.println("ok");
// 反序列化,注意读取顺序
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(pathName));
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
Object obj = objectInputStream.readObject();
// 向下转型 注意:这里需要将Dog类的定义拷贝到可以引用的位置
Dog dog = (Dog)obj;
System.out.println("姓名: " + dog.getName() + " 年龄: " + dog.getAge());
objectInputStream.close();
System.out.println("ok");
}
}
// 要被序列化的类一定要实现Serializable接口
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
对象处理流的使用细节:
- 读写顺序要一致
- 要求实现序列化或反序列化对象,需要实现
Serializable
- 序列化的类中建议添加
SerialVersionUID
,为了提高版本的兼容性- 例如:
private static final long SerialVersionUID = 1L
- 例如:
- 序列化对象时,默认将里面所有属性都进行序列化,但除了
static
或transient
修饰的成员 - 序列化对象时,要求里面属性的类型也需要实现序列化接口
- 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
面试题:close()和flush()的区别
close() 关闭流对象,但要先刷新一次缓冲区。关闭后流对象不可以继续被使用了。
flush() 仅仅刷新缓冲区,刷新之后流对象依然可以继续使用。
字节流和字符流使用情况:(重要)
字符流和字节流的使用范围:
字节流一般用来处理图像,视频,以及PPT,Word类型的文件。
字符流一般用于处理纯文本类型的文件,如TXT文件等。
字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件。
结论:只要处理纯文本类型的数据,优先考虑字符流,其余文件一律用字节流。
字节流和字符流的区别(重点)
字节流和字符流的区别:(详细可以参见这篇文章)
字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()
方法时,信息已经输出了,而字符流只有在调用close()
方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()
方法。(close()
方法在关闭字符流之前会强制刷新一遍缓冲区)
读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。