在Java当中 将计算机中所有的文件和目录都用File这个类描述
IO input output 如何对文件进行数据的写入和读取
java.io这个包下面
File类构造函数与分隔符
//File类会自动甄别文件系统路径Linux/Windows
//关联了一个相对路径的文件
File f1 = new File("haha.txt");
//特殊:对于当前的IDEA/Eclipse而言 相对路径获取的文件都在项目根目录下
System.out.println(f1.exists()); //项目根目录下的haha.txt文件
File f4 = new File("C:\\Users\\HENG\\Desktop\\YD_Java\\src\\Chapter11\\haha.txt");
System.out.println(f4.exists()); //和此类同目录的haha.txt文件
//关联了一个绝对路径的文件
File f2 = new File("C:\\Users\\HENG\\haha.txt");
//如果此路径是Linux的文件路径 / 根目录
File f3 = new File("/haha/xixi/lala");
File f5 = new File("C:\\Users\\HENG\\Desktop\\YD_Java\\src\\Chapter11","haha.txt");
System.out.println(f5.exists());
File parent = new File("C:\\Users\\HENG\\Desktop\\YD_Java\\src\\Chapter11");
File f6 = new File(parent,"haha.txt");
System.out.println(f6.exists());
//因为Linux/Unix/Windows/MAC这些操作系统中 路径分割符是不统一的
//当我们不确定程序所运行的系统环境 如果需要用到文件路径 路径分割符采用File自带的separator
String parentPath = "C:\\Users\\HENG\\Desktop\\YD_Java\\src\\Chapter11";
File f7 = new File(parentPath + File.separator + "haha.txt");
System.out.println(f7.exists());
File类的获取相关
File f = new File("C:\\Users\\HENG\\Desktop\\YD_Java\\第11章笔记.txt");
//打印文件的绝对路径
System.out.println(f.getAbsolutePath());
//文件对象构造函数中写的是啥 这边打印的就是啥
System.out.println(f.getPath());
//获取文件名 - 获取相对路径
System.out.println(f.getName());
//获取文件大小 单位字节 b
System.out.println(f.length());
//最后一次修改时间
System.out.println();
String time = DateFormat.
getDateTimeInstance(DateFormat.LONG,DateFormat.LONG).
format(new Date(f.lastModified()));
System.out.println(time);
System.out.println(f.getParent());
文件和文件夹的创建
//文件的创建 目录的创建
File f1 = new File("file01.txt");
//File f1 = new File("E:\\file01.txt");
//E盘不存在 则报错 IOException
//文件不存在 则创建 返回 true
System.out.println(f1.createNewFile());
//文件已存在 则不创建 返回 false
System.out.println(f1.createNewFile());
//合理的创建方式 先判断 再考虑是否创建
if (!f1.exists()) {
f1.createNewFile();
}
//一般而言 目录是没有后缀名 文件也可以没有后缀名
File f2 = new File("haha");
if (!f2.exists()) {
f2.createNewFile();
}
//File dirc1 = new File("haha");
//上面已经有一个同名没后缀名的文件 从系统角度而言 属于重名内容 不允许创建
File dirc1 = new File("lala");
//创建一个目录
System.out.println(dirc1.mkdir());
File dirc2 = new File("xixi.txt");
System.out.println(dirc2.mkdir());
//上边xixi.txt目录已经创建 则同名的xixi.txt文件不允许 System.out.println(dirc2.createNewFile());
//总而言之,对于系统而言 无论是文件还是目录 只要重名都不能再创建新的了
//尽量创建文件时加上后缀名
//尽量创建目录时不要有非法字符存在(后缀名)
File dirc3 = new File("abc/def/ghi");
//mkdir一次只能创建一个一级目录
System.out.println(dirc3.mkdir());
//若果创建多级目录用mkdirs
System.out.println(dirc3.mkdirs());
文件和文件夹的删除
File f1 = new File("xixi.txt");
//删除一个目录 不走回收站
f1.delete();
//该目录中有多个子文件和其他子目录 不能直接删除
File f2 = new File("abc");
System.out.println(f2.delete());
//如果非得要删除的话 只能先将其内部的所有元素删除之后 再删除该目录
File f3 = new File("haha.txt");
f3.delete();
//总而言之 删除文件 用delete
//delete只能删除单一的文件或单一的目录
//如果所删除的目录有内容 则不能删除 只能手动
子文件与文件过滤器
File f1 = new File("xixi.txt");
//删除一个目录 不走回收站
f1.delete();
//该目录中有多个子文件和其他子目录 不能直接删除
File f2 = new File("abc");
System.out.println(f2.delete());
//如果非得要删除的话 只能先将其内部的所有元素删除之后 再删除该目录
File f3 = new File("haha.txt");
f3.delete();
//总而言之 删除文件 用delete
//delete只能删除单一的文件或单一的目录
//如果所删除的目录有内容 则不能删除 只能手动
11.5 子文件与文件过滤器
public static void main(String[] args) {
File dir = new File("C:\\Users\\HENG\\Desktop\\YD_Java");
//查看该目录下所有的文件(包含隐藏文件)
//list()返回的是该目录下第一层级的所有文件和目录的名字的字符串数组
MyFileNameFilter filter = new MyFileNameFilter();
String[] fileNames = dir.list(filter);//只能传关于名字的过滤
if (fileNames != null) {
for (String name : fileNames) {
System.out.println(name);
}
}
MyFileFilter filter2 = new MyFileFilter();
//listFiles()返回的是该目录下第一层级的所有文件和目录的File对象的一维数组
File[] files = dir.listFiles(filter2);//关于文件名 文件属性的过滤都行
if (files != null) {
for (File file : files) {
System.out.println(file.getAbsolutePath());
}
}
dir.list();
}
public static class MyFileFilter implements FileFilter {
@Override
public boolean accept(File file) {
return file.length() > 2000;
}
}
public static class MyFileNameFilter implements FilenameFilter {
//File dir 父目录
//String name 当前文件的名称
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
}
获取文件夹全部内容
private static void printDirDieDai(File dir) {
LinkedList<File> queue = new LinkedList<>();
queue.offer(dir);
while (!queue.isEmpty()) {
File file = queue.poll();
System.out.println("【" + file.getName() + "】");
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
if (f.isFile()) {
System.out.println(f.getName());
} else {
queue.offer(f);
}
}
}
}
}
private static void printDir(File dir,int level) {
System.out.println(getSpace(level) + "【" + dir.getName() + "】");
File[] files = dir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isFile()) {
System.out.println(getSpace(level + 1) + file.getName());
} else {
printDir(file,level + 1);
}
}
}
private static String getSpace(int level) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < level; i++) {
sb.append("--");
}
return sb.toString();
}
删除文件夹全部内容
private static void deleteDir(File dir) {
File[] files = dir.listFiles();
if (files == null) {
dir.delete();
return;
}
for (File file : files) {
if (file.isFile()) {
file.delete();
} else {
deleteDir(file);
}
}
dir.delete();
}
字节流与字符流
一进一出 针对内存(程序)
从文件中读取输入到内存 输入流
从内存把数据写入带文件 输出流
流就是文件到内存的一个桥梁 数据传输的载体 单向
按照方向
输入流
输出流
按照数据的类型
字节流
字符流
对于任何OS来说 文件最终都是以二进制的形式存储在硬盘里
.txt .mp3 .avi .doc 最终都是二进制文件
但是对于.txt .java .py .cpp 这些文件而言 唯一存储的数据是字符
所以对于上述文件的操作 既可以是字节流操作 字符流操作
注意:字符流只能针对纯文本文件 .doc不算纯文本文件
字符流 = 字节流 + 编码表
IO它不一定非得和文件操作 但肯定和内存有关
OutputStream
此抽象类是表示输出字节流的所有类的超类
OutputStream 字节输出流
FileOutputStream 文件字节输出流
File f1 = new File(“test01.txt”);
//如果文件不存在 则创建
//如果文件存在 删除原先的再创建 - 覆盖
//如果路径不存在 则报错
//如果关联的是目录 报错
FileOutputStream fos = new FileOutputStream(f1);
fos.write(97);
fos.write(100);
String info = “I Love U”;
byte[] bytes = info.getBytes();
//字符串 -> 字节 编码
System.out.println(Arrays.toString(bytes));
fos.write(bytes);
//用文本程序打开一个文本文件 读取字节 经过码表 得到字符
//字节 -> 字符串 解码
fos.close(); //关闭流
InputSteam
// 此抽象类是表示输入字节流的所有类的超类
InputStream 字节输入流
FileInputStream 文件字节输入流
File f1 = new File("test01.txt");
//如果存在 则正常
//如果不存在 则报错
FileInputStream fis = new FileInputStream(f1);
//此处在Windows读取换行时 \r\n
StringBuilder sb = new StringBuilder();
byte[] buff = new byte[4];
int len = 0;
while ((len = fis.read(buff)) != -1) {
sb.append(new String(buff,0,len));
}
System.out.println(sb.toString());
//read()一个一个读取
/*
int b = 0;
while ((b = fis.read()) != -1) {
System.out.println(b + " : " + (char) b);
}
*/
复制文件操作
private static void function02() throws IOException {
File source = new File("C:\\Users\\HENG\\Desktop\\aim.wmv");
File copy = new File("copy.wmv");
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(copy);
byte[] buff = new byte[1024 * 1024];
int len = 0;
while ((len = fis.read(buff)) != -1) {
fos.write(buff,0,len);
}
fis.close();
fos.close();
}
private static void function01() throws IOException {
File source = new File("C:\\Users\\HENG\\Desktop\\aim.wmv");
File copy = new File("copy.wmv");
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(copy);
int b = 0;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fis.close();
fos.close();
}
复制文件夹操作
public static void main(String[] args) {
File sourceDir = new File("C:\\Users\\HENG\\Desktop\\YD_Java");
File copyDir = new File("D:\\YD_Java");
copy(sourceDir,copyDir);
}
private static void copy(File sourceDir, File copyDir) {
if (!copyDir.exists()) {
copyDir.mkdir();
}
File[] files = sourceDir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isFile()) {
String sourceFilePath = file.getAbsolutePath();
String copyFilePath = copyDir.getAbsolutePath() + File.separator + file.getName();
copyFile(sourceFilePath,copyFilePath);
} else {
copy(file,new File(copyDir.getAbsolutePath() + File.separator + file.getName()));
}
}
}
private static void copyFile(String sourceFilePath, String copyFilePath) {
File sourceFile = new File(sourceFilePath);
File copyFile = new File(copyFilePath);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(copyFile);
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
fos.write(buf,0,len);
}
} catch (IOException e ) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
复制文件夹操作+过滤
// 只复制某一个类型的文件 .java
// 复制的时候也要保证文件路径结构
public static void main(String[] args) {
// File sourceDir = new File("C:\\Users\\HENG\\Desktop\\YD_Java");
File copyDir = new File("D:\\YD_Java");
// copy(sourceDir,copyDir);
deleteEmptyDir(copyDir);
}
private static void deleteEmptyDir(File copyDir) {
File[] files = copyDir.listFiles();
if (files == null || files.length == 0) { // ????0
System.out.println(copyDir.getName() + "被删掉了");
System.out.println(copyDir.delete());
}
for (File file : files) {
if (file.isDirectory()) {
deleteEmptyDir(file);
}
}
files = copyDir.listFiles();
if (files == null || files.length == 0) {
System.out.println(copyDir.getName() + "被删掉了");
System.out.println(copyDir.delete());
}
}
private static void copy(File sourceDir, File copyDir) {
if (!copyDir.exists()) {
copyDir.mkdir();
}
MyFileFilter mff = new MyFileFilter();
File[] files = sourceDir.listFiles(mff);
if (files == null) {
return;
}
for (File file : files) {
if (file.isFile()) {
String sourceFilePath = file.getAbsolutePath();
String copyFilePath = copyDir.getAbsolutePath() + File.separator + file.getName();
copyFile(sourceFilePath,copyFilePath);
} else {
copy(file,new File(copyDir.getAbsolutePath() + File.separator + file.getName()));
}
}
}
private static void copyFile(String sourceFilePath, String copyFilePath) {
File sourceFile = new File(sourceFilePath);
File copyFile = new File(copyFilePath);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(copyFile);
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
fos.write(buf,0,len);
}
} catch (IOException e ) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static class MyFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java") || pathname.isDirectory();
}
}
BufferedInputStream与BufferedOutputStream
BufferedInputStream与BufferedOutputStream都叫做缓冲流 目的就是为了提高IO效率 缓冲大小8mb
FileInputStream而言
无论是read()一个字节一个字节读取
还是read(byte[])一堆字节一堆字节读取
它们都是直接从硬盘上读取数据的
如果文件中有1000个字节的数据 每次对硬盘进行一次读取操作假设是1秒
read() 需要 1000秒
read(byte[10]) 需要100秒
BufferedInputStream 自身也带一个缓冲区
并且BufferedInputStream是其它InputStream(FileInputStream)的装饰类
FileInputStream纯粹是从硬盘进行读取数据 硬盘的计算速度跟不上内存的计算速度的
如果一个一个读 或者一批一批(阙值)读的话 速度相对而言都是慢的
BufferedInputStream自身内部有一个缓冲区在内存中 假设缓冲区大小为500
对于文件中1000个字节的数据只需要两次IO就读到内存中了 耗时2秒
第1次 读取500个 程序中再用byte[10]从内存缓冲区中进行读取 一次0.1秒 耗时5秒
如果前500个数据被读取完毕之后 要进行填充
第2次 读取500个 程序中再用byte[10]从内存缓冲区中进行读取 一次0.1秒 耗时5秒
总耗时12秒
BufferedOutputStream 程序先将数据byte[10]写入到缓冲区中byte[500] 等到缓冲区满的时候
一次将缓冲区的内容写入到硬盘文件中1秒
阙值的注意:如果FileInputStream read(byte[500])
File source = new File("C:\\Users\\HENG\\Desktop\\aim.wmv");
File copy = new File("copy.wmv");
FileInputStream fis = new FileInputStream(source);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(copy);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] buff = new byte[1024 * 1024];
int len = 0;
while ((len = bis.read(buff)) != -1) {
bos.write(buff,0,len);
}
bis.close();
bos.close();
字节流与编码
字符流 = 字节流 + 码表
字符串->二进制 编码
二进制->字符串 解码
//常见的码表 gbk GBK utf-8 UTF-8(是Unicode编码的一种)
//目前的IDEA环境 默认UTF-8编码
String s1 = “abc”;
System.out.println(Arrays.toString(s1.getBytes()));
System.out.println(Arrays.toString(s1.getBytes(“gbk”)));
System.out.println(Arrays.toString(s1.getBytes(“utf-8”)));
String s2 = “abc你好”;
System.out.println(Arrays.toString(s2.getBytes()));
System.out.println(Arrays.toString(s2.getBytes(“gbk”)));
System.out.println(Arrays.toString(s2.getBytes(“utf-8”)));
/*
[97, 98, 99, -60, -29, -70, -61]
[97, 98, 99, -28, -67, -96, -27, -91, -67]
在GBK当中 其实 任何一个字符 都是用两个字节存储的
[97, 98, 99, -60, -29, -70, -61]
也就是说“你好”在gbk当中是4字节 对应的结果 -60, -29, -70, -61
我们能否单独的把-60转成一个字符来对待?不能
对于一个gbk当中的汉字来说 由两个字节组成 并且这两个字节不能分开对待 必须作为一个整体来操作
为了避免用户将这种一对字节拆开操作 所以 结果是负数
一定都是负数吗?不一定
负数是咋来的?比如一个汉字的两个字节如下
00000100 11000101
00000100 这个字节作为汉字的第一个字节 所以取负数即可
11111011 + 1 = 11111100
11000101 由于连个字节被拆开了 后面的这个字节是否是负数 取决于第一位
[97, 98, 99, -28, -67, -96, -27, -91, -67]
在UTF-8码表里 有可能1字节、2字节、3字节、4字节
英文,数字,符号 1字节
汉字 3字节
在字符串“你好”中 两个汉字 6个字节 - 6个数字
-28, -67, -96 -> 你
-27, -91, -67 -> 好
InputStreamReader
XXXInputStream 字节输入流
XXXOutputStream 字节输出流
XXXReader 字符输入流
XXXWriter 字符输出流
从硬盘读取字节 将字节转为字符 转换流
public static void main(String[] args) throws IOException {
File f1 = new File("第11章笔记.txt");
FileInputStream fis = new FileInputStream(f1);
InputStreamReader isr = new InputStreamReader(fis,"gbk");
char[] cbuf = new char[100];
int len = 0;
while ((len = isr.read(cbuf)) != -1) {
System.out.println(new String(cbuf));
}
isr.close();
InputStreamReader
// XXXInputStream 字节输入流
// XXXOutputStream 字节输出流
// XXXReader 字符输入流
// XXXWriter 字符输出流
// 从硬盘读取字节 将字节转为字符 转换流
public static void main(String[] args) throws IOException {
File f1 = new File("第11章笔记.txt");
FileInputStream fis = new FileInputStream(f1);
InputStreamReader isr = new InputStreamReader(fis,"gbk");
char[] cbuf = new char[100];
int len = 0;
while ((len = isr.read(cbuf)) != -1) {
System.out.println(new String(cbuf));
}
isr.close();
}
OutputStreamWriter
// 将字符 转换为字节 然后写入到硬盘
public static void main(String[] args) throws IOException {
//赋值一个文本文件
File f1 = new File("第11章笔记.txt");
File f2 = new File("第11章笔记_copy.txt");
FileInputStream fis = new FileInputStream(f1);
FileOutputStream fos = new FileOutputStream(f2);
InputStreamReader isr = new InputStreamReader(fis);
OutputStreamWriter osw = new OutputStreamWriter(fos);
char[] cbuf = new char[100];
int len = 0;
while ((len = isr.read(cbuf)) != -1) {
osw.write(cbuf,0,len);
}
isr.close();
osw.close();
}
FileReader
Reader
InputStreamRead
FileReader 功能= InputStreamRead + FileInputStream
FileWriter
Writer
OutputStreamWriter
FileWriter
FileReader和FileWriter 本质上底层还是用字节流来操作
但是自身又拥有转换的功能 所以相当于是
FileReader 功能= InputStreamRead + FileInputStream
FileWriter 功能= OutputStreamWriter + FileOutputStream
FileReader FileWriter 不能再操作非文本文件了
其次 FileReader FileWriter 不能进行指定编码表 字符集
public static void main(String[] args) throws IOException {
//复制一个文本文件
FileReader fr = new FileReader("第10章笔记.txt");
FileWriter fw = new FileWriter("第10章笔记_copy.txt");
char[] cbuf = new char[100];
int len = 0;
while ((len = fr.read(cbuf)) != -1) {
fw.write(cbuf,0,len);
}
fr.close();
fw.close();
}
BufferedReader与BufferedWriter
//复制一个文本文件
FileReader fr = new FileReader("第10章笔记.txt");
FileWriter fw = new FileWriter("第10章笔记_copy.txt");
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
流的操作规律
(1)确定来源和目的
来源:数据从哪里来 文件 网络 控制台 内存
目的:数据区哪里 文件 网络 控制台 内存
(2)确定字节流还是字符流
字符流:纯文本数据
字节流:非纯文本数据
批量复制文本文件
// 需求:将当前工程目录中的所有.java文件 复制到另一个文件夹之中
public static void main(String[] args) {
File sourceDir = new File("C:\\Users\\HENG\\Desktop\\YD_Java");
File copyDir = new File("JavaSourceCode");
if (!copyDir.exists()) {
copyDir.mkdir();
}
copyJavaFile(sourceDir,copyDir);
}
private static void copyJavaFile(File sourceDir, File copyDir) {
//匿名实现子类(内部类-局部)的匿名对象
//一般是在创建某一个接口的实现子类对象的时候使用
File[] files = sourceDir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory() || file.getName().endsWith(".java");
}
});
if (files == null || files.length == 0) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
copyJavaFile(file,copyDir);
} else {
copyFile(file,new File(copyDir.getAbsolutePath() + File.separator + file.getName()));
}
}
}
private static void copyFile(File sourceFile, File copyFile) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile)));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(copyFile),"gbk"));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件切割与合并
// 切割的代码 一个输入流 多个输出流
public static void main(String[] args) throws Exception {
int count = 1;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("music.mp3"));
byte[] buf = new byte[1024 * 1024 * 2];
BufferedOutputStream bos = null;
int len = 0;
while ((len = bis.read(buf)) != -1) {
bos = new BufferedOutputStream(new FileOutputStream("music.mp3.part" + count++));
bos.write(buf,0,len);
bos.close();
}
bis.close();
}
合并的代码 多个输入流 一个输出流
public static void main(String[] args) throws Exception {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("music_copy.mp3"));
for (int i = 1; i <= 7; i++) {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("music.mp3.part" + i));
byte[] buf = new byte[100];
int len = 0;
while ((len = bis.read(buf)) != -1) {
bos.write(buf,0,len);
}
bis.close();
}
bos.close();
}