1. 文件操作
IO: Input/读文件 Output/写文件
所属软件包: java.io
1.File - 文件类, 可以表示文件或者目录
构造方法:
new File(String 文件路径)
new File(String 父路径, String 子路径)
常用API:
获得文件/目录的绝对路径
获得file对象中所有的文件 listFiles()
File file = new File(".");
file.listFiles(new FileFilter() {
@Override
public boolean accept(File f) {
// 处理了f, 让他返回true, 表示f要保留
// 处理了f, 返回false, 表示f不想保留了
return false;
}
});
// filter.accept(f) --> 返回true
public File[] listFiles(FileFilter filter) {
// 得到了这个目录下面所有的文件名字
String ss[] = list();
if (ss == null) return null;
// 创建了一个存储File对象的集合
ArrayList<File> files = new ArrayList<>();
// 迭代这个名字的数组
for (String s : ss) {
// 使用文件名, 创建了一个对应的File对象
File f = new File(s, this);
if ((filter == null) || filter.accept(f))
// 当accept方法返回true, 将这个文件对象加入到list列表中
files.add(f);
}
// 将list变成数组返回
return files.toArray(new File[files.size()]);
}
2.路径
绝对路径: window是 - 从盘符开始 C:\xx\xx...
Linux是 - /xx/xx (从根目录开始)
相对路径: 会有一个参照对象 a.txt
参考值: /Users/bonnie/Desktop 相对路径是: a.txt
那么a.txt的真实路径: /Users/bonnie/Desktop/a.txt
现在a.txt的真实路径: /Users/bonnie/IdeaWorks/corejava/API_day09/a.txt
那么现在的参考值: /Users/bonnie/IdeaWorks/corejava/API_day09
参考值 我们称之为 - 当前目录
参考值: C:\IdeaWorks\day09\src 相对路径: com/zzxx/demo01/a.txt
那么a.txt的真实路径: C:/IdeaWorks/day09/src/com/zzxx/demo01/a.txt
. : 当前目录 - 现在的参考值
..: 上一级目录 - 现在的参考值 往上一层
根据相对路径, 获得当前程序环境下的绝对路径
复习: 1.xx.class.getResource("相对路径") -> 得到一个绝对路径
2.xx.class.getClassLoader().getResource("相对路径") -> 得到一个绝对路径
注意:
类路径 classpath: 就是src编译后的目录, 也叫编译根目录
以上 1 和 2 代码得到的绝对路径, 都是在编译后的目录中, 和src没有直接关系
在开发中, 我们是先将文件放入src中的, 会自动编译到类路径中
import org.junit.Test;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
public class FileDemo {
@Test
public void test01(){
//传输文件的相对路径给File的构造方法,创建File对象
//路径的参考值为当前module目录 E:\ideaWorkplace\com
//注意:new 出来的文件对象只在jvm中存在,和本地磁盘有没有这个文件无关
File file1 = new File("a/b/c.txt");
System.out.println(file1);//File类的toString方法已经重写
// 输出文件路径和文件名 参考值:(E:\ideaWorkplace\com\) + 相对路径:(a\b\c.txt) 括号和+只是为了分隔路径的参考值以及相对路径
//参考值改变,相对路径所代表的绝对路径也会改变
//传输文件父路径和子路径给File的构造方法,创建File对象
File file2 = new File("a/b", "b/c.txt");
System.out.println(file2);
//获取绝对路径(即文件存在的真实路径),windows从盘符开始
System.out.println(file1.getAbsolutePath());
//
}
@Test
public void test02(){
//class.getResource 查找具有给定名称的资源
// url.getPath()获取此 URL的路径部分。
//在编译后(注意:class文件为字节码文件,是编译后的文件,所以找的是out目录中的包目录)的包目录下查找具有给定名称的资源,获取资源a.txt存在的目录
String path = FileDemo.class.getResource("com/hzt/file/a.txt").getPath();
//a.txt 路径参考值:当前类的编译目录 - 就是当前这个包
//直接理解为:a.txt 和当前这个类 同一包
System.out.println(path);
}
@Test
public void test03(){
//getClassLoader 返回类的类加载器
/* 在编译后(注意:class文件为字节码文件,而getClassLoader是获取了此类的类加载器类,相当于模组的编译后的文件目录,
所以找的是out目录中的模组目录)的模组目录下查找具有给定名称的资源,获取资源a.txt存在的目录*/
String path = FileDemo.class.getClassLoader().getResource("com/hzt/file/a.txt").getPath();
//b.txt 路径的参考值:当前这个模块编译后的根目录 classpath
//直接理解为: a.txt 就是在src下的
System.out.println(path);
}
@Test
public void test04(){
File file = new File("src/com/hzt/file/a.txt");//文件相对路径为 src/com/hzt/file/a.txt
//判断此文件或目录是否存在
System.out.println(file.exists());
//创建此文件对象的文件或目录
//windows系统中\/都可以用作路径分隔符,但是在字符串中\需要转义且/在linux和windows中都可以用,所以推荐用/
//因为路径的参考值为当前module目录 E:\ideaWorkplace\com,所以文件创建在了E:\ideaWorkplace\com/src/com/hzt/file/a.txt
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//判断此文件是否为目录
System.out.println(file.isDirectory());
//判断此文件是否为文件
System.out.println(file.isFile());
//删除此文件 返回true为删除成功
System.out.println(file.delete());//delete方法,如果此File表示目录,则目录必须为空才能删除。否则必须先删除目录中的文件
//以上方法返回值均为boolean类型
}
@Test
public void test05(){
File file = new File("src/newDir");
System.out.println(file.exists());//目录是否存在
System.out.println(file.mkdir());//创建目录
System.out.println(file.exists());
File file1 = new File("src/parentDir/newDir");//创建多级目录文件
System.out.println(file1.exists());
System.out.println(file1.mkdir());//因为只能在已有目录下在创建一级目录,所以会返回false创建失败
System.out.println(file1.mkdirs());//创建多级目录
File file2 = new File("src/parentDir/newDir1");//创建多级目录文件
file2.mkdirs();
}
@Test
public void test06(){
//创建一个File对象,"."表示参考值即当前模组目录
File file = new File(".");
System.out.println(file.getAbsolutePath());//当前文件的绝对目录为E:\ideaWorkplace\com\.
//创建一个File数组,存储file对象中所有的文件和目录
//file对象是文件,数组为null, file对象是空文件夹,数组存在有地址且长度为0
File[] files = file.listFiles();
for(File f: files){
//因为存储类型为File类型所以可以使用文件对象的方法
System.out.println(f + "此文件对象为是否为文件:" + f.isFile());
}
//返回一个String数组,表示file对象中的所有文件和目录
String[] strings = file.list();
for(String s: strings){
System.out.println(s);
}
}
@Test
public void test07(){
//创建一个File对象,".."表示参考值的上一级目录
File file = new File("../com/src/com/hzt");
System.out.println(file.getAbsolutePath());
//文件过滤器 FileFilter
//FileFilter为函数式接口,只有一个抽象方法,作为listFiles方法的参数用于过滤文件,过滤条件通过重写accept方法自定义
//创建File数组,存储file文件下的所有文件和文件夹
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return true;//接受所有文件
}
});
//函数式接口在作为方法参数时可以用lambda表达式简化
//重写accept方法为只保留文件,不保留目录
File[] files1 = new File(".").listFiles((pathname)->{return pathname.isFile();});
System.out.println("只接受文件");
for(File f: files1){
System.out.println(f.getName());//输出数组中的文件名
}
//只接受后缀名为.txt的文件
System.out.println("只接受后缀名为.txt的文件");
files1 = new File(".").listFiles((p)->{ return p.getName().endsWith(".txt");});
for(File f: files1){
System.out.println(f.getName());//输出数组中的文件名
}
}
@Test
public void test08(){
//创建文件
try {
new File("./src/newDir/a").mkdirs();
new File("./src/newDir/a/c.txt").createNewFile();
new File("./src/newDir/a/a.txt").createNewFile();
new File("./src/newDir/b.txt").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//调用deleteDirectory方法删除非空目录
File file = new File("./src/newDir");
deleteDirectory(file);
}
public void deleteDirectory(File file){
//用迭代删除非空文件夹
//创建要删除的文件夹对象数组
File[] files = file.listFiles();
//如果文件类型是目录,目录为空的情况因为长度是0所以无法进入foreach循环所以对判断无影响 调用方法删除文件夹对象中的文件
if(file.isDirectory()){
for (File f: files){
deleteDirectory(f);
}
}
//如果文件类型是文件 直接删除
file.delete();
}
}
2. IO 流
1.以单位来分: 字节流 字符流
2.以层级来分: 底层流 包装流
字节流: InputStream/OutputStream
子类: FileInputStream/FileOutputStream
字符流: Reader/Writer
注意:
1.IO所有跟文件相关的流中, 构造方法中需要File作为参数的都可以使用文件路径直接取代
2.字节流写和读都是以字节为单位的, 单个字节能不能正常显示出来, 是不确定的
字节流
API:
void write(int) : 写入这个int值得低八位
int read() : 读文件中一个字节, 并且存入int的低八位, 其余空位补0
当返回 -1 的时候, 说明文件读到了末尾
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class File_IO_Demo {
//file字节输出流(用程序把字节写入文件)
@Test
public void FileOutput() throws IOException {
//创建文件输出流对象,参数为(File file/ String path[, append true])
//参数中的所有文件类对象都可以用路径字符串替换(jdk中创建了构造方法来简化), append = true为在文件末尾写入即为可拼接,默认为false即直接重写
//如果目标输出文件不存在,则创建一个文件
FileOutputStream os = new FileOutputStream("./src/com/hzt/stream/a.txt",true);
//使用输出流对象的write方法写入字节
//重载1:参数为int write只写入参数转化为二进制补码(java中所有基本数据类型都以二进制补码存储)后的低八位bit数据
os.write(0);//写入 00000000 00000000 00000000 00000000 的低8位 00000000 转化为空白字符
os.write(97);//写入 00000000 00000000 00000000 01100001 的低8位 01100001 转化为字符为a
os.write(48);//写入 00000000 00000000 00000000 00110000 的低8位 01100001 转化为字符为0
os.write(-1);//写入 11111111 11111111 11111111 11111111 的低8位 11111111 255转化为无法识别的字符
//关闭输出流
os.close();
}
@Test
//file字节输入流(用程序把字节从文件读入)
public void FileInput() throws IOException {
//创建文件输出流, 参数为(File file/ String path)
//如果文件不存在则抛出异常
FileInputStream is = new FileInputStream("./src/com/hzt/stream/a.txt");
//循环读取文件字符,将字符转换为字节
//用read方法读取数据
//重载1:读一个字节 8位 放入int的 32位 中的低八位, 其他空位都补0
int i;
while(( i = is.read()) != -1){
System.out.println(i);
}
}
@Test
//复制文件
public void copy() throws IOException {
FileInputStream is = new FileInputStream("./src/com/hzt/stream/a.txt");
FileOutputStream os = new FileOutputStream("./src/com/hzt/stream/a_bak.txt");
//循环读取正本文件的一个字节,同时写入副本中
int i;
while((i = is.read()) != -1){
os.write(i);
}
}
}
字符流
Reader/Writer
InputStreamReader(InputStream in, String charsetName) - 指定字符集
InputStreamReader(InputStream in) - 默认字符集
int read() 读一个字符
int read(char[] cbuf) 将字符读入数组。
int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。- 了解
注: 以上三个方法, 返回 -1 都标记着读到文件末尾
OutputStreamWriter(OutputStream out, String charsetName)
OutputStreamWriter(OutputStream out)
void write(char[] cbuf) 写入一个字符数组。
void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
void write(int c) 写入单个字符
代码实现:
import org.junit.Test;
import java.io.*;
//字符流
public class WriterAndReader {
@Test
//使用字符流读取数据
public void reader() throws IOException {
File fileI = new File("src/com/hzt/stream/a.txt");
FileInputStream is = new FileInputStream(fileI);
//构造方法1:使用字符流包装一个字节流
InputStreamReader isr1 = new InputStreamReader(is);
int i;
//循环读取一个字符,返回值为int,将读取的16位放入int的低16位
while ((i = isr1.read()) != -1){
System.out.print((char)i);
}
}
@Test
//使用字符流写入数据
public void writer() throws IOException {
File fileI = new File("src/com/hzt/stream/a.txt");
FileOutputStream os = new FileOutputStream(fileI);
//构造方法1:创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter osw1 = new OutputStreamWriter(os);
char[] ch = new char[]{'h', 'e', 'l', 'l', 'o'};
//写入字符数组的一部分。
osw1.write("Hello,World!");
//写出换行
osw1.write("\n");
//写入字符数组的一部分
osw1.write(ch);
//因为已经不是底层字符流了,需要进行刷新
// osw1.flush();
//或者直接close释放字符流
osw1.close();
}
@Test
//文件复制
public void copy(){
File fileI = new File("src/com/hzt/stream/a.txt");
File fileO = new File("src/com/hzt/stream/a_bak.txt");
try{
//FileReader/FileWriter 字符流的便捷类
FileReader fr = new FileReader(fileI);
FileWriter fw = new FileWriter(fileO);
int i;
while ((i = fr.read()) != -1){
fw.write(i);
fw.flush();
}
}
catch(IOException e){
e.printStackTrace();
}
}
}