1.File类
1.1 概念引入
-
java.io.File类,文件与目标路径的抽象表示形式。主要用于文件和目录的创建、操作硬盘上的文件或文件夹。
-
绝对路径:从盘符开始的完整路径,在系统中具有唯一性。
-
相对路径:不是从盘否开始的路径,相对于某个目录的路径,在系统中不具有唯一性。
如果不指明相对的目录,则相对目录的默认相对位置为当前项目的根目录
1.2 构造方法
- public File(String pathname) : 以指定的路径名字符串创建File实例(绝对和相对路径均可)
- public File(String parent,String child) : 根据父路径字符串和子路径字符串创建File实例
- public File(File parent,String child) : 根据父路径文件对象和子路径字符串创建File实例
如果路径不存在文件或目录,并不会影响到File对象的创建,但该对象没有关联任一文件,使用时会报错
1.3 常用方法
1.3.1 获取功能
- String getAbsolutePath(); 获得此File对象的绝对路径字符串
- String getPath(); 获得此File对象的相对路径字符串
- String getName(); 获得此File对象表示的文件或文件夹名称
- Long length(); 获得此File对象表示的文件的大小(字节),但不能获得文件夹大小
- File getParentFile(); 获得父路径文件对象
1.3.2 判断功能
- public boolean exists(); 判断File对象表示的文件或文件夹是否存在
- public boolean isDirectory(); 判断是否是文件夹,是返回true,否则false(不存在也是false)
- public boolean isFile(); 判断是否是文件,是返回true,否则false(不存在也是false)
1.3.3 创建删除功能
- public boolean createNewFile();
当且仅当具有该名称的文件不存在时创建一个空的文件。存在不创建,且不能创建文件夹
- public boolean delete();
删除此File对象表示的文件或文件夹。删除文件夹时必须保证文件夹为空,否则无法删除
- public boolean mkdir();
创建由此File对象表示的文件夹,但只能创建单级文件夹。存在不创建,且不能创建文件
- public boolean mkdirs();
创建由此File对象表示的文件夹,可以创建多级文件夹。存在不创建,且不能创建文件
1.3.4 目录遍历
- 使用File对象调用下面两种方法进行遍历:
- public String[] list(); 获得File目录下的所有子文件或目录,并以字符串数组形式返回
上述方法一般比较少用
- public File[] listFiles(); 获取文件夹下所有的子文件或子文件夹,返回文件数组
上述方法比较常用。但注意使用上述方法时File需要关联一个文件夹,若关联文件则返回null
- 获得数组后遍历即可
- 注意:如果要获取该File对象表示的路经下的所有文件,需要利用递归的方法。
1.3.5 静态成员变量
- static String pathSeparator : 与系统相关的路经分割符
- Mac/Linux使用
:
,Window使用;
- static String separator : 与系统相关的名称分割符
- Mac/Linux使用
/
,Window使用\
2. IO流概念引入
2.1 IO的概念
- 数据的传输,以内存为基准可以分为输入input和输出output
- Java中的IO操作是java.io包下内容,输入叫做读取数据,输出叫做写出数据
2.2 分类
-
按数据流向分:
- 输入流:数据从其他设备读取到内存中的流
- 输出流:数据从内存中写到其他设备上的流
-
按数据类型分:
- 字节流:以字节为单位读写数据
- 字符流:以字符为单位读写数据
其超类如下:
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流(InputStream) | 字节输入流(OutputStream) |
字符流 | 字符输入流(Reader) | 字符输入流(Writer) |
不管是什么流,**底层**传输的始终为**二进制数据**!
3.字节流
- 所有类型的数据都可以用字节流传输
3.1 字节输出流(OutputStream)
-
所有字节输出流的父类(超类),是一个抽象类
-
基本的共性方法如下:
- void close(); 关闭此输出流并释放与之关联的所有系统资源 - void write(byte[] b); 从指定的字节数组中写入此输出流 - void write(byte[] b, int off, int len); 从指定的字节数组中输出一部分内容。off为数组写入时的起始索引,len为输出的字节个数 - abstract void write(int b); 根据b的值输出对应的一个字节
上述方法所有字节输出流都能使用
3.2 文件字节输出流(FileOutputstream)
- 将数据写出到文件的流
3.2.1 构造方法
- FileOutputStream (File file) : 根据文件对象创建字节输出流对象
- FileOutputStream (String name) : 根据文件路径字符串创建字节输出流对象
注意事项:(重要)
- 创建一个该流的对象必须传入一个文件路径,String name不是随便一个字符串;
- 该路径下存在文件会清空原有的文件数据(除非数据追加续写),若不存在则新建文件!!!!!
3.2.2 数据追加续写
-
创建新的输出流对象时保留原有文件的数据,不会清空
-
对构造方法进行调整:
- FileOutputStream(File file, boolean append) - FileOutputStream(String name, boolean append)
其中:boolean append为true则保留原数据并追加,false则清空原文件数据。默认是false
3.2.3 使用FileOutputstream写出数据到文件
-
常用方法:
- void write(byte[] b); 从指定的字节数组中写入此输出流 - void write(byte[] b, int off, int len); 从指定的字节数组中写出指定长度。 - void write(int b); 根据b的值写出对应的一个字节(按ASCII码转换)(b的取值范围不能超出-128~127)
示例代码:
public class Test01 {
public static void main(String[] args) throws IOException {
//创建File类对象
File f = new File("Java/study/test01.txt");
FileOutputStream fos = new FileOutputStream(f,true);
//按单个字节输出
fos.write(97);//输出的是a
//按一个字符数组输出
byte[] b = {'a','b','b','c'};
fos.write(b);
//另外一种写法
String str = "I love you";
fos.write(str.getBytes());
fos.write("\r\n".getBytes());//输出换行,记得也要getBytes()
//一定要关流
fos.close();
}
}
3.2.4 输出换行
-
Windows换行符:\r\n
-
linux:\n
-
mac:\r
回车符\r:回到一行的开头;换行符\n:下一行
3.3 字节输入流(InputStream)
-
所有字节输入流的父类(超类),是一个抽象类
-
基本的共性方法如下:
- void close(); 关闭此输入流并释放与之关联的所有系统资源 - abstract void read(); 从输入流中读取数据的下一个字节,返回读取的数值。读到末尾分返回-1 - int read(byte[] b); 从输入流中读取一些字节数,并将存储到字节数组b中,读到末尾返回-1 - int read(byte[] b, int off, int len); 输入部分字节到数组中。off为数组写入时的起始索引,len为输出的字节个数
上述方法所有字节输入流都能使用
3.4 文件字节输入流(FileInputStream)
- 从文件中读取数据
3.4.1 构造方法
- FileInputStream(String name); 根据文件对象创建字节输入流
- FileInputStream(File file); 根据文件路径字符串创建字节输入流
注意事项:(重要)
- 目标文件不存在,则抛出异常,不会新建;
- 关联的目标文件必须是文件,不能是文件夹
3.4.2 使用FileInputstream从文件读取数据
-
常用方法:
- int read(); 每次读取一个字节的数据。读到末尾分返回-1 - int read(byte[] b); 每次读取数组长度个字节到数组中,返回读到的有效字节个数,读到末尾返回-1
示例代码:
public class Test02 {
public static void main(String[] args) throws IOException {
File f = new File("Java/study/test02.txt");
//创建字节输入流
FileInputStream fis = new FileInputStream(f);
/*固定套路*/
//创建一个字节数组,JVM将一次按照该数组的长度的保存字节到数组中,超过长度的在下一次读取。(利用循环)
// 1024是固定套路,一次读取的字节数刚好是1kb=1024b,记住即可
byte[] buf = new byte[1024];
int len;
/*
read(byte[] buf)是将一次读取到(即数组长度)的每个字节数据存放到buf数组,返回值是本次存放到数组的个数,末尾返回-1
注意与read()的区分!!
*/
while ((len = fis.read(buf)) != -1) {
/*利用String的构造方法:public String(byte bytes[], int offset, int length)
来保证不会因为剩余字节个数不够填字节数组的长度而导致数组后面的字节未被覆盖新值而重复读入*/
System.out.println(new String(buf,0,len));
}
//一定要关闭流
fis.close();
}
}
3.5 文件字节流示例案例
需求:文件复制
public class Test03 {
public static void main(String[] args) throws IOException{
//创建原文件的文件对象
File source = new File("Java/study/resource.txt");
//创建目标文件的文件对象
File target = new File("Java/study/target.txt");
//创建字节输入、出流
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(target);
/*固定套路*/
//先读取
byte[] buf = new byte[1024];
int len = -1;
while ((len = fis.read(buf)) != -1) {
//输出
fos.write(buf,0,len); //同样是为了避免不够字节数组长度的部分字节重复写出
}
//一定要关闭流
fis.close();
fos.close();
System.out.println("复制完毕");
}
}
4.字符流
- 专门用于处理文本文件,不能用于图像或者视频之类的数据传输
4.1 字符输出流(Writer)
-
所有字符输出流的父类(超类),是一个抽象类
-
基本的共性方法如下:
- abstract void close(); 关闭此输出流并释放与之关联的所有系统资源 - abstract void write(int c); 根据b的值输出对应的一个字符 - void write(char[] cbuf); 从指定的字符数组中写入此输出流 - void write(char[] cbuf, int off, int len); 从指定的字节数组中输出一部分内容。off为数组写入时的起始索引,len为输出的字符个数 - void write(String str); 写出一个字符串 - void write(String str, int off, int len); 从指定的字符串中输出一部分内容。off为字符串写入时的起始索引,len为输出的字符个数
上述方法所有字符输出流都能使用
4.2 文件字符输出流(FileWriter)
- 写出字符到文件
4.2.1 构造方法
- FileWriter (File file) : 根据文件对象创建输出流对象,默认清空原文件
- FileWriter (String name) : 根据文件路径字符串创建输出流对象,默认清空原文件
- FileWriter (File file,boolean append)
根据文件对象创建输出流对象,根据append的值是否保留
- FileWriter (String name,boolean append)
根据文件路径字符串创建输出流对象,根据append的值是否保留
注意事项:(重要)
1、目标文件不存在不会新建文件,而直接报错
4.2.2 使用FileWriter写出到文件
1、写出单个字符:
write(int b); 根据整数对应的ASCII输出字符
2、写出字符数组:
- void write(char[] cbuf);
- void write(char[] cbuf, int off, int len);
3、写出字符串:
- void write(String str);
- void write(String str, int off, int len);
4、写出换行
write("\r\n")
4.2.3 示例范例
需求:控制台输入信息,信息保存在文件中,可多次输出直至输入end
public class Test04 {
public static void main(String[] args) throws IOException {
//创建文件对象
File f = new File("Java/study/test04.txt");
Scanner sc = new Scanner(System.in);
//使用字符输出流,在循环外创建,避免浪费资源
FileWriter fw = new FileWriter(f,true);
while (true) {
System.out.println("请输入信息(输入end时将结束输入):");
String message = sc.nextLine();
if (!message.equals("end")){
fw.write(message + "\r\n");
} else {
System.out.println("再见");
break;
}
}
//记得关闭流
fw.close();
}
}
4.3 字符输入流(Reader)
-
所有字符输入流的父类(超类),是一个抽象类
-
基本的共性方法如下:
- abstract void close(); 关闭此输入流并释放与之关联的所有系统资源 - int read(); 从输入流中读取数据的下一个字符,返回读取的数值。读到末尾分返回-1 - int read(char[] cbuf); 从输入流中读取一些字符,并将存储到字符数组cbuf中,读到末尾返回-1
上述方法所有字符输入流都能使用
4.4 文件字符输入流(FileReader)
- 读取字符文件,构造是使用默认的码表和默认字节缓冲区
4.4.1 构造方法
- FileReader(String name); 根据文件对象创建字符输入流
- FileReader(File file); 根据文件路径字符串创建字符输入流
注意事项:(重要)
- 目标文件不存在,则抛出异常,不会新建;
- 关联的目标文件必须是文件,不能是文件夹
4.4.2 使用FileReader从文件中读取
1、读取单个字符:
read(int b); 根据整数对应的ASCII读取字符
2、写出字符数组:
- int read(char[] cbuf);
5. IO异常处理
1、JDK1.7以前的处理:
try...catch...finally...
- 在try语句中创建流和执行流代码
- 在finally语句中关闭流
2、JDK1.7的处理:
try-with-resource语句:确保每个资源在语句结束时关闭
-
格式:
try (创建流对象语句,如果多个,使用';'隔开) { // 执行流的代码 } catch (IOException e) { e.printStackTrace(); }
3、JDK1.9的处理:
-
先创建流对象;
-
执行下列语句:
try (流对象1、流对象2...) {
// 执行流的代码
} catch (IOException e) {
e.printStackTrace();
}
- 好处:流对象在try语句后面还能使用
- 坏处:流对象创建时仍要声明异常
6. 属性集(Properties)
6.1 概述
- java.util.Properties类,继承Hashtable,实现了Map接口,也是一个双列集合。
6.2 特点
-
键值默认是字符串类型,不需指定类型;
-
有与流技术相结合的方法:
- 可直接将集合的数据保存到文件中;
- 可从文件中读取数据到集合中;
-
其余与Map相同
6.3 属性文件要求:
- 命名时后缀是
.properties
; - 每一个键值对占据一行,格式为键=值;
- 文件中可使用注释,注释要以
#
开头
6.4 常用方法
- Object setProperty(String key, String value);添加键值对
1'如果键存在,新值替换旧值,返回旧值
2'若键不存在,则返回null,并创建键值对
- String getProperty(String key); 根据键获得值,返回键对应的值,键不存在返回null
- 删除元素仍用Map的remove();
6.5 遍历
- 除了Map集合遍历方法,也有特有方法
- Set<String> stringPropertyNames(); 获得所有键的名称的集合
- 用上述方法获得key集合,在用增强for或Iterator遍历
6.6 与流相关方法:
- void store(OutputStream out,String comments);
1'将集合中的数据保存到流关联的目标文件中
2'comments:说明文字,一般给null即可
- void load(InputStream in); 从流关联的目标文件中加载数据到集合中
6.7 示例案例
需求:使用属性集,读取已有数据,查找是不是有saber,若有,将攻击力改为100,并输出到原有的文件中
public class Test05 {
public static void main(String[] args) {
Properties pro = new Properties();
try(FileInputStream fis = new FileInputStream(new File("Java/study/Score.txt"))) {
//2. 读取数据到集合中
pro.load(fis);
//3. 遍历集合,获取到每一个key
Set<String> keysets = pro.stringPropertyNames();
for (String key : keysets) {
if (key.equals("saber")) {
pro.setProperty(key, "100");
}
}
/*
注意:fos必须在这里创建,若在try或者读取数据前创建,原有的数据会被清空!!,那么就读取不了原来的数据了!!导致set一直是空的
而在读取后再创建,就可以把旧数据清空,然后再把存在properties的数据重新写出到文件中!
*/
FileOutputStream fos = new FileOutputStream(new File("day09projects/src/homework/homework/Score.txt"));
pro.store(fos, null);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7. 疑问
Q:为何在使用完流之后要关闭流,它关闭了什么?
A:因为流在使用的过程中会与文件关联,即一直占用该文件,则该文件不能再被其他程序使用。故使用完流之后要关闭流,将关联的文件释放出去,这样文件才可重新被使用。它关闭的是java程序与文件之间的连接