File和流二
目录
一、File基本知识点
1. File
构造方法:
File(String pathname)
File(String parent, String child)
File(File parent, String child)
相对路径和绝对路径
成员方法:
创建功能
createNewFile()
mkdir()
mkdirs()
删除功能
delete()
1. 不走回收站 2. 只能删除空文件夹
判断功能
exists()
isFile()
isDirectory()
获取功能
getAbsolutePath()
getPath()
getName()
length() : 获取文件的字节个数, 不能获取文件夹(数据有问题)
2. 递归
概述: 方法自己调用自己
注意事项: 1. 必须有出口 2. 就算有出口次数不能过多
递归求阶乘:
public void fun(int n) {
if (n == 1) {
return 1;
}
return n * fun(n - 1);
}
3. 字节输入流
FileInputStream
构造方法:
FileInputStream(File file)
FileInputStream(String name)
输入流关联的文件如果不存在, 会报错
成员方法:
read() : 读取一个字节
如果读取到末尾, 返回-1
read(byte[] arr) : 将自己读取到字节数组中
返回读取到有效的字节个数
如果读取到末尾, 返回-1
4. 字节输出流
FileOutputStream
构造方法:
FileOutputStream(File file)
FileOutputStream(String name)
输出流关联的文件不存在, 会创建
成员方法:
write(int ) : 写出一个字节
writer(byte[] arr, int off, int len)
写出arr字节数组中, 从off索引开始的len个字节
5. 字符流
字符流的应用场景:
字符流可以拷贝纯文本文件, 但是也不用, 因为会使用字节流进行拷贝.
如果只读取纯文本文件可以使用字符流
如果值写出纯文本文件可以使用字符流
Writer: 有一个长度为1024的字符数组(缓冲区)
close()和flush()
close() : 关流, 但是在关流之前会刷出一次缓冲区
flush() : 刷出一次缓冲区
关于文件删除说明
java.io.File里的delete操作很实用也很常用,可以用来删除单独的文件和某一目录。但有时候会出现delete失败的情况,出现这种情况的原因一般有以下几种:
1、删除时还有其他程序在使用该文件,此时将无法正确删除
2、没有close关闭和该文件相关的所有输入输出流等,导致无法删除(这一点是最容易忘记的,你犯的可能就是这一条)
3、当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败。这里可以采用listFiles对目录下的文件或者目录进行处理。
下面给出一个具体的例子:
File f = new File(path);
DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));
if (f.exists()) {
System.out.println(f.getAbsoluteFile());
if (!f.delete()) {
System.out.println("请关闭使用该文件的所有进程或者流!!");
} else {
System.out.println(f.getName()+" 成功被删除!");
}
}
此时f是无法delete的,即f.delete()将返回false,原因就在于没有关闭dos.所以需要在if之前加入一句f.close(),这样就可以删除成功了。
File f = new File(path);
DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));
if (f.exists()) {
System.out.println(f.getAbsoluteFile());
if (!f.delete()) {
System.out.println("请关闭使用该文件的所有进程或者流!!");
} else {
System.out.println(f.getName()+" 成功被删除!");
}
}
二. 属性集
- Properties
1. 构造方法
public Properties()
2. 成员方法
- 作为双列集合的使用
public Object setProperty(String key, String value)
添加键值对
public String getProperty(String key)
根据键获取值
public class Demo01 {
public static void main(String[] args) {
// 创建了一个属性集的对象(双列集合)
// Properties的键和值有默认的数据类型 : String
Properties p = new Properties();
// 添加
p.setProperty("username", "zhangsan");
p.setProperty("password", "123");
p.setProperty("password", "456");
// 获取
String username = p.getProperty("username");
System.out.println(username);
System.out.println(p);
}
}
- 作为配置文件使用
public void load(InputStream inStream)
: 加载 -> 从输入流中读取属性列表(键和元素对)。
: 从输入流关联的配置文件中获取键值对信息
public void store(OutputStream out,
String comments) // 注释
: 将此 Properties 表中的属性列表(键和元素对)写入输出流
: 将此 Properties中的键值对, 写到配置文件中
public class Demo03 {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
// 输入流关联配置文件
FileInputStream fis = new FileInputStream("day13-code\\aaa.properties");
// 加载
p.load(fis);
fis.close();
String username = p.getProperty("username");
String password = p.getProperty("password");
System.out.println(username + "---" + password);
}
}
三. 缓冲流
缓冲区 : 数组
1. 字节流
缓冲流的输入输出流:
- 带缓冲区的字节输入流 : BufferedInputStream
- 带缓冲区的字节输出流 : BufferedOutputStream
构造方法
public BufferedInputStream(InputStream in)
public BufferedOutputStream(OutputStream out)
带缓冲的流一定要进行刷新操作,不然可能会导致其最终效果不符合实际情况
2. 字符流
带缓冲区的字符输入流
- BufferedReader
构造方法
public BufferedReader(Reader in)
成员方法
public String readLine()
: 读取一行, 一行的结束是以换行符为结束标记(没有获取到换行符)
如果读取到文件的末尾, 返回null
带缓冲区的字符输出流
- BufferedWriter
构造方法
public BufferedWriter(Writer out)
成员方法
public void newLine() : 写出跨平台的换行符
缓冲流的基本拷贝
public class Demo01 {
public static void main(String[] args) throws IOException {
/*FileInputStream fis = new FileInputStream("day13-code\\aaa.txt");
BufferedInputStream bis = new BufferedInputStream(fis);*/
// 创建带缓冲区的字节输入流(高效字节输入流)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day13-code\\test.mp4"));
// 创建带缓冲区的字节输出流(高效字节输出流)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day13-code\\copyTest.mp4"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
bos.close();
bis.close();
}
}
读取一行
public class Demo02 {
public static void main(String[] args) throws IOException {
// 创建高效字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("day13-code\\aaa.txt"));
// 读取一行
String line = br.readLine();
System.out.println(line);
// 关流
br.close();
}
}
写出换行
public class Demo03 {
public static void main(String[] args) throws IOException {
// write once run anywhere
BufferedWriter bw = new BufferedWriter(new FileWriter("day13-code\\bbb.txt"));
bw.write("天将降大任于斯人也");
bw.newLine();
bw.write("必现苦其心志");
bw.newLine();
bw.write("劳其筋骨");
bw.newLine();
bw.write("饿其体肤");
bw.newLine();
bw.write("空乏其身");
bw.newLine();
bw.write("行拂乱其所为");
bw.newLine();
bw.write("所以动心忍性");
bw.newLine();
bw.write("增益其所不能");
bw.close();
}
}
一行一行的拷贝
public class Demo04 {
public static void main(String[] args) throws IOException {
// 创建输入输出流对象
BufferedReader br = new BufferedReader(new FileReader("day13-code\\bbb.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("day13-code\\copyBbb.txt"));
String line;
// 不断的读取
while ((line = br.readLine()) != null) {
// 写出读取到的一行
bw.write(line);
// 换行
bw.newLine();
}
// 关流
bw.close();
br.close();
}
}
四. 转换流
转换流 --- 字符流
1. 输入流
- InputStreamReader
- 是字节流通向字符流的桥梁, 可以通过指定的字符集, 将字节转换成字符
构造方法
public InputStreamReader(InputStream in, String charsetName)
charsetName: 字符集的名字
public InputStreamReader(InputStream in) : 使用默认字符集, 将字节转换成字符
2. 输出流
- OutputSreamWriter
- 是字符流通向字节流的桥梁, 可以通过指定的字符集, 将字符转换成字节
构造方法
public OutputStreamWriter(OutputStream out, String charsetName)public OutputStreamWriter(OutputStream out) : 使用默认字符集, 将字符转换成字节
转换流拷贝不同字符集的文件
public class Demo02 {
public static void main(String[] args) throws IOException {
// 创建转换流的输入流对象, 指定字符集(gbk)
InputStreamReader isr = new InputStreamReader(new FileInputStream("g:\\gbk.txt"), "gbk");
// 创建转换流的输出流对象, 指定字符集(utf-8)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day13-code\\utf-8.txt"), "utf-8");
int c;
while ((c = isr.read()) != -1) {
osw.write(c);
}
osw.close();
isr.close();
}
}
3. 转换流的其他应用场景
- 只能获取到字节流, 想要读取文件中的一行
- 字节流: FileInputStream
- 读取一行: BufferedReader
public class Demo03 {
public static void main(String[] args) throws IOException {
// 只有字节流
FileInputStream fis = new FileInputStream("day13-code\\aaa.txt");
// 将字节流转换成BufferedReader字符流 -> 字节流通向字符流的桥梁 -> InputStreamReader
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
System.out.println(br.readLine());
br.close();
}
}
- 自己完成键盘录入(不使用Scanner)
public class Demo04 { public static void main(String[] args) throws IOException { // BufferedReader InputStreamReader System.in(InputStream) BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 读取一行 String s = br.readLine(); System.out.println("获取到的字符串是: " + s); br.close(); }}
4. 打印流
public class Demo01 {
public static void main(String[] args) throws IOException {
// System.out : 标准的输出流 -> 默认指向控制台
// System.in : 标准的输入流 -> 默认指向控制台
// System.err: 标准错误输出流 -> 指向控制台, 打印出来的内容是红色的
Scanner sc = new Scanner(System.in);
// 打印是红色的
System.err.println("魑魅魍魉");
// 会打印到控制台
System.out.println("abc");
PrintStream ps = new PrintStream("day13-code\\ccc.txt");
// 修改打印流
System.setOut(ps);
// 这个会打印到ccc.txt中
System.out.println("abc");
ps.close();
}
}
五. 序列化流
是字节流
1. 输入流
- ObjectInputStream : 反序列化
- 对象输入流
构造方法
public ObjectInputStream(InputStream in)
成员方法
public final Object readObject()
2. 输出流
- ObjectOutputStream: 序列化
- 对象输出流
构造方法
public ObjectOutputStream(OutputStream out)
成员方法
public final void writeObject(Object obj)
String类型的序列化和反序列化
public class Demo01_String {
public static void main(String[] args) throws IOException {
String s = "哈哈哈";
// 创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day13-code\\object.txt"));
oos.writeObject(s);
oos.close();
}
}
// ==================================================================================
public class Demo02_String {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day13-code\\object.txt"));
// 读取
String s = (String) ois.readObject();
System.out.println(s);
ois.close();
}
}
自定义类型的序列化和反序列化
public class Demo03_Person {
public static void main(String[] args) throws IOException {
// 创建Person对象
Person p = new Person("高圆圆", 35);
// 创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day13-code\\object.txt"));
// NotSerializableException : 需要实现Serializable接口, 但是没实现
// StreamCorruptedException : 不小心修改了写出硬盘上的文件
// 写出
oos.writeObject(p);
oos.close();
}
}
// ====================================================================================
public class Demo04_Person {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day13-code\\object.txt"));
// ClassNotFoundException : 编译时异常, 未雨绸缪
// 找不到Xxx.class字节码文件
// 读取
Person p = (Person) ois.readObject();
System.out.println(p);
ois.close();
}
}
了解即可
- 序列化和反序列化操作的时候, 需要使用到对象的字节码文件(Xxx.class)
- transient修饰的内容可以不被序列化
六. 装饰设计模式
目标: 在不改变原有类中内容的前提下, 对类中的功能进行增强
完成这个目标的操作方式:
1. 装饰设计模式
2. 继承, 重写 3. 动态代理
从理论中来,到实践中去,最终回归理论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?