File
- 操作文件和文件夹
分隔符
//路径分隔符 win 分号; linux/os 冒号:
System.out.println(File.pathSeparator);
System.out.println(File.pathSeparatorChar);
//名称分割符 win 反斜杠\ linux/os 正斜杠/
System.out.println(File.separator);
System.out.println(File.separatorChar);
路径
- 绝对路径,完整的路径,以盘符开始的路径
- 相对路径,简化的路径,相对的是当前项目的根目录
- 路径不区分大小写
- win中,路径中的名称分隔符使用反斜杠,字符串中用两个反斜杠转义
构造
- 不管真假
File file = new File("/Users/apple/Desktop/java/test.txt");
System.out.println(file); // 重写了toString
- 两个参数的构造,父路径和子路径可以单独书写,使用灵活,会自动补充斜杠
File file1 = new File("User/apple/Desktop/java", "test/text.txt");
- 两个参数,父路径是
File类型,可以用File的方法,对路径进行操作,在创建对象
File parentFile = new File("User/apple/Desktop");
File file2 = new File(parentFile, "java/test/text.txt");
获取
- 获取绝对路径,相对路径也会转换为绝对路径
System.out.println(file.getAbsolutePath());
- 获取构造方法传递的路径,
toString调用的就是getPath()
System.out.println(file.getPath());
- 获取构造方法传递路径的结尾
System.out.println(file.getName());
- 获取文件的大小,字节为单位,文件不存在返回0
System.out.println(file.length());
判断
- 如果不存在都返回
false - 是否存在
System.out.println(file.exists());
- 是否是目录
System.out.println(file.isDirectory());
是否为文件
System.out.println(file.isFile());
创建和删除
- 创建文件
- 文件不存在,创建文件,返回true;文件存在,不会创建,返回false
- 路径必须存在,不然会抛出异常,必须处理
System.out.println(file.createNewFile());
- 创建文件夹,不会抛出异常
//单级
System.out.println(file.mkdir());
//多级
System.out.println(file.mkdirs());
- 删除,文件和文件夹都可以删除
- 删除成功返回true;失败返回false
- 文件夹中有内容,不管是什么内容,都不会删除,返回false
System.out.println(file.delete());
遍历
list方法和listFile方法遍历的是构造方法的路径- 如果给出的路径不存在/如果路径不是一个目录,抛出空指针异常
- 可以获取隐藏文件/隐藏文件夹
//字符串数组
String[] arr = file.list();
for (String s : arr) {
System.out.println(s);
}
//返回的字符串数组转换成File数组
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1);
}
文件过滤器
FileFilter用来过滤文件的,针对File对象;其中的accept方法,返回true,会把传递的过去的File对象保存在File数组中;返回false就不会FilenameFilter针对文件名称的过滤,dir参数遍历的文件目录,name目录下的每一个文件/文件夹的名称- 两个过滤器接口没有实现类,需要我们自己实现,定义过滤的规则
listFiles方法,会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹,封装为File对象;会调用参数传递的过滤器的accept方法;会把遍历得到的每一个File对象,传递给accept方法的参数pathname- FileFilter
public static void getAllFile(File dir) {
//匿名内部类
File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
//文件夹不过滤
return pathname.getName().toLowerCase().endsWith(".png") || pathname.isDirectory();
}
});
//Lambda
File[] files1 = dir.listFiles(pathname -> pathname.getName().toLowerCase().endsWith(".png")
|| pathname.isDirectory());
for (File file : files1) {
if (file.isDirectory()) {
getAllFile(file);
} else {
System.out.println(file);
}
}
}
- FilenameFilter
File[] files2 = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory() || name.toLowerCase().endsWith(".png");
}
});
File[] files3 = dir.listFiles(((d, name) -> new File(d, name).isDirectory()
|| name.toLowerCase().endsWith(".png")));
递归
- 直接递归,自己调用自己
- 间接递归,A调用B,B中包含A
- 一定要有条件限定,次数不能太多,保证递归能停下来,否则会发生栈内存溢出
- 构造方法,禁止递归
- 前提,调用方法主体不变,每次调用方法的参数不同,可以使用递归
public static int sum(int n) {
//中断递归
if (n == 1) {
return 1;
}
return n + sum(n - 1);
}
- 方法调用的过程
IO
- 流:数据(字符、字节) 1个字符=2个字节 1个字节=8个二进制位
- 输入,把硬盘的数据,读取到内存中
- 输出,把内存中的数据,写入到硬盘中
字节流
- 一切文件数据,都是字节
- 要先关闭写的,在关闭读的
fileOutputStream.close();
fileInputStream.close();
- 使用字节流读取中文文件,一个中文,GBK占用两个字节;UTF-8占用三个字节,容易出现乱码
字节输出流
- OutputStream
- 写入的原理,java程序->JVM->OS(操作系统)->OS调用写数据的方法->写入文件
- 写入
File file = new File("/Users/apple/Desktop/java/test.txt");
//自动创建
FileOutputStream fileOutputStream = new FileOutputStream(file);
//十进制整数转换成二进制,0-127查询ASCII码,其他值查询系统默认编码表(GBK中文)
fileOutputStream.write(130);
String outputStr = "hello,world";
fileOutputStream.write(outputStr.getBytes());
//写一部分,起始,长度
fileOutputStream.write(outputStr.getBytes(), 3,4);
//如果第一个字节是负数,第二个字节会和第一个字节组成一个中文
byte[] bytes = {-46,45,-12,43,-10,90,-44,-45}; //噎臬鲒杂
fileOutputStream.write(bytes);
//关闭
fileOutputStream.close();
- 续写,
append追加写开关,true创建对象不会覆盖原文件,继续在文件的末尾追加写数据
FileOutputStream fileOutputStream = new FileOutputStream(file, true);
- 换行,win
\r\n,linux\n,mac\r
fileOutputStream.write("\r".getBytes());
字节输入流
- 读取的原理,java程序->JVM->OS(操作系统)->OS调用读数据的方法->写入文件
FileInputStream fileInputStream = new FileInputStream("day3-code/src/test.txt");
int i = 0;
//while循环读取
//读取一个字节并返回,读取到文件的末尾返回-1,指针向后一位
while ((i = fileInputStream.read()) != -1) {
System.out.print((char) i);
}
fileInputStream.close();
- 一次读取多个字节,返回读取到的有效字节个数,参数存放读到的字节,起到缓冲的作用,一般长度为1024
byte[] bytes = new byte[10];
int len = fileInputStream.read(bytes);
System.out.println(len);
System.out.println(Arrays.toString(bytes));
System.out.println(new String(bytes));
- 循环读取多个字节
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0,len));
System.out.println(len);
}
- 读取所有
byte[] bytes = fileInputStream.readAllBytes();
String s = new String(bytes);
System.out.println(s);
字符流
字符输入流
- 把硬盘文件的数据以字符的方式读取到内存中
- 一个个字符读取
FileReader fileReader = new FileReader("day3-code/src/test.txt");
int len = 0;
while ((len = fileReader.read()) != -1) {
System.out.print((char) len);
}
fileReader.close();
- 读取多个
int len = 0;
char[] chars = new char[1024];
while ((len = fileReader.read(chars)) != -1) {
System.out.println(new String(chars,0,len));
}
字符输出流
- 写入到内存缓存区中,调用
flush和close才会写入
FileWriter fileWriter = new FileWriter("day3-code/src/test.txt",true);
fileWriter.write("hello.你好.123.abc");
fileWriter.flush();
fileWriter.close();
- 续写
FileWriter fileWriter = new FileWriter("day3-code/src/test.txt",true);
- 其他写入方式
fileWriter.write("hello.你好.123.abc",2,10);
fileWriter.flush();
char[] chars = {'a', 'b', 'c', 'w', 'e', '\r'};
fileWriter.write(chars);
fileWriter.flush();
fileWriter.write(chars,3,2);
close和flush
- flush,刷新缓冲区,流对象可以继续使用
- close,先刷新缓冲区,然后通知系统释放资源,流对象不可以再使用
try-with-resource
- 处理IO异常
- 前
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("dasday3-code/src/test.txt",true);
fileWriter.write("hello.你好.123.abc\r");
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
//如果创建失败了,fileWriter默认值为null
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("fileWriter 为 null");
}
}
- JDK7新,try中后面的()可以定义流对象,流对象的作用域就在try中有效,try执行完毕自动释放
close
try (FileWriter fileWriter = new FileWriter("day3-code/src/test.txt",true);){
fileWriter.write("hello.你好.123.abc\r");
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
- JKD9,比较麻烦,也要
throws
FileWriter fileWriter = new FileWriter("day3-code/src/test.txt",true);
try (fileWriter){
fileWriter.write("hello.你好.123.abc\r");
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
Properties
- 继承
Hashtable,已经被淘汰了,但是这个子类唯一和IO流相结合的集合 - 双列结合,键值默认都是字符串
- 基本使用
Properties properties = new Properties();
//存储
properties.setProperty("name", "zhangsan");
properties.setProperty("age","18");
properties.setProperty("address","beijing");
//stringPropertyNames 返回带有键的set集合
for (String stringPropertyName : properties.stringPropertyNames()) {
//获取值
System.out.println(properties.getProperty(stringPropertyName));
}
- 把集合中的临时数据持久化写入到硬盘中存储
//字节输出流,不能写入中文,中文显示的/Unicode;字符输出流,可以写中文
//参数 comments,解释说明保存的文件,不能使用中文,一般传入空字符串
FileWriter fileWriter = new FileWriter("day3-code/src/properties.txt");
//FileOutputStream fileOutputStream = new FileOutputStream("day3-code/src/properties.txt");
properties.store(fileWriter, "properties");
- 把硬盘中的数据(键值对)读取到集合中使用,文件中用空格和等号分隔都可以读出来
//字节输入流,不能读中文;字符输入流,可以读中文
FileReader fileReader = new FileReader("day3-code/src/properties.txt");
Properties properties = new Properties();
//读取文件
properties.load(fileReader);
for (String stringPropertyName : properties.stringPropertyNames()) {
System.out.println(stringPropertyName + " = " + properties.getProperty(stringPropertyName));
}
缓冲流
- 增强基本流的效率
字节缓冲输出流
- 增加一个缓冲区,提高写入效率
- 参数size,指定缓冲流内部缓冲区的大小
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("day3-code/src/test.txt",true),1024);
bufferedOutputStream.write("hello.world".getBytes());
//需要手动调用flush才会刷新
bufferedOutputStream.close();
字节缓冲输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("day3-code/src/test.txt"));
int len = 0;
byte[] bytes = new byte[1024];
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
bufferedInputStream.close();
字符缓冲输出流
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("day3-code/src/test.txt", true));
//行分隔符
bufferedWriter.newLine();
bufferedWriter.write("张三李四王五找刘");
bufferedWriter.newLine();
bufferedWriter.close();
字符缓冲输入流
BufferedReader bufferedReader = new BufferedReader(new FileReader("day3-code/src/test.txt"));
char[] chars = new char[1024];
int len = 0;
while ((len = bufferedReader.read(chars)) != -1) {
System.out.println(new String(chars, 0 ,len));
System.out.println(len);
}
bufferedReader.close();
- 读一行文本
String s = "";
while ((s = bufferedReader.readLine()) != null) {
System.out.println(s);
}
转换流
- 对应规则
- 编码 字符->字节
- 解码 字节->字符
- 中国 GBK
- 国际 Unicode 常见UTF-8
FileReader可以读取默认格式的UTF-8,但是读取GBK报错
写入转换流
- 参数一 OutputStream对象;参数二 指定编码,默认为utf-8
OutputStreamWriter gbk = new OutputStreamWriter(new FileOutputStream("day3-code/src/test1.txt"), "gbk");
gbk.write("你好世界");
gbk.flush();
gbk.close();
读取转换流
InputStreamReader gbk = new InputStreamReader(new FileInputStream("day3-code/src/test1.txt"), "gbk");
int len = 0;
char[] chars = new char[1024];
while ((len = gbk.read(chars)) != -1) {
System.out.println(new String(chars,0,len));
}
gbk.close();
序列化和反序列化
- 序列化 把对象以流的方式写入到文件中保存,对象的序列化
- 反序列化,把文件中的字节对象读取到java程序中,对象的反序列化
- 类中要实现
Serializable序列化标记型接口 - 被static修饰的成员变量,是不能被序列化的
transient关键字修饰的成员变量,不能被序列化
序列化
Person p1 = new Person("zhangsan", 18);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("day3-code/src/person.txt"));
objectOutputStream.writeObject(p1);
objectOutputStream.close();
反序列化
- 要先关闭流,在输出
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("day3-code/src/person.txt"));
Object o = objectInputStream.readObject();
objectInputStream.close();
System.out.println(o);
序列号
- 如果类发生改变,就会重新生成一个类序列号
- 类中手动添加序列号
private static final long serialVersionUID = 30L;
打印流
- 只负责数据的输出,不负责读取
- 永远不会抛出异常
- 如果使用父类
write输出数据,那么查看数据的时候会查询编码表 - 如果使用自己特有的方法
print/println输出,数据原样输出
PrintStream printStream = new PrintStream("day3-code/src/print.txt");
printStream.write(97);
printStream.println(97);
printStream.print("3i129ndaowdjo");
printStream.print(true);
//改变 System.out.println 输出语句的目的地
System.setOut(printStream);
System.out.println("\rhello world");
printStream.close();