File、IO流
序列化
对象持久化
在 Java 程序中所创建的对象都保存在内存中,一旦 JVM 停止运行,这些对象都将会消失。因此以下两种情况必须通过序列化实现:
- 需要把对象持久化保存在文件中,在 JVM 重启后能够继续使用。
- 通过网络传送对象信息,在多个 JVM 间共享对象。
Serializable 接口
在类中声明实现 Serializable 接口,表示允许 Java 程序对这个类的对象序列化:JVM 会将对象的成员变量保存为一组字节,这些字节可以再被 JVM 组装成对象。对象序列化只保存的对象的成员变量,且不会关注类中的静态变量。
- transient 字段:默认序列化机制就会被忽略。
- private 字段:序列化后不会被保护,任何 JVM 都可读取。
- serialVersionUID 字段:申明序列化的版本号码,序列化的版本号与反序列化的版本号必须一致才不会出错!(private static final long serialVersionUID = 1;)
//person类的读入读出
//对于 class Person implements Serializable
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));
Person person = new Person("John", 101, Gender.MALE);
oout.writeObject(person); // 序列化
oout.close();
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Object newPerson = oin.readObject(); // 反序列化 (没有强制转换到Person类型)
oin.close();
File
// 创建对象
File f = new File("D:\\resources\\xueshan.jpeg"); // 创建File对象(指定了文件的路径)
File f = new File("D:" + File.separator+"resources"+ File.separator +"xueshan.jpeg"); // File.separator 分隔符创建文件对象
File f = new File("file-io-app/src/data.txt"); // 相对路径:一般定位模块中的文件的。 相对到工程下!!
File f = new File("D:\\resources"); // File创建对象 ,可以是文件也可以是文件夹
// 判断文件类型、获取文件信息功能
f.length() // 文件大小(字节)
f.exists(); // 判断这个路径是否存在,这个文件夹存在否
f.getAbsolutePath(); // 获取绝对路径
f.getPath(); // 获取文件定义的时候使用的路径
f.getName(); //获取文件的名称:带后缀
f.lastModified(); // 获取文件的最后修改时间
f.isFile(); // 判断文件是文件还是文件夹
f.isDirectory(); // 判断文件是文件还是文件夹
// 创建文件
f.createNewFile(); // 创建新文件,创建成功返回true
f.mkdir(); // 创建一级目录
f.mkdirs(); // 支持多级创建
// 删除文件
f.delete(); // 删除文件或者空文件夹,占用一样可以删除
// 遍历文件夹
f.list(); // 获取当前目录下所有的"一级文件名称"到一个字符串数组
f.listFiles(); // 获取当前目录下所有的"一级文件对象"到一个文件对象数组
listFiles方法注意事项:
- 当调用者不存在时,返回null
- 当调用者是一个文件时,返回null
- 当调用者是一个空文件夹时,返回一个长度为0的数组
- 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
- 当调用者是一个需要权限才能进入的文件夹时,返回null
递归实现文件搜索
package com.itheima.d2_recusion;
import java.io.File;
import java.io.IOException;
/**
目标:去D判断搜索 eDiary.exe文件
*/
public class RecursionDemo05 {
public static void main(String[] args) {
// 2、传入目录 和 文件名称
searchFile(new File("D:/") , "eDiary.exe");
}
/**
* 1、搜索某个目录下的全部文件,找到我们想要的文件。
* @param dir 被搜索的源目录
* @param fileName 被搜索的文件名称
*/
public static void searchFile(File dir,String fileName){
// 3、判断dir是否是目录
if(dir != null && dir.isDirectory()){
// 可以找了
// 4、提取当前目录下的一级文件对象
File[] files = dir.listFiles(); // null []
// 5、判断是否存在一级文件对象,存在才可以遍历
if(files != null && files.length > 0) {
for (File file : files) {
// 6、判断当前遍历的一级文件对象是文件 还是 目录
if(file.isFile()){
// 7、是不是咱们要找的,是把其路径输出即可
if(file.getName().contains(fileName)){
System.out.println("找到了:" + file.getAbsolutePath());
// 启动它。
try {
Runtime r = Runtime.getRuntime();
r.exec(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}else {
// 8、是文件夹,需要继续递归寻找
searchFile(file, fileName);
}
}
}
}else {
System.out.println("对不起,当前搜索的位置不是文件夹!");
}
}
}
字符集
String编码
// 编码:把文字转换成字节(使用指定的编码)
String name = "abc我爱你中国";
// byte[] bytes = name.getBytes(); // 以当前代码默认字符集进行编码 (UTF-8)
byte[] bytes = name.getBytes("GBK"); // 指定编码
System.out.println(bytes.length);
System.out.println(Arrays.toString(bytes));
String解码
// 解码:把字节转换成对应的中文形式(编码前 和 编码后的字符集必须一致,否则乱码 )
// String rs = new String(bytes); // 默认的UTF-8
String rs = new String(bytes, "GBK"); // 指定GBK解码
System.out.println(rs);
IO

字节流
FileInputStream
// 创建一个文件字节输入流管道与源文件接通
InputStream is = new FileInputStream("file-io-app\\src\\data.txt");
int b1 = is.read(); // 读取一个字节返回 每次读取一个字节,性能较慢,读取中文字符输出无法避免乱码问题。
int b4 = is.read(); // 读取完毕返回-1
// 定义一个字节数组,用于读取字节数组
byte[] buffer = new byte[3];
int len = is.read(buffer); // 返回读取的字节个数 每次读取一个字节数组,读取的性能得到了提升,读取中文字符输出无法避免乱码问题。
int len3 = is.read(buffer); // 读取完毕返回-1
String rs = new String(buffer,0 ,len2); // 将读出的字节数组转换为字符串(读取多少倒出多少)
// 如何使用字节输入流读取中文内容输出不乱码呢?
// 方式一: 定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。
File f = new File("file-io-app/src/data03.txt");
byte[] buffer = new byte[(int) f.length()]; // 定义一个字节数组与文件的大小刚刚一样大。
int len = is.read(buffer);
System.out.println(new String(buffer));
// 方式二: 官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中
byte[] buffer = is.readAllBytes(); // 读取全部字节数组
System.out.println(new String(buffer));
FileOutputStream
OutputStream os = new FileOutputStream("file-io-app/src/out04.txt" , true); // 追加数据管道
OutputStream os = new FileOutputStream("file-io-app/src/out04.txt"); // 先清空之前的数据,写新数据进入
os.write('a'); // 写一个字节
byte[] buffer = {'a' , 97, 98, 99};
byte[] buffer2 = "我是中国人".getBytes();
os.write(buffer); // 写一个字节数组
os.write("\r\n".getBytes());// 换行
os.write(buffer, 0 , 3); // 写一个字节数组的一部分
os.flush(); // 写数据必须,刷新数据 可以继续使用流
os.close(); // 释放资源,包含了刷新的!关闭后流不可以使用了
字符流
FileReader
// 创建一个字符输入流管道与源文件接通
Reader fr = new FileReader("file-io-app\\src\\data06.txt");
int code = fr.read(); // 读取一个字符返回,没有可读的字符了返回-1,每次读取一个字符性能较慢
System.out.print((char)code);
// 2、用循环,每次读取一个字符数组的数据
char[] buffer = new char[1024]; // 1K字符
int len;
while ((len = fr.read(buffer)) != -1) {
String rs = new String(buffer, 0, len); // 每次读取一个字符数组,读取的性能得到了提升,读取中文字符输出不会乱码
System.out.print(rs);
}
FileWriter
// 创建一个字符输出流管道与目标文件接通
Writer fw = new FileWriter("file-io-app/src/out08.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
Writer fw = new FileWriter("file-io-app/src/out08.txt", true); // 追加管道
fw.write('a'); // 写一个字符
fw.write("abc我是中国人"); // 写一个字符串
fw.write("abc我是中国人", 0, 5); // 写字符串的一部分
har[] chars = "abc我是中国人".toCharArray();
fw.write(chars); // 写一个字符数
fw.write(chars, 3, 5); // 写字符数组的一部分
fw.write("\r\n"); // 换行
fw.flush(); // 刷新后流可以继续使用
fw.close(); // 关闭包含刷线,关闭后流不能使用
缓冲流
BufferedInputStream/BufferedOutputStream
InputStream is = new FileInputStream("D:\\resources\\newmeinv.jpeg"); // 创建一个字节输入流管道与原视频接通
InputStream bis = new BufferedInputStream(is); // 把原始的字节输入流包装成高级的缓冲字节输入流
OutputStream os = new FileOutputStream("D:\\resources\\newmeinv222.jpeg"); // 创建一个字节输出流管道与目标文件接通
OutputStream bos = new BufferedOutputStream(os); // 把字节输出流管道包装成高级的缓冲字节输出流管道
BufferedReader/BufferedWriter
try (
// 创建一个文件字符输入流与源文件接通。
Reader fr = new FileReader("io-app2/src/data01.txt");
// 把低级的字符输入流包装成高级的缓冲字符输入流。
BufferedReader br = new BufferedReader(fr);
){
String line;
while ((line = br.readLine()) != null){ // 读取一行数据返回,如果读取没有完毕,无行可读返回null
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// 创建一个字符输出流管道与目标文件接通
Writer fw = new FileWriter("io-app2/src/out02.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
//Writer fw = new FileWriter("io-app2/src/out02.txt", true); // 追加数据
BufferedWriter bw = new BufferedWriter(fw); // 包装成高级字符输出流, API与文件字符输出流FileWriter保持一致
bw.newLine(); // 换行(新增功能)
转换流
InputStreamReader
// 字符输入转换流InputStreamReader作用:解决字符流读取不同编码乱码的问题,可以把原始的字节流按照指定编码转换成字符输入流。
InputStream is = new FileInputStream("D:\\resources\\data.txt");
// 把原始字节流转换成字符输入流
Reader isr = new InputStreamReader(is , "GBK"); // 以指定的GBK编码转换成字符输入流 完美的解决了乱码问题
OutputStreamWriter
// 字符输出转换流OutputStreamWriter 可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码!
OutputStream os = new FileOutputStream("io-app2/src/out03.txt"); // 定义一个字节输出流
// 把原始的字节输出流转换成字符输出流
Writer osw = new OutputStreamWriter(os , "GBK"); // 指定GBK的方式写字符出去
BufferedWriter bw = new BufferedWriter(osw); // 把低级的字符输出流包装成高级的缓冲字符输出流。
bw.write("我爱中国~~");
bw.close();
打印流
PrintStream/PrintWriter
// 创建一个打印流对象
// PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt"));
// PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt" , true)); // 追加数据,在低级管道后面加True
// PrintStream ps = new PrintStream("io-app2/src/ps.txt" );
new PrintWriter(new File("io-app2/src/ps.txt"));
PrintWriter ps = new PrintWriter("io-app2/src/ps.txt"); // 打印功能上与PrintStream的使用没有区别
ps.println(97);
ps.println('a');
ps.println(23.3);
ps.println(true);
ps.println("我是打印流输出的,我是啥就打印啥");
ps.close();
// 改变输出语句的位置(重定向)
PrintStream ps = new PrintStream("io-app2/src/log.txt");
System.setOut(ps); // 把系统打印流改成我们自己的打印流
资源释放
try-catch-finally
public class TryCatchFinallyDemo1 {
public static void main(String[] args) {
InputStream is = null;
OutputStream os = null;
try {
// System.out.println(10/ 0);
// 1、创建一个字节输入流管道与原视频接通
is = new FileInputStream("file-io-app/src/out04.txt");
// 2、创建一个字节输出流管道与目标文件接通
os = new FileOutputStream("file-io-app/src/out05.txt");
// 3、定义一个字节数组转移数据
byte[] buffer = new byte[1024];
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0 , len);
}
System.out.println("复制完成了!");
// System.out.println( 10 / 0);
} catch (Exception e){
e.printStackTrace();
} finally {
// 无论代码是正常结束,还是出现异常都要最后执行这里
System.out.println("========finally=========");
try {
// 4、关闭流。
if(os!=null)os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(is != null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(test(10, 2));
}
public static int test(int a , int b){
try {
int c = a / b;
return c;
}catch (Exception e){
e.printStackTrace();
return -111111; // 计算出现bug.
}finally {
System.out.println("--finally--");
// 哪怕上面有return语句执行,也必须先执行完这里才可以!
// 开发中不建议在这里加return ,如果加了,返回的永远是这里的数据了,这样会出问题!
return 100;
}
}
}
try-with-resource
public class TryCatchResouceDemo2 {
public static void main(String[] args) {
try (
// 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
// 1、创建一个字节输入流管道与原视频接通
InputStream is = new FileInputStream("file-io-app/src/out04.txt");
// 2、创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");
// int age = 23; // 这里只能放资源(资源都是实现了Closeable/AutoCloseable接口的类对象)
MyConnection connection = new MyConnection(); // 最终会自动调用资源的close方法
)
{
// 3、定义一个字节数组转移数据
byte[] buffer = new byte[1024];
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0 , len);
}
System.out.println("复制完成了!");
} catch (Exception e){
e.printStackTrace();
}
}
}
class MyConnection implements AutoCloseable{
@Override
public void close() throws IOException {
System.out.println("连接资源被成功释放了!");
}
}
// JDK 9释放资源的方式
public class TryCatchResouceDemo3 {
public static void main(String[] args) throws Exception {
// 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
// 1、创建一个字节输入流管道与原视频接通
InputStream is = new FileInputStream("file-io-app/src/out04.txt");
// 2、创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");
try ( is ; os ) {
// 3、定义一个字节数组转移数据
byte[] buffer = new byte[1024];
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0 , len);
}
System.out.println("复制完成了!");
} catch (Exception e){
e.printStackTrace();
}
}
}

浙公网安备 33010602011771号