JAVAIO
文件相关知识
文件流
文件在程序中以流的形式来操作,有输入流(数据源(文件)到程序(内存))和输出流(程序(内存)到数据源(文件))。
常用的文件操作
创建新文件
new File(String pathname) //根据路径建一个File对象
new File(File parent, String child) //根据父目录文件+子路径构建
new File(String parent, String child) //根据父目录+子路径构建
file.creatNewFile(); //调用该方法创建新文件
注意路径需要 “ \\ ” ;注意异常的捕获或抛出。
获取文件的相关信息
//先创建文件对象
File file = new File("d:\\ioTestFile1.txt");
//创建新文件
try {
file.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
//获取相应信息
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());
流的分类
按操作数据单位不同分为:字节流 (8 bit)(通常读取二进制文件),字符流 (按字符)(文本文件)
按数据流的流向不同分为:输入流,输出流
按流的角色的不同分为:节点流,处理流 / 包装流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
节点流
字节流
FileInputStream 和 FileOutputStream
FileInputStream:文件输入流
FileOutputStream:文件输出流
FileInputStream读取文件:
String filePath = "d:\\ioTestFile1.txt";
int readData = 0;
//写在try外,方便finally中使用
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//读取一个字节的数据,如果没有输入,返回 -1, 跳出循环
while ((readData = fileInputStream.read()) != -1){
//转为char显示
System.out.print((char) readData);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
//关闭文件流,释放资源
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
输出为该文件中的内容。
单个字符的读取,效率较低,使用 read(byte[] b) 读取:
String filePath = "d:\\ioTestFile1.txt";
int readData = 0;
//字节数组
byte[] buf = new byte[8];
//定义一个整型来记录实际读取的字节数
int readLen = 0;
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//读取一个字节的数据,返回实际读取的字节数。如果没有输入,返回 -1, 跳出循环
while ((readLen = fileInputStream.read(buf)) != -1){
//输出buf中 0 - readLen 的字符。
System.out.print(new String(buf, 0, readLen));
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
//关闭文件流,释放资源
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
FileOutputStream 写入字符和字符串
//创建FileOutputStream 对象
String filePath = "d:\\ioTestFile1.txt";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(filePath);
//写入一个字节
fileOutputStream.write('H');
//写入一个字符串
String str = "hello,world";
//使用 str.getBytes() 将字符串转为字节数组
fileOutputStream.write(str.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
运行结果:文件中为:Hhello,world
FileOutputStream 追加地写入字符和字符串(指定其中一部分字符)
String filePath = "d:\\ioTestFile1.txt";
FileOutputStream fileOutputStream = null;
try {
//当b为true时,写入为追加在已有字符串后面
fileOutputStream = new FileOutputStream(filePath, true);
//写入一个字节
fileOutputStream.write('H');
//写入一个字符串
String str = "hello,world";
//从索引 i 开始,写入字符串中接下来的 i1 个字符
fileOutputStream.write(str.getBytes(), 6, 5);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
运行结果:文件中为:Hhello,worldHworld
使用 FileInputStream 和 FileOutputStream 进行文件拷贝
public static void main(String[] args) throws IOException {
//也可以直接抛出异常
//定义起始和目标文件路径
String srcFilePath = "d:\\ioTestFile1.txt";
String destFilePath = "d:\\ioTestFile2.txt";
FileInputStream fileInputStream = new FileInputStream(srcFilePath);
FileOutputStream fileOutputStream = new FileOutputStream(destFilePath);
//定义一个字节数组,提高读取效率
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(buf)) != -1){
// 每次读取到之后就直接写入新文件
//切记要用有readLen的方法
fileOutputStream.write(buf, 0, readLen);
}
if(fileInputStream != null){
fileOutputStream.close();
}
if(fileOutputStream != null){
fileOutputStream.close();
}
}
运行结果:新文件中也为:Hhello,worldHworld
字符流
FileReader 和 FileWriter
使用 FileReader 读取文件
public static void main(String[] args) throws IOException {
String filePath = "d:\\ioTestFile1.txt";
int data = 0;
//创建 FileReader 对象
FileReader fileReader = new FileReader(filePath);
//read 返回int型,为相应字符的相应编码,如果没有输入,返回 -1,跳出循环
while((data = fileReader.read()) != -1){
//转为char型输出
System.out.print((char) data);
}
if(fileReader != null){
fileReader.close();
}
}
运行结果:输出为Hhello,worldHworld
使用字符串高效读入:
跟 FileInputStream 类似
使用 FileWriter 写入文件
不上代码啦,介绍几种FileWriter的write方法,具体实现与上相类似。
new FileWriter(File/String) 覆盖模式,指针在首端
new FileWriter(File/String, true) 追加模式,指针在尾端
write(int) 写入单个字符
write(char[]) 写入指定数组
write(String.toCharArray) //将String转为char[],然后同上
write(char[], off, len) 写入字符数组的指定部分
write(String) 写入整个字符串
write(String, off, len) 写入字符串的指定部分
注意:FileWriter 使用后,必须要 .close 或 .flush ,否则不会真正写入(.close 中是先 .flush 再关闭)
处理流(包装流)
节点流是从一个特定的数据源读写数据。
处理流(也可以称包装流),将节点流进行包装,从而提供更强大的读写功能,也可以消除不同节点流动实现差异。
底层逻辑/原因:包装流中有一个属性是节点流类相对应的抽象类,可以传入节点流类,从而调用其方法。(如 BufferedReader 中有属性 Reader 类,可传入 Reader 的子类,即 FileReader、StringReader、PipeReader 之类,从而进行包装)
使用BufferedReader读入文件
public static void main(String[] args) throws IOException {
String filePath = "d:\\ioTestFile1.txt";
//创建 BufferedReader 对象
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String line;
//readLine()是按行读取文件,返回值为null时,文件读取完毕,退出循环
while((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
//关闭流,只要关闭包装流,其底部会关闭节点流
bufferedReader.close();
}
运行结果:输出Hhello,worldHworld
使用 BufferedWriter 写入文件
public static void main(String[] args) throws IOException {
String filePath = "d:\\ioTestFile1.txt";
//如要追加模式,在 FileWriter 中加 true 即可
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));
bufferedWriter.write("in");
//插入一个和系统相对应的换行
bufferedWriter.newLine();
bufferedWriter.write("bluemsun");
bufferedWriter.newLine();
//只要关闭外层包装流,底层会关闭节点流
bufferedWriter.close();
}
运行结果:文件中为:
Hhello,worldHworldin
bluemsun
对象流
ObjectOutputStream 和 ObjectInputStream
对象流解决了一个问题:我们想储存一个对象,储存这个对象的方法和属性,这时我们可以使用对象流。
序列化:在保存数据时,保存数据的值和数据类型
反序列化:在恢复数据时,恢复数据的值和数据类型
想要使某一个对象序列化,就要让它的类是可序列化的,为了做到这一点,这个类必须实现如下接口之一:
Serializable :这是一个标记接口,没有方法
Externalizable :该接口有方法需要实现,因此我们一般实现上面的 Serializable接口
将一个 int 型和一个 Dog 类序列化
public static void main(String[] args) throws IOException {
//序列化后,保存的文件格式,不是纯文件,而是按照它的格式来保存
String filePath = "d:\\ioTestFile3.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//自动将 int 类变为其包装类 Integer,其实现了 Serializable 接口
oos.write(100);
//存入一个Dog类对象
oos.writeObject(new Dog("旺财", 10));
oos.close();
}
其他一些方法:
writeBoolean(boolean b) 会将 boolean 类转为 Boolean 类
writeChar(char c) 会将 char 类转为 Char 类
writeDouble(double d) 同上
writeUTF(String str) String类
ObjectInputStream 反序列化(读取 / 恢复)一个对象:
public static void main(String[] args) throws IOException, ClassNotFoundException {
String filePath = "d:\\ioTestFile3.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
//反序列化的顺序应该和序列化的顺序相一致,在这里即,先读入int,再读入Dog
System.out.println(ois.readInt());
//此处 dog 的编译类型是 Object, 运行类型是 Dog
Object dog = ois.readObject();
System.out.println(dog.age);
//如果想要调用Dog的方法,需要向下转型
//还需要将Dog的定义放在可以引用到的位置
Dog dog_ = (Dog) dog;
ois.close();
}
ObjectOutputStream 和 ObjectInputStream 的其他注意事项:
要求实现序列化或反序列化对象,需要实现 Serializable
序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
序列化对象时,要求里面属性的类型也需要实现序列化接口
序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实了序列化。
总结:
DataStream
用来操作基本数据类型和字符串。
DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中。
DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中。
转换流
InputStreamReader
字节输入流 -->字符输入流
File file = new File("d:\\ioTestFile1.txt");
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
char[] c = new char[3];
int n = -1;
while((n = isr.read(c)) != -1){
System.out.print(new String(c,0,n));
}
isr.close();
OutputStreamWriter
字符输出流 -->字节输出流
File file = new File("ioTestFile1");
File target = new File("ioTestFile2");
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis,"Unicode");
FileOutputStream fos = new FileOutputStream(target,true);
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
char[] c = new char[3];
int n = -1;
while((n = isr.read(c)) != -1){
osw.write(c,0,n);
}
isr.close();
osw.close();