IO操作
File类概述和构造方法
File类的概述
文件和目录路径名的抽象表示形式
构造方法
public File(String pathname)
public File(String parent,String child)
public File(File parent,String child)
import java.io.File; /* * 我们要想实现IO的操作,就必须知道硬盘上文件的表现形式。 * 而Java就提供了一个类File供我们使用。 * * File:文件和目录(文件夹)路径名的抽象表示形式 * 构造方法: * File(String pathname):根据一个路径得到File对象 * File(String parent, String child):根据一个目录和一个子文件/目录得到File对象 * File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象 */ public class FileDemo { public static void main(String[] args) { // File(String pathname):根据一个路径得到File对象 // 把e:\\demo\\a.txt封装成一个File对象 File file = new File("E:\\demo\\a.txt"); // File(String parent, String child):根据一个目录和一个子文件/目录得到File对象 File file2 = new File("E:\\demo", "a.txt"); // File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象 File file3 = new File("e:\\demo"); File file4 = new File(file3, "a.txt"); // 以上三种方式其实效果一样 } }
File类的成员方法
创建功能
public boolean createNewFile()
public boolean mkdir()
public boolean mkdirs()
删除功能
public boolean delete()
重命名功能
public boolean renameTo(File dest)
创建功能
/*
*创建功能:
*public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
*public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
*public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
*
*骑白马的不一定是王子,可能是班长。
*注意:你到底要创建文件还是文件夹,你最清楚,方法不要调错了。
*/
public class FileDemo { public static void main(String[] args) throws IOException { // 需求:我要在e盘目录下创建一个文件夹demo File file = new File("e:\\demo"); System.out.println("mkdir:" + file.mkdir()); // 需求:我要在e盘目录demo下创建一个文件a.txt File file2 = new File("e:\\demo\\a.txt"); System.out.println("createNewFile:" + file2.createNewFile()); // 需求:我要在e盘目录test下创建一个文件b.txt // Exception in thread "main" java.io.IOException: 系统找不到指定的路径。 // 注意:要想在某个目录下创建内容,该目录首先必须存在。 // File file3 = new File("e:\\test\\b.txt"); // System.out.println("createNewFile:" + file3.createNewFile()); // 需求:我要在e盘目录test下创建aaa目录 // File file4 = new File("e:\\test\\aaa"); // System.out.println("mkdir:" + file4.mkdir()); // File file5 = new File("e:\\test"); // File file6 = new File("e:\\test\\aaa"); // System.out.println("mkdir:" + file5.mkdir()); // System.out.println("mkdir:" + file6.mkdir()); // 其实我们有更简单的方法 File file7 = new File("e:\\aaa\\bbb\\ccc\\ddd"); System.out.println("mkdirs:" + file7.mkdirs()); // 看下面的这个东西: File file8 = new File("e:\\liuyi\\a.txt"); System.out.println("mkdirs:" + file8.mkdirs()); } }
/*
* 删除功能:public boolean delete()
*
* 注意:
* A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
* B:Java中的删除不走回收站。
* C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
*/
public class FileDemo { public static void main(String[] args) throws IOException { // 创建文件 // File file = new File("e:\\a.txt"); // System.out.println("createNewFile:" + file.createNewFile()); // 我不小心写成这个样子了 File file = new File("a.txt"); System.out.println("createNewFile:" + file.createNewFile()); // 继续玩几个 File file2 = new File("aaa\\bbb\\ccc"); System.out.println("mkdirs:" + file2.mkdirs()); // 删除功能:我要删除a.txt这个文件 File file3 = new File("a.txt"); System.out.println("delete:" + file3.delete()); // 删除功能:我要删除ccc这个文件夹 File file4 = new File("aaa\\bbb\\ccc"); System.out.println("delete:" + file4.delete()); // 删除功能:我要删除aaa文件夹 // File file5 = new File("aaa"); // System.out.println("delete:" + file5.delete()); File file6 = new File("aaa\\bbb"); File file7 = new File("aaa"); System.out.println("delete:" + file6.delete()); System.out.println("delete:" + file7.delete()); } }
重命名功能
/*
* 重命名功能:public boolean renameTo(File dest)
* 如果路径名相同,就是改名。
* 如果路径名不同,就是改名并剪切。
*
* 路径以盘符开始:绝对路径c:\\a.txt
* 路径不以盘符开始:相对路径a.txt
*/
public class FileDemo { public static void main(String[] args) { // 创建一个文件对象 // File file = new File("林青霞.jpg"); // // 需求:我要修改这个文件的名称为"东方不败.jpg" // File newFile = new File("东方不败.jpg"); // System.out.println("renameTo:" + file.renameTo(newFile)); File file2 = new File("东方不败.jpg"); File newFile2 = new File("e:\\林青霞.jpg"); System.out.println("renameTo:" + file2.renameTo(newFile2)); } }
判断功能
/*
* 判断功能:
* public boolean isDirectory():判断是否是目录
* public boolean isFile():判断是否是文件
* public boolean exists():判断是否存在
* public boolean canRead():判断是否可读
* public boolean canWrite():判断是否可写
* public boolean isHidden():判断是否隐藏
*/
public class FileDemo { public static void main(String[] args) { // 创建文件对象 File file = new File("a.txt"); System.out.println("isDirectory:" + file.isDirectory());// false System.out.println("isFile:" + file.isFile());// true System.out.println("exists:" + file.exists());// true System.out.println("canRead:" + file.canRead());// true System.out.println("canWrite:" + file.canWrite());// true System.out.println("isHidden:" + file.isHidden());// false } }基本获取功能
public String getAbsolutePath()
public String getPath()
public String getName()
public long length()
public long lastModified()
高级获取功能
public String[] list()
public File[] listFiles()
/*
* 获取功能:
* public String getAbsolutePath():获取绝对路径
* public String getPath():获取相对路径
* public String getName():获取名称
* public long length():获取长度。字节数
* public long lastModified():获取最后一次的修改时间,毫秒值
*/
public class FileDemo { public static void main(String[] args) { // 创建文件对象 File file = new File("demo\\test.txt"); System.out.println("getAbsolutePath:" + file.getAbsolutePath()); System.out.println("getPath:" + file.getPath()); System.out.println("getName:" + file.getName()); System.out.println("length:" + file.length()); System.out.println("lastModified:" + file.lastModified()); // 1416471971031 Date d = new Date(1416471971031L); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String s = sdf.format(d); System.out.println(s); } }高级功能
import java.io.File; /* * 获取功能: * public String[] list():获取指定目录下的所有文件或者文件夹的名称数组 * public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组 */ public class FileDemo { public static void main(String[] args) { // 指定一个目录 File file = new File("e:\\"); // public String[] list():获取指定目录下的所有文件或者文件夹的名称数组 String[] strArray = file.list(); for (String s : strArray) { System.out.println(s); } System.out.println("------------"); // public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组 File[] fileArray = file.listFiles(); for (File f : fileArray) { System.out.println(f.getName()); } } }File类练习
判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称
import java.io.File; /* * 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称 * * 分析: * A:封装e判断目录 * B:获取该目录下所有文件或者文件夹的File数组 * C:遍历该File数组,得到每一个File对象,然后判断 * D:是否是文件 * 是:继续判断是否以.jpg结尾 * 是:就输出该文件名称 * 否:不搭理它 * 否:不搭理它 */ public class FileDemo { public static void main(String[] args) { // 封装e判断目录 File file = new File("e:\\"); // 获取该目录下所有文件或者文件夹的File数组 File[] fileArray = file.listFiles(); // 遍历该File数组,得到每一个File对象,然后判断 for (File f : fileArray) { // 是否是文件 if (f.isFile()) { // 继续判断是否以.jpg结尾 if (f.getName().endsWith(".jpg")) { // 就输出该文件名称 System.out.println(f.getName()); } } } } }
实现二;
/*
* 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称
* A:先获取所有的,然后遍历的时候,依次判断,如果满足条件就输出。
* B:获取的时候就已经是满足条件的了,然后输出即可。
*
* 要想实现这个效果,就必须学习一个接口:文件名称过滤器
* public String[] list(FilenameFilter filter)
* public File[] listFiles(FilenameFilter filter)
*/
public class FileDemo2 { public static void main(String[] args) { // 封装e判断目录 File file = new File("e:\\"); // 获取该目录下所有文件或者文件夹的String数组 // public String[] list(FilenameFilter filter) String[] strArray = file.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { // return false; // return true; // 通过这个测试,我们就知道了,到底把这个文件或者文件夹的名称加不加到数组中,取决于这里的返回值是true还是false // 所以,这个的true或者false应该是我们通过某种判断得到的 // System.out.println(dir + "---" + name); // File file = new File(dir, name); // // System.out.println(file); // boolean flag = file.isFile(); // boolean flag2 = name.endsWith(".jpg"); // return flag && flag2; return new File(dir, name).isFile() && name.endsWith(".jpg"); } }); // 遍历 for (String s : strArray) { System.out.println(s); } } }
改成
/*
* 需求:把E:\评书\三国演义下面的视频名称修改为
* 00?_介绍.avi
*
* 思路:
* A:封装目录
* B:获取该目录下所有的文件的File数组
* C:遍历该File数组,得到每一个File对象
* D:拼接一个新的名称,然后重命名即可。
*/
public class FileDemo { public static void main(String[] args) { // 封装目录 File srcFolder = new File("E:\\评书\\三国演义"); // 获取该目录下所有的文件的File数组 File[] fileArray = srcFolder.listFiles(); // 遍历该File数组,得到每一个File对象 for (File file : fileArray) { // System.out.println(file); // E:\评书\三国演义\三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi // 改后:E:\评书\三国演义\001_桃园三结义.avi String name = file.getName(); // 三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi int index = name.indexOf("_"); String numberString = name.substring(index + 1, index + 4); // System.out.println(numberString); // int startIndex = name.lastIndexOf('_'); // int endIndex = name.lastIndexOf('.'); // String nameString = name.substring(startIndex + 1, endIndex); // System.out.println(nameString); int endIndex = name.lastIndexOf('_'); String nameString = name.substring(endIndex); String newName = numberString.concat(nameString); // 001_桃园三结义.avi // System.out.println(newName); File newFile = new File(srcFolder, newName); // E:\\评书\\三国演义\\001_桃园三结义.avi // 重命名即可 file.renameTo(newFile); } } }递归
递归解决问题的思想
找到出口
找到规律
求阶乘案例
普通for循环
递归实现
画内存图
断点查看执行流程
递归
方法定义中调用方法本身的现象
Public void show(){
Show();
System.exit(0);
return;
}
递归注意实现
要有出口,否则就是死递归
次数不能太多,否则就内存溢出
构造方法不能递归使用
/*
* 递归:方法定义中调用方法本身的现象
*
* 方法的嵌套调用,这不是递归。
* Math.max(Math.max(a,b),c);
*
* public void show(int n) {
* if(n <= 0) {
* System.exit(0);
* }
* System.out.println(n);
* show(--n);
* }
*
* 注意事项:
* A:递归一定要有出口,否则就是死递归
* B:递归的次数不能太多,否则就内存溢出
* C:构造方法不能递归使用
*
* 举例:
* A:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
* 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
* 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
* 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
* ...
* 庙挂了,或者山崩了
* B:学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
* 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
* 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
* 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
* ...
* 娶不到媳妇或者生不了娃娃
*/
public class DiGuiDemo {
// public DiGuiDemo() {
// DiGuiDemo();
// }
}
递归的思路内存图
/*
* 需求:请用代码实现求5的阶乘。
* 下面的知识要知道:
* 5! = 1*2*3*4*5
* 5! = 5*4!
*
* 有几种方案实现呢?
* A:循环实现
* B:递归实现
* a:做递归要写一个方法
* b:出口条件
* c:规律
*/
public class DiGuiDemo { public static void main(String[] args) { int jc = 1; for (int x = 2; x <= 5; x++) { jc *= x; } System.out.println("5的阶乘是:" + jc); System.out.println("5的阶乘是:"+jieCheng(5)); } /* * 做递归要写一个方法: * 返回值类型:int * 参数列表:int n * 出口条件: * if(n == 1) {return 1;} * 规律: * if(n != 1) {return n*方法名(n-1);} */ public static int jieCheng(int n){ if(n==1){ return 1; }else { return n*jieCheng(n-1); } } }
案例请大家把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
/*
* 需求:请大家把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
*
* 分析:
* A:封装目录
* B:获取该目录下所有的文件或者文件夹的File数组
* C:遍历该File数组,得到每一个File对象
* D:判断该File对象是否是文件夹
* 是:回到B
* 否:继续判断是否以.java结尾
* 是:就输出该文件的绝对路径
* 否:不搭理它
*/
public class FilePathDemo { public static void main(String[] args) { // 封装目录 File srcFolder = new File("E:\\JavaSE"); // 递归功能实现 getAllJavaFilePaths(srcFolder); } private static void getAllJavaFilePaths(File srcFolder) { // 获取该目录下所有的文件或者文件夹的File数组 File[] fileArray = srcFolder.listFiles(); // 遍历该File数组,得到每一个File对象 for (File file : fileArray) { // 判断该File对象是否是文件夹 if (file.isDirectory()) { getAllJavaFilePaths(file); } else { // 继续判断是否以.java结尾 if (file.getName().endsWith(".java")) { // 就输出该文件的绝对路径 System.out.println(file.getAbsolutePath()); } } } } }
递归删除带内容的目录
/*
* 需求:递归删除带内容的目录
*
* 目录我已经给定:demo
*
* 分析:
* A:封装目录
* B:获取该目录下的所有文件或者文件夹的File数组
* C:遍历该File数组,得到每一个File对象
* D:判断该File对象是否是文件夹
* 是:回到B
* 否:就删除
*/
public class FileDeleteDemo { public static void main(String[] args) { // 封装目录 File srcFolder = new File("demo"); // 递归实现 deleteFolder(srcFolder); } private static void deleteFolder(File srcFolder) { // 获取该目录下的所有文件或者文件夹的File数组 File[] fileArray = srcFolder.listFiles(); if (fileArray != null) { // 遍历该File数组,得到每一个File对象 for (File file : fileArray) { // 判断该File对象是否是文件夹 if (file.isDirectory()) { deleteFolder(file); } else { System.out.println(file.getName() + "---" + file.delete()); } } System.out .println(srcFolder.getName() + "---" + srcFolder.delete()); } } }IO流概述
IO流用来处理设备之间的数据传输
上传文件和下载文件
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
IO流分类
按照数据流向
输入流读入数据
输出流写出数据
按照数据类型
字节流
字符流
什么情况下使用哪种流呢?
如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流。
如果你什么都不知道,就用字节流
IO流常用基类
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
字节流写数据
OutputStream
FileOutputStream
往一个文本文件中写一句话:”helloworld”
分析发现其实更适合用字符流,但是由于字节流先出现,所以,我们考虑先使用字节流后面再讲会什么出现字符流。
FileOutputStream的构造方法
FileOutputStream(File file)
FileOutputStream(String name)
/*
* IO流的分类:
* 流向:
* 输入流读取数据
* 输出流 写出数据
* 数据类型:
* 字节流
* 字节输入流读取数据InputStream
* 字节输出流写出数据OutputStream
* 字符流
* 字符输入流读取数据Reader
* 字符输出流写出数据Writer
*
* 注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。
*
* 需求:我要往一个文本文件中输入一句话:"hello,io"
*
* 分析:
* A:这个操作最好是采用字符流来做,但是呢,字符流是在字节流之后才出现的,所以,今天我先讲解字节流如何操作。
* B:由于我是要往文件中写一句话,所以我们要采用字节输出流。
*
* 通过上面的分析后我们知道要使用:OutputStream
* 但是通过查看API,我们发现该流对象是一个抽象类,不能实例化。
* 所以,我们要找一个具体的子类。
* 而我们要找的子类是什么名字的呢?这个时候,很简单,我们回想一下,我们是不是要往文件中写东西。
* 文件是哪个单词:File
* 然后用的是字节输出流,联起来就是:FileOutputStream
* 注意:每种基类的子类都是以父类名作为后缀名。
* XxxOutputStream
* XxxInputStream
* XxxReader
* XxxWriter
* 查看FileOutputStream的构造方法:
* FileOutputStream(File file)
*FileOutputStream(String name)
*
* 字节输出流操作步骤:
* A:创建字节输出流对象
* B:写数据
* C:释放资源
*/
public class FileOutputStreamDemo { public static void main(String[] args) throws IOException { // 创建字节输出流对象 // FileOutputStream(File file) // File file = new File("fos.txt"); // FileOutputStream fos = new FileOutputStream(file); // FileOutputStream(String name) FileOutputStream fos = new FileOutputStream("fos.txt"); /* * 创建字节输出流对象了做了几件事情: * A:调用系统功能去创建文件 * B:创建fos对象 * C:把fos对象指向这个文件 */ //写数据 fos.write("hello,IO".getBytes()); fos.write("java".getBytes()); //释放资源 //关闭此文件输出流并释放与此流有关的所有系统资源。 fos.close(); /* * 为什么一定要close()呢? * A:让流对象变成垃圾,这样就可以被垃圾回收器回收了 * B:通知系统去释放跟该文件相关的资源 */ //java.io.IOException: Stream Closed //fos.write("java".getBytes()); } }
字节流写数据的方式
public void write(int b)
public void write(byte[] b)
public void write(byte[] b,int off,int len)
/*
* 字节输出流操作步骤:
* A:创建字节输出流对象
* B:调用write()方法
* C:释放资源
*
* public void write(int b):写一个字节
* public void write(byte[] b):写一个字节数组
* public void write(byte[] b,int off,int len):写一个字节数组的一部分
*/
public class FileOutputStreamDemo2 { public static void main(String[] args) throws IOException { // 创建字节输出流对象 // OutputStream os = new FileOutputStream("fos2.txt"); // 多态 FileOutputStream fos = new FileOutputStream("fos2.txt"); // 调用write()方法 //fos.write(97); //97 -- 底层二进制数据-- 通过记事本打开 -- 找97对应的字符值 -- a // fos.write(57); // fos.write(55); //public void write(byte[] b):写一个字节数组 byte[] bys={97,98,99,100,101}; fos.write(bys); //public void write(byte[] b,int off,int len):写一个字节数组的一部分 fos.write(bys,1,3); //释放资源 fos.close(); } }
字节流写数据常见问题
数据写成功后,为什么要close()?
如何实现数据的换行?
如何实现数据的追加写入?
/*
* 如何实现数据的换行?
* 为什么现在没有换行呢?因为你只写了字节数据,并没有写入换行符号。
* 如何实现呢?写入换行符号即可呗。
* 刚才我们看到了有写文本文件打开是可以的,通过windows自带的那个不行,为什么呢?
* 因为不同的系统针对不同的换行符号识别是不一样的?
* windows:\r\n
* linux:\n
* Mac:\r
* 而一些常见的个高级记事本,是可以识别任意换行符号的。
*
* 如何实现数据的追加写入?
* 用构造方法带第二个参数是true的情况即可
*/
public class FileOutputStreamDemo3 { public static void main(String[] args) throws IOException { // 创建字节输出流对象 // FileOutputStream fos = new FileOutputStream("fos3.txt"); // 创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。 FileOutputStream fos = new FileOutputStream("fos3.txt", true); // 写数据 for (int x = 0; x < 10; x++) { fos.write(("hello" + x).getBytes()); fos.write("\r\n".getBytes()); } // 释放资源 fos.close(); } }
异常处理
/*
* 加入异常处理的字节输出流操作
*/
public class FileOutputStreamDemo4 { public static void main(String[] args) { // 分开做异常处理 // FileOutputStream fos = null; // try { // fos = new FileOutputStream("fos4.txt"); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } // // try { // fos.write("java".getBytes()); // } catch (IOException e) { // e.printStackTrace(); // } // // try { // fos.close(); // } catch (IOException e) { // e.printStackTrace(); // } // 一起做异常处理 // try { // FileOutputStream fos = new FileOutputStream("fos4.txt"); // fos.write("java".getBytes()); // fos.close(); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } catch (IOException e) { // e.printStackTrace(); // } // 改进版 // 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值 FileOutputStream fos = null; try { // fos = new FileOutputStream("z:\\fos4.txt"); fos = new FileOutputStream("fos4.txt"); fos.write("java".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 如果fos不是null,才需要close() if (fos != null) { // 为了保证close()一定会执行,就放到这里了 try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
字节流读取数据
inputStream
FileInputStream
把刚才写的数据读取出来显示在控制台
FileInputStream的构造方法
FileInputStream(File file)
FileInputStream(String name)
FileInputStream的成员方法
public int read()
public int read(byte[] b)
/*
* 字节输入流操作步骤:
* A:创建字节输入流对象
* B:调用read()方法读取数据,并把数据显示在控制台
* C:释放资源
*
* 读取数据的方式:
* A:int read():一次读取一个字节
* B:int read(byte[] b):一次读取一个字节数组
*/
public class FileInputStreamDemo { public static void main(String[] args) throws IOException { // FileInputStream(String name) // FileInputStream fis = new FileInputStream("fis.txt"); FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java"); // // 调用read()方法读取数据,并把数据显示在控制台 // // 第一次读取 // int by = fis.read(); // System.out.println(by); // System.out.println((char) by); // // // 第二次读取 // by = fis.read(); // System.out.println(by); // System.out.println((char) by); // // // 第三次读取 // by = fis.read(); // System.out.println(by); // System.out.println((char) by); // // 我们发现代码的重复度很高,所以我们要用循环改进 // // 而用循环,最麻烦的事情是如何控制循环判断条件呢? // // 第四次读取 // by = fis.read(); // System.out.println(by); // // 第五次读取 // by = fis.read(); // System.out.println(by); // //通过测试,我们知道如果你读取的数据是-1,就说明已经读取到文件的末尾了 // 用循环改进 // int by = fis.read(); // while (by != -1) { // System.out.print((char) by); // by = fis.read(); // } // 最终版代码 int by = 0; // 读取,赋值,判断 while ((by = fis.read()) != -1) { System.out.print((char) by); } // 释放资源 fis.close(); } }
把当前项目目目录下的a.txt内容复制到当前项目目录下的b.txt中
/*
* 复制文本文件。
*
* 数据源:从哪里来
* a.txt--读取数据--FileInputStream
*
* 目的地:到哪里去
* b.txt--写数据--FileOutputStream
*
* java.io.FileNotFoundException: a.txt (系统找不到指定的文件。)
*
* 这一次复制中文没有出现任何问题,为什么呢?
* 上一次我们出现问题的原因在于我们每次获取到一个字节数据,就把该字节数据转换为了字符数据,然后输出到控制台。
* 而这一次呢?确实通过IO流读取数据,写到文本文件,你读取一个字节,我就写入一个字节,你没有做任何的转换。
* 它会自己做转换。
*/
public class CopyFileDemo { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("a.txt"); // 封装目的地 FileOutputStream fos = new FileOutputStream("b.txt"); int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } // 释放资源(先关谁都行) fos.close(); fis.close(); } }
把c盘下的a.txt的内容复制到d盘下的b.txt中
/*
* 需求:把c盘下的a.txt的内容复制到d盘下的b.txt中
*
* 数据源:
* c:\\a.txt--读取数据--FileInputStream
* 目的地:
* d:\\b.txt--写出数据--FileOutputStream
*/
public class CopyFileDemo2 { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("c:\\a.txt"); // 封装目的地 FileOutputStream fos = new FileOutputStream("d:\\b.txt"); // 复制数据 int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } // 释放资源 fos.close(); fis.close(); } }
把e:\\林青霞.jpg内容复制到当前项目目录下的mn.jpg中
/*
* 需求:把e:\\林青霞.jpg内容复制到当前项目目录下的mn.jpg中
*
* 数据源:
* e:\\林青霞.jpg--读取数据--FileInputStream
* 目的地:
* mn.jpg--写出数据--FileOutputStream
*/
public class CopyImageDemo { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("e:\\林青霞.jpg"); // 封装目的地 FileOutputStream fos = new FileOutputStream("mn.jpg"); // 复制数据 int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } // 释放资源 fos.close(); fis.close(); } }
复制视频
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中 * * 数据源: * e:\\哥有老婆.mp4--读取数据--FileInputStream * 目的地: * copy.mp4--写出数据--FileOutputStream */ public class CopyMp4Demo { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("e:\\哥有老婆.mp4"); // 封装目的地 FileOutputStream fos = new FileOutputStream("copy.mp4"); // 复制数据 int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } // 释放资源 fos.close(); fis.close(); } }一次一个数组读取
import java.io.FileInputStream; import java.io.IOException; /* * 一次读取一个字节数组:int read(byte[] b) * 返回值其实是实际读取的字节个数。 */ public class FileInputStreamDemo2 { public static void main(String[] args) throws IOException { // 创建字节输入流对象 // FileInputStream fis = new FileInputStream("fis2.txt"); FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java"); // 读取数据 // 定义一个字节数组 // 第一次读取 // byte[] bys = new byte[5]; // int len = fis.read(bys); // // System.out.println(len); // // System.out.println(new String(bys)); // // System.out.println(new String(bys, 0, len)); // System.out.print(new String(bys, 0, len)); // // // 第二次读取 // len = fis.read(bys); // // System.out.println(len); // // System.out.println(new String(bys)); // // System.out.println(new String(bys, 0, len)); // System.out.print(new String(bys, 0, len)); // // // 第三次读取 // len = fis.read(bys); // // System.out.println(len); // // System.out.println(new String(bys)); // // System.out.println(new String(bys, 0, len)); // System.out.print(new String(bys, 0, len)); // // // 第四次读取 // len = fis.read(bys); // // System.out.println(len); // // System.out.println(new String(bys, 0, len)); // System.out.print(new String(bys, 0, len)); // // 代码重复了,用循环改进 // // 但是,我不知道结束条件 // // len = fis.read(bys); // // System.out.println(len); // // len = fis.read(bys); // // System.out.println(len); // // 如果读取到的实际长度是-1,就说明没有数据了 // byte[] bys = new byte[115]; // 0 // int len = 0; // while ((len = fis.read(bys)) != -1) { // System.out.print(new String(bys, 0, len)); // // System.out.print(new String(bys)); //千万要带上len的使用 // } // 最终版代码 // 数组的长度一般是1024或者1024的整数倍 byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { System.out.print(new String(bys, 0, len)); } // 释放资源 fis.close(); } }
二次比较
字节流读取数据两种方式图解比较
一次读取一个字节
一次读取一个字节数组
每次可以读取多个数据,提高了操作效率
字符数组读取
/*
* 需求:把c:\\a.txt内容复制到d:\\b.txt中
*
* 数据源:
* c:\\a.txt--读取数据--FileInputStream
* 目的地:
* d:\\b.txt--写出数据--FileOutputStream
*/
public class CopyFileDemo { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("c:\\a.txt"); FileOutputStream fos = new FileOutputStream("d:\\b.txt"); // 复制数据 byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } // 释放资源 fos.close(); fis.close(); } }mp4复制到当前项目目录下的copy.mp4
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中 * * 数据源: * e:\\哥有老婆.mp4--读取数据--FileInputStream * 目的地: * copy.mp4--写出数据--FileOutputStream */ public class CopyMp4Demo { public static void main(String[] args) throws IOException { // 封装数据源 FileInputStream fis = new FileInputStream("e:\\哥有老婆.mp4"); // 封装目的地 FileOutputStream fos = new FileOutputStream("copy.mp4"); // 复制数据 byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } // 释放资源 fos.close(); fis.close(); } }字节缓冲流
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
字节缓冲输出流
BufferedOutputStream
字节缓冲输入流
BufferedInputStream
import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; /* * 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非常好的。 * 既然是这样的话,那么,java开始在设计的时候,它也考虑到了这个问题,就专门提供了带缓冲区的字节类。 * 这种类被称为:缓冲区类(高效类) * 写数据:BufferedOutputStream * 读数据:BufferedInputStream * * 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。 * * 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢? * 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。 */ public class BufferedOutputStreamDemo { public static void main(String[] args) throws IOException { // BufferedOutputStream(OutputStream out) // FileOutputStream fos = new FileOutputStream("bos.txt"); // BufferedOutputStream bos = new BufferedOutputStream(fos); // 简单写法 BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("bos.txt")); // 写数据 bos.write("hello".getBytes()); // 释放资源 bos.close(); } }
读数据操作
/*
* 注意:虽然我们有两种方式可以读取,但是,请注意,这两种方式针对同一个对象在一个代码中只能使用一个。
*/
public class BufferedInputStreamDemo { public static void main(String[] args) throws IOException { // BufferedInputStream(InputStream in) BufferedInputStream bis = new BufferedInputStream(new FileInputStream( "bos.txt")); // 读取数据 // int by = 0; // while ((by = bis.read()) != -1) { // System.out.print((char) by); // } // System.out.println("---------"); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { System.out.print(new String(bys, 0, len)); } // 释放资源 bis.close(); } }四种读写的比较
/*
* 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中
*
* 字节流四种方式复制文件:
* 基本字节流一次读写一个字节:共耗时:117235毫秒
* 基本字节流一次读写一个字节数组: 共耗时:156毫秒
* 高效字节流一次读写一个字节: 共耗时:1141毫秒
* 高效字节流一次读写一个字节数组: 共耗时:47毫秒
*/
public class CopyMp4Demo { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); // method1("e:\\哥有老婆.mp4", "copy1.mp4"); // method2("e:\\哥有老婆.mp4", "copy2.mp4"); // method3("e:\\哥有老婆.mp4", "copy3.mp4"); method4("e:\\哥有老婆.mp4", "copy4.mp4"); long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end - start) + "毫秒"); } // 高效字节流一次读写一个字节数组: public static void method4(String srcString, String destString) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream( srcString)); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(destString)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } // 高效字节流一次读写一个字节: public static void method3(String srcString, String destString) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream( srcString)); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(destString)); int by = 0; while ((by = bis.read()) != -1) { bos.write(by); } bos.close(); bis.close(); } // 基本字节流一次读写一个字节数组 public static void method2(String srcString, String destString) throws IOException { FileInputStream fis = new FileInputStream(srcString); FileOutputStream fos = new FileOutputStream(destString); byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } fos.close(); fis.close(); } // 基本字节流一次读写一个字节 public static void method1(String srcString, String destString) throws IOException { FileInputStream fis = new FileInputStream(srcString); FileOutputStream fos = new FileOutputStream(destString); int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } fos.close(); fis.close(); } }总结
1:递归(理解)
(1)方法定义中调用方法本身的现象
举例:老和尚给小和尚讲故事,我们学编程
(2)递归的注意事项;
A:要有出口,否则就是死递归
B:次数不能过多,否则内存溢出
C:构造方法不能递归使用
(3)递归的案例:
A:递归求阶乘
C:递归输出指定目录下所有指定后缀名的文件绝对路径
D:递归删除带内容的目录(小心使用)
2:IO流(掌握)
(1)IO用于在设备间进行数据传输的操作
(2)分类:
A:流向
输入流读取数据
输出流写出数据
B:数据类型
字节流
字节输入流
字节输出流
字符流
字符输入流
字符输出流
注意:
a:如果我们没有明确说明按照什么分,默认按照数据类型分。
b:除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。
(3)FileOutputStream写出数据
A:操作步骤
a:创建字节输出流对象
b:调用write()方法
c:释放资源
B:代码体现:
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("hello".getBytes());
fos.close();
C:要注意的问题?
a:创建字节输出流对象做了几件事情?
b:为什么要close()?
c:如何实现数据的换行?
d:如何实现数据的追加写入?
(4)FileInputStream读取数据
A:操作步骤