File
File对象
File表示什么?
File对象表示路径,可以是文件、也可以是文件夹。
绝对路径和相对路径是什么意思?
- 绝对路径带盘符
- 相对路径是不带盘符的,默认到当前项目下去找。
File三种构造方法的作用?
| 方法名 | 作用 |
|---|---|
| public File(String pathname) | 把字符串表示的路径变成File对象 |
| public File(String parent,String child) | 把父路径和子路径进行拼接 |
| public File(File parent, String child) | 把父路径和子路径进行拼接 |
代码示例:
public class TestFile {
public static void main(String[] args) {
//绝对路径
File file1 = new File("C:\Users\ZG\Desktop\file.txt");
File file2 = new File("C:\Users\ZG\Desktop", "file.txt");
File file3 = new File("C:\Users\ZG\Desktop");
File file4 = new File(file3, "file.txt");
//相对路径
File file5 = new File("io\test01.txt");
System.out.println(file1);
System.out.println(file2);
System.out.println(file4);
System.out.println(file5);
}
}
File常见成员方法
代码示例:
public class TestFile {
public static void main(String[] args) throws IOException {
//windows当中路径是唯一的,如果当前路径已经存在,则创建失败,返回false
//mkdir只能创建单级文件夹,不能创建多级文件夹
File file1 = new File("io\doc");
boolean mkdir = file1.mkdir();
System.out.println(mkdir);
//mkdirs创建多级文件夹
File file2 = new File("io\mkdirs\doc");
boolean mkdirs = file2.mkdirs();
System.out.println(mkdirs);
//如果当前路径表示的文件是不存在的,则创建成功,方法返回true
//如果当前路径表示的文件是存在的,则创建失败,方法返回false
//如果父级路径不存在,那么方法会抛出IOException
//createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件
File file3 = new File("io\doc\test01.txt");
boolean newFile = file3.createNewFile();
System.out.println(newFile);
//如果删除的是文件,则直接删除,不走回收站
//如果删除的是文件夹,则直接删除,不走回收站
//如果删除的是有内容的文件夹,则删除失败
File file4 = new File("io\doc\test01.txt");
boolean delete = file4.delete();
System.out.println(delete);
}
}
- 当调用者File表示的路径不存在时,返回null
- 当调用者File表示的路径是文件时,返回null
- 当调用者File表示的路径是空文件夹时,返回一个长度为0的数组
- 当调用者File表示的路径是一个有内容的文件夹时,将里面所有的文件夹和文件的路径放在File数组中返回
- 当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有的文件夹和文件的路径放在File数组中放回,包含隐藏文件
- 当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
代码示例:
public class TestFile {
public static void main(String[] args) {
File file = new File("F:\新建文件夹");
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1);
}
}
}
File练习
创建一个文件
public class TestFile {
public static void main(String[] args) throws IOException {
//创建文件
File file1 = new File("io\doc");
file1.mkdirs();
File file2 = new File(file1, "test.txt");
boolean newFile = file2.createNewFile();
if (newFile) {
System.out.println("创建成功");
} else {
System.out.println("创建失败");
}
}
}
查询某一个文件夹中是否有txt文件
public static boolean haveTxt(File file) {
if (!file.exists()) {
return false;
}
if (file.isFile() && file.getName().endsWith(".txt")) {
return true;
}
File[] files = file.listFiles(pathname -> pathname.isFile() && pathname.getName().endsWith(".txt"));
return files != null && (files.length > 0);
}
查询电脑上所有的xlsx文件
public class TestFile {
public static void main(String[] args) throws IOException {
File[] files = File.listRoots();
for (File file : files) {
findXlsx(file);
}
}
public static void findXlsx(File file) {
File[] files = file.listFiles();
if (files != null) {
for (File file1 : files) {
if (file1.isFile() && file1.getName().endsWith(".xlsx")) {
System.out.println(file1);
} else {
findXlsx(file1);
}
}
}
}
}
删除一个多级文件夹
public class TestFile {
public static void main(String[] args) throws IOException {
File file = new File("F:\新建文件夹 (2)");
delete(file);
}
public static void delete(File file) {
File[] files = file.listFiles();
if (files != null) {
for (File file1 : files) {
if (file1.isFile()) {
file1.delete();
} else {
delete(file1);
}
}
}
file.delete();
}
}
统计文件夹大小
public class TestFile {
public static void main(String[] args) throws IOException {
File file = new File("F:\新建文件夹\掘金素材");
System.out.println(count(file));
}
public static long count(File file) {
long len = 0;
File[] files = file.listFiles();
if (files != null) {
for (File file1 : files) {
if (file1.isFile()) {
len += file1.length();
} else {
len += count(file1);
}
}
}
return len;
}
}
IO流
IO流分类
什么是IO流?
- 存储和读取数据的解决方案
- I:input O:output
- 流:像水流一样传输数据
IO流的作用?
用于读写数据(本地文件、网络)
IO流按照流向可以分为哪两种流/
- 输出流:程序->文件
- 输入流:文件->程序
IO流按照操作文件的类型可以分为哪两种流?
- 字节流:可以操作所有类型的文件
- 字符流:只能操作纯文本数据
什么是纯文本文件?
用windows系统自带的记事本打开并且能读懂的文件。txt文件、md文件、xml文件、lrc文件等
字节流
字节输出流 FileOutputStream
书写步骤:
- 创建字节输出流对象
- 写数据
- 释放资源
代码示例:
public class TestIO {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//参数是字符串表示的路径或者是File对象都是可以的
//如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
//如果已经存在,则会清空文件
FileOutputStream fos = new FileOutputStream("io\doc\test01.txt");
//write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符,57在ASCII上对应就是9
fos.write(57);
fos.write(57);
//每次使用完流之后都要释放资源
fos.close();
}
}
换行:
public class TestIO {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("io\doc\test01.txt");
String str1 = "hello world";
fos.write(str1.getBytes());
String str2 = "\r\n";
fos.write(str2.getBytes());
String str3 = "china";
fos.write(str3.getBytes());
fos.close();
}
}
续写:
public class TestIO {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("io\doc\test01.txt", true);
String str1 = "hello world\r\n";
fos.write(str1.getBytes());
fos.close();
}
}
字节输入流 FileIntputStream
书写步骤:
- 创建字节输入流对象
- 读取数据
- 释放资源
代码示例:
public class TestIO {
public static void main(String[] args) throws IOException {
//文件不存在直接报错
FileInputStream fis = new FileInputStream("io\doc\test01.txt");
//一次读一个字节,读取出来的数据是在ASCII上对应的数字
//读到文件末尾了,read方法返回-1
int read;
while ((read = fis.read()) != -1) {
System.out.print((char) read);
}
//每次使用完流之后都要释放资源
fis.close();
}
}
文件复制:
public class TestIO {
public static void main(String[] args) throws IOException {
//文件复制,一次读一个字节写一个字节,效率低
FileInputStream fis = new FileInputStream("io\doc\test01.txt");
FileOutputStream fos = new FileOutputStream("io\doc\test02.txt");
int read;
while ((read = fis.read()) != -1) {
fos.write(read);
}
fos.close();
fis.close();
}
}
IO流中不同JDK版本捕获异常的方式
基本用法:
public class TestIO {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("io\doc\test01.txt");
fos = new FileOutputStream("io\doc\test02.txt");
byte[] bytes = new byte[1024 * 1024 * 5];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
JDK7(自动释放资源):必须实现AutoCloseable接口
public class TestIO {
public static void main(String[] args) {
//自动释放资源
try (FileInputStream fis = new FileInputStream("io\doc\test01.txt");
FileOutputStream fos = new FileOutputStream("io\doc\test02.txt")) {
byte[] bytes = new byte[1024 * 1024 * 5];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
JDK9(自动释放资源):必须实现AutoCloseable接口
public class TestIO {
public static void main(String[] args) throws FileNotFoundException {
//自动释放资源
FileInputStream fis = new FileInputStream("io\doc\test01.txt");
FileOutputStream fos = new FileOutputStream("io\doc\test02.txt");
try (fis; fos) {
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符集
ASCII字符集、GBK字符集、Unicode字符集(万国码)
- 在计算机中,任意的数据都是以二进制的形式进行存储的
- 计算机中最小的存储单元是一个字节
- ASCII字符集中,一个英文占一个字节
- 简体中文版windows,默认使用GBK字符集
- GBK字符集完全兼容ASCII字符集
- 一个英文占一个字节,二进制的第一位是0
- 一个中文占两个字节,二进制高位字节的第一位是1
Unicode字符集:
- UTF-16编码规则:2-4个字节保存
- UTF-32编码规则:固定使用4个字节保存
- UTF-8编码规则:1-4个字节保存
UTF-8编码规则(二进制):
- ASCII(英文):1个字节(0xxxxxxx)二进制第一位是0,转成十进制是正数
- 简体中文:3个字节(1110xxxx 10xxxxxx 10xxxxxx)二进制第一位是1,转成十进制是负数
乱码:
- 读取数据的时候未读完整个汉字
- 编码和解码时的方式不统一
- 解决方式:不要使用字节流读取文本文件,编码和解码时使用同一个码表,同一个编码方式
字符流
字符输入流 FileReader
read()无参读取:
public class TestIO {
public static void main(String[] args) throws IOException {
//创建对象并关联本地文件
FileReader fr = new FileReader("io\doc\test01.txt");
int ch;
//使用无参构造读取文件
//字符流的底层是字节流,默认也是一个一个字节读取的,
//如果遇到中文就会一次读取多个,GBK一次读取2个字节UTF-8一次读取3个字节
//在读取之后,方法的底层还会进行解码并转成10进制,并最终把10进制作为返回值,这个10进制也表示在字符集上的数字
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
//关闭流
fr.close();
}
}
read(chars)有参读取:
public class TestIO {
public static void main(String[] args) throws IOException {
//创建对象并关联本地文件
FileReader fr = new FileReader("io\doc\test01.txt");
char[] chars = new char[2];
int len;
//读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
while ((len = fr.read(chars)) != -1) {
System.out.print(new String(chars,0,len));
}
//关闭流
fr.close();
}
}
字符输出流 FileWriter
代码示例:
public class TestIO {
public static void main(String[] args) throws IOException {
//开启续写
FileWriter fileWriter = new FileWriter("io\doc\test01.txt", true);
//写出一个字符,写出的是字符集上面对应的字符
fileWriter.write(97);
//写出一个字符串
fileWriter.write("我爱你中国!");
//写出一个字符串的一部分
fileWriter.write("我爱你中国!", 0, 3);
//写出一个字符数组
char[] chars = {'我', '爱', '你', '西', '安'};
fileWriter.write(chars);
//写出一个字符数组的一部分
fileWriter.write(chars, 0, 3);
fileWriter.close();
}
}
字符流底层原理
字符输入流底层原理
字符输出流底层原理
文件夹复制
public class TestIO {
public static void main(String[] args) throws IOException {
copyFile(new File("F:\新建文件夹"),new File("F:\001"));
}
public static void copyFile(File src, File dest) throws IOException {
dest.mkdirs();
File[] files = src.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isFile()) {
//复制文件
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File(dest, file.getName()));
int len;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fos.close();
fis.close();
} else {
copyFile(file, new File(dest, file.getName()));
}
}
}
}
缓冲流
字节缓冲流
private static int DEFAULT_BUFFER_SIZE = 8192;
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
public class BufferTest01 {
public static void main(String[] args) throws IOException {
//利用字节缓冲流复制文件
//字节缓冲输入流,缓冲区默认为8192,可以根据有参构造继进行设置
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("io\test01.txt"));
//字节缓冲输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("io\test02.txt"));
int len;
byte[] bytes = new byte[1024];
while ((len = bufferedInputStream.read(bytes)) != -1) {
bufferedOutputStream.write(bytes, 0, len);
}
bufferedOutputStream.close();
bufferedInputStream.close();
}
}
字符缓冲流
字符缓冲输入流(特有方法readLine,一次读取一行)
public class BufferTest01 {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("io\test01.txt"));
//字符缓冲输入流特有方法,readLine一次读取一整行
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
}
}
字符缓冲输出流(特有方法newLine,跨平台换行)
public class BufferTest01 {
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("io\test02.txt"));
//字符缓冲输出流特有方法,newLine换行
String content1 = "电视里看到教授副教授打开房间";
String content2 = "丢失了多久";
bufferedWriter.write(content1);
bufferedWriter.newLine();
bufferedWriter.write(content2);
bufferedWriter.close();
}
}
转换流
字节流转换为字符流
利用转换流按照指定编码读取
public class BufferTest01 {
public static void main(String[] args) throws IOException {
//字节流转换为字符流
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("io\gbk.txt"), Charset.forName("GBK"));
int read;
while ((read = inputStreamReader.read()) != -1) {
System.out.println((char) read);
}
inputStreamReader.close();
}
}
public class BufferTest01 {
public static void main(String[] args) throws IOException {
//JDK11之后才出现
FileReader fileReader = new FileReader("io\gbk.txt", Charset.forName("GBK"));
int read;
while ((read = fileReader.read()) != -1) {
System.out.println((char) read);
}
fileReader.close();
}
}
利用转换流按照指定的编码写入
public class BufferTest01 {
public static void main(String[] args) throws IOException {
//传统模式字节输出流包装成字符输出流
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("io\gbk.txt",true), Charset.forName("GBK"));
outputStreamWriter.write("我爱你!");
outputStreamWriter.close();
//JDK11之后
FileWriter fileWriter = new FileWriter("io\gbk.txt", Charset.forName("GBK"),true);
fileWriter.write("我爱你中国!");
fileWriter.close();
}
}
序列化流
序列化流
可以把java中的对象写到本地文件中,前提是javabean必须实现Serializable接口
public class BufferTest01 {
public static void main(String[] args) throws IOException {
ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("io\student.txt"));
Student student = new Student();
student.setAge(20);
student.setName("lisi");
objectOutput.writeObject(student);
objectOutput.close();
}
}
反序列化流
可以把序列化到本地文件中的对象,读取到程序中来。
public class BufferTest01 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("io\student.txt"));
Object o = objectInputStream.readObject();
System.out.println(o);
}
}
序列化与反序列化的细节
打印流
字节打印流
public class BufferTest01 {
public static void main(String[] args) throws IOException {
PrintStream printStream = new PrintStream(new FileOutputStream("io\gbk.txt"), true, StandardCharsets.UTF_8);
printStream.println(456);
printStream.close();
}
}
字符打印流
public class BufferTest01 {
public static void main(String[] args) throws IOException {
PrintWriter printWriter = new PrintWriter(new FileWriter("io\gbk.txt"), true);
//打印一个字节,97对应的是a
printWriter.write(97);
//打印一个字符串
printWriter.write("99");
printWriter.close();
}
}
总结
- 有字节打印流和字符打印流两种
- 打印流不操作数据源,只能操作目的地
- 字节打印流,默认自动刷新,特有println自动换行
- 字符打印流,自动刷新需要开启,特有println自动换行