day34
File类
理解
File是文件和目录路径名的抽象表示
File类的对象可以表示文件:D:\笔记\奇男子\qnz.txt
File类的对象可以表示目录路径名:D:\笔记\奇男子
File只关注文件本身的信息(文件名、是否可读、是否可写…),而不能操作文件里面的内容
File类 – 表示文件或文件夹,不能对文件里的数据进行操作
对文件里的数据进行操作的是:IO流
需求1:
通过程序,获取已知文件的信息
public class Test01 {
public static void main(String[] args) {
//创建file对象
File file = new File("D:\\笔记\\奇男子\\qnz.txt");
System.out.println("获取文件路径:" + file.getAbsolutePath());
System.out.println("获取文件名:" + file.getName());
System.out.println("获取文件是否可读:" + file.canRead());
System.out.println("获取文件是否可写:" + file.canWrite());
System.out.println("获取文件是否隐藏:" + file.isHidden());
System.out.println("获取文件大小(字节):" + file.length());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String datetime = sdf.format(file.lastModified());
System.out.println("获取文件最后修改时间:" + datetime);
}
}
相对路径 和 绝对路径
绝对路径:
从根目录开始的完整路径,包含了文件系统中该文件或目录
理解:所在的完整路径,通常以根目录符号(如Linux中的“/”,Windows中的“C:\”)开始
相对路径:
相对于当前项目下的路径
public class Test02 {
public static void main(String[] args) {
File file = new File("file.txt");//使用的是相对路径
System.out.println(file.length());
//D:\workspace\MyDay33\file.txt
System.out.println("绝对路径:" + file.getAbsolutePath());
//file.txt
System.out.println("相对路径:" + file.getPath());
}
}
需求2
通过程序,判断指定路径的文件是否存在,如果不存在,则创建该文件
下面按各种情况来解决该问题
1)目录已存在的情况
如果目录不存在就会报错,找不到系统路径
public class Test01 {
public static void main(String[] args) throws IOException {
File file = new File("file01\\hhy.txt");
//判断文件是否存在
if(!file.exists()){
//创建文件
file.createNewFile();
}
}
}
2)有一个层级的目录不存在的情况
public class Test02 {
public static void main(String[] args) throws IOException {
//D:\workspace\MyDay34\file01\qnz.txt
File file = new File("file01\\qnz.txt");
//获取父路径 -- D:\workspace\MyDay34\file01
File parentFile = file.getParentFile();
//判断父路径是否存在
if(!parentFile.exists()){
//创建一层目录
parentFile.mkdir();
}
//判断文件是否存在
if(!file.exists()){
//创建文件
file.createNewFile();
}
}
}
3)有多个层级的目录不存在的情况
public class Test03 {
public static void main(String[] args) throws IOException {
//D:\workspace\MyDay34\file01\file02\file03\qnz.txt
File file = new File("file01\\file02\\file03\\qnz.txt");
//获取父路径 -- D:\workspace\MyDay34\file01\file02\file03
File parentFile = file.getParentFile();
//判断父路径是否存在
if(!parentFile.exists()){
//创建多层目录
parentFile.mkdirs();
}
//判断文件是否存在
if(!file.exists()){
//创建文件
file.createNewFile();
}
}
}
需求3:
输出指定目录下的所有文件信息
public class Test01 {
public static void main(String[] args) {
File file = new File("D:\\笔记");
//获取当前目录下所有文件及文件夹的名字
// String[] list = file.list();
// for (String fileName : list) {
// System.out.println(fileName);
// }
//获取当前目录下所有的file对象
File[] listFiles = file.listFiles();
//获取当前目录下所有的文件及文件夹的file对象
for (File f : listFiles) {
System.out.println(f.getName() + " -- " + f.canRead() + " -- " + f.canWrite());
}
}
}
1)要求只输出文件后缀名为txt的文件
public class Test02 {
public static void main(String[] args) {
File file = new File("D:\\笔记");
//获取当前目录下所有文件及文件夹的名字
// String[] list = file.list();
// for (String fileName : list) {
// if(fileName.endsWith(".txt")){
// System.out.println(fileName);
// }
// }
//获取当前目录下所有的file对象
File[] listFiles = file.listFiles();
//获取当前目录下所有的文件及文件夹的file对象
for (File f : listFiles) {
String fileName = f.getName();
//判断f是否是文件
if(f.isFile() && fileName.endsWith(".txt")){
System.out.println(fileName);
}
}
}
}
2)根据API的过滤器来完成该功能
public class Test03 {
public static void main(String[] args) {
File file = new File("D:\\笔记");
String[] list = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File childFile = new File(dir, name);
if(childFile.isFile() && childFile.getName().endsWith(".txt")){
return true;
}
return false;
}
});
for (String fileName : list) {
System.out.println(fileName);
}
}
}
3)需求继续跟进,列出当前目录及子目录中符合该条件的文件信息(递归)
递归:方法里面调用方法自身
public class Test04 {
public static void main(String[] args) {
File file = new File("D:\\笔记");
fileHandler(file, ".txt");
}
public static void fileHandler(File file,String suffix){
File[] listFiles = file.listFiles();
for (File f : listFiles) {
if(f.isFile()){//文件
String name = f.getName();
if(name.endsWith(suffix)){
System.out.println(name);
}
}else if(f.isDirectory()){//文件夹
fileHandler(f, suffix);
}
}
}
}
IO流
概念
IO流是计算机编程中的一个重要概念,主要用于处理数据的输入和输出操作。
I – in – 输入(读)O – out – 输出(写)
流 – 一点一点的像水流一样去传输数据
注意:站在程序的角度去看待输入还是输出
分类
按照方向分流:输入流、输出流
按照单位分流:字节流、字符流
按照功能分流:基础流/节点流、处理流
注意:new 处理流(new 基础流) – 装饰者模型 – 处理流对象中往往包含了基础流的对象,在基础流的基础上拓展了额外的功能,使得流更为强大(效率),工作中一般使用处理流
存储单位
1024byte = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
1024TB = 1PB
注意:进制1024
学习注意事项
- 按照流的发展历史去学习
- 注意流与流之间的继承关系
- 举一反三
字节流
应用场景:操作二进制数据(音频、视频、图片)
abstract class InputStream – 字节输入流的基类(抽象类)
abstract class OutputStream – 字节输出流的基类(抽象类)
class FileInputStream extends InputStream – 文件字节输入流
class FileOutputStream extends OutputStream – 文件字节输出流
class FilterInputStream extends InputStream – 过滤器字节输入流
class FilterOutputStream extends OutputStream – 过滤器字节输出流
class BufferedInputStream extends FilterInputStream – 带缓冲区的字节输入流
class BufferedOutputStream extends FilterOutputStream – 带缓冲区的字节输出流
默认缓冲区大小:8192字节
1.利用 文件字节输出流 向文件写入数据
不处理异常
当文件存在时
当文件不存在时
经验:所有的输出流,当文件不存在时都会创建该文件
public class Test01 {
public static void main(String[] args) throws IOException {
//1.创建流对象
FileOutputStream fos = new FileOutputStream("io.txt");
//2.写入数据
//fos.write(97);//写入UniCode码
//fos.write("123abc".getBytes());//写入byte数组
fos.write("123abc".getBytes(), 2, 3);//写入byte数组、偏移量、写入长度
//3ab
//3.关闭资源
fos.close();
}
}
- 在文件末尾追加内容
经验:在文件末尾追加考虑基础流的构造方法
public class Test02 {
public static void main(String[] args) throws IOException {
//1.创建流对象 + 设置在文件末尾追加
FileOutputStream fos = new FileOutputStream("io.txt",true);//默认是false
//2.写入数据
fos.write("123abc".getBytes());//写入byte数组
//3.关闭资源
fos.close();
}
}
- 处理异常
public class Test03 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//1.创建流对象 + 设置在文件末尾追加
fos = new FileOutputStream("io.txt",true);
//2.写入数据
fos.write("123abc".getBytes());//写入byte数组
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭资源
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意:
对于try-catch,底层会逐句判断,所有在同样功能情况下,try中代码越少越好
2.利用 文件字节输入流 读取文件里的数据
注意:
读取中文数据时会出现中文乱码的情况
utf-8编码1个中文占3个字节,gbk编码1个中文占2个字节
读取中文数据采用的是一次读取一个字节的方式,始终会报错
只能使用每次读取一个字节数组的方式来读取
- 不处理异常
- 文件存在
public class Test04 {
public static void main(String[] args) throws IOException {
//1.创建流对象
FileInputStream fis = new FileInputStream("io.txt");
//2.读取数据
//read():一个字节一个字节的读取数据,读取到文件末尾返回-1
int read = fis.read();
System.out.println(read);
read = fis.read();
System.out.println(read);
read = fis.read();
System.out.println(read);
read = fis.read();
System.out.println(read);
read = fis.read();
System.out.println(read);
read = fis.read();
System.out.println(read);
read = fis.read();
System.out.println(read);
//3.关闭资源
fis.close();
}
}
减少冗余代码,但还是一个字节一个字节的读取数据
//while循环读取
//2.读取数据
//read():一个字节一个字节的读取数据,读取到文件末尾返回-1
int read;
while((read = fis.read()) != -1){
System.out.println((char)read);
}
加快读取
//指定长度读取
//2.读取数据
//read(bs):读取bs长度的数据,并把数据放入数组,返回读取到的有效字节数,如果读取到文件末尾则返回-1
byte[] bs = new byte[1024];
int len;
while((len = fis.read(bs)) != -1){
System.out.println(new String(bs, 0, len));
}
- 文件不存在
经验:所有文件输入流,在文件不存在的情况下都会报错 – FileNotFoundException
- 处理异常
public class Test07 {
public static void main(String[] args){
FileInputStream fis = null;
try {
//1.创建流对象
fis = new FileInputStream("io.txt");
//2.读取数据
//read(bs):读取bs长度的数据,并把数据放入数组,返回读取到的有效字节数,如果读取到文件末尾则返回-1
byte[] bs = new byte[1024];
int len;
while((len = fis.read(bs)) != -1){
System.out.println(new String(bs, 0, len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭资源
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件拷贝
利用文件字节输入、输出流
思路:读取源文件,写入目标文件
public class Copy01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("奇男子.mp4");
FileOutputStream fos = new FileOutputStream("copy.mp4");
int read;
while((read = fis.read()) != -1){
fos.write(read);
}
fis.close();
fos.close();
}
}
加快拷贝,数据大的时候就很明显
byte[] bs = new byte[1024];
int len;
while((len = fis.read(bs)) != -1){
fos.write(bs, 0, len);
}
处理异常
public class Copy03 {
public static void main(String[] args){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("奇男子.mp4");
fos = new FileOutputStream("copy.mp4");
byte[] bs = new byte[1024];
int len;
while((len = fis.read(bs)) != -1){
fos.write(bs, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//分开关闭,不然会出问题if(fis != null && fos != null)导致无法关闭
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
简化,新特性
public class Copy04 {
public static void main(String[] args){
//注意:小括号里创建的流会在try...catch后自动关闭
try(FileInputStream fis = new FileInputStream("奇男子.mp4");
FileOutputStream fos = new FileOutputStream("copy.mp4");) {
byte[] bs = new byte[1024];
int len;
while((len = fis.read(bs)) != -1){
fos.write(bs, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}