目录
IO原理
1. 计算机体系结构
2. 硬盘存储——文件操作
3. 在Java中,实现基本的IO操作
1. 计算机体系结构
硬件:处理器(CPU)、存储器(内存)、输入设备(Input Device)、输出设备(Output Device)
其中CPU只能和内存做直接的数据交换。
Input Device:现实中的物理信号(光信号、电信号、波信号)->数字个数,存储在内存中。Output Device:数字->物理信号
IO设备:显示器(O)、触屏显示器(IO)、鼠标(I)、键盘(I)、摄像头(I)、麦克风(I)、扬声器(O)
硬盘(IO)、网卡(IO)
2. 硬盘——存储
计算机存储常识
易失存储:
1.断电后丢失
2.以进程为单位管理变量、对象本质上的编程语言对硬件中内存的抽象
持久存储:
1.断电后一般仍能保存
2.通常可以跨进程读写
各个存储访问速度的一个直观感受
内存(Memory):又被称为RAM(Random Access Memory)。
支持以O(1)时间复杂度,根据下标(内存地址)访问的存储。硬盘
硬盘的实现Hard Disk Drive (HDD)
1. 磁盘(利用磁性实现的一种存储方式)、硬盘(机械硬盘)
磁盘寻址:磁盘更适合做连续数据的读写,而不适合做随机数据的读写。
2. 固态硬盘(Solid State Disk SSD)
3. 闪存(Flash Memory)
软件层面认识硬盘中的数据
硬盘数据的读写->文件的读写问题
由OS+文件系统(FileSystem),统一管理文件。
文件基本知识
我们看到的文件的基本知识
1. 文件被以树形结构(数据结构学过的树,但不是二叉树)进行管理,文件都是树上的节点(node)。2. 文件可以大体分成两大类:
1)存储数据的文件——普通文件(俗称的文件)
2)管理树形结构组织数据的文件——目录/文件夹(directory / dir)无论是目录或文件都只是树上的一个结点,一个结点可以有多个孩子。
3. 这棵文件树只是一个逻辑结构,而不是硬盘上的物理结构
a.普通文件
在Windows OS下,以文件后缀(file suffiex)来标记出这个文件存储的内容是什么内容。
如:*.txt普通文本、*.docx Word文档等。b. 可见or隐藏
文件:包括目录、文本文件、不是文本的文件(二进制文件)。
例如:a.txt、a.java(文本),a.class、a.png(二进制)。关于文件的路径(Path):根据一个规则,从文件树上唯一确定一个位置,这个位置一定对应到某个结点,但是这个结点可以不存在。
路径:
1. 绝对路径(absolute path abs path):从一棵树的根结点出发描述的路径。
2. 相对路径(relative path ):从“我们”所在的当前位置出发。描述的路径。无论“我们”身在何处,总是唯一确定一个位置。
什么叫做“我们”所在的位置:每个进程都有一个当前工作目录(current working directory ,cwd),一般一个进程的启动目录,就是当前工作目录。
真实中怎么去描述路径(重点):windows 下,先以绝对路径为例
在代码的字符串中如何表示这个路径
String path ="D:\Java\截图.png";
直接这么写的错误的,因为字符串中反斜杠\,表示转义的意思比如\n \t 等。
应该写作:使用\\转义后表示\。
String path = "D:\\Java\\截图.png";
Windows 使用 \ 作为路径分隔符,Linux(Unix/XOS)使用 / 作为路径分隔符。
Java号称跨平台,所以可以帮我们处理这个问题,代码中写"/或者“\\”都可以,一般使用"/”为主。写作如下,同样正确。
String path = "D:/Java/截图.png";
路径表示中的两个特殊的符号一个点(".")和两个点(" ..")
其中:"."表示在当前位置(目录)不动
".."表示回到当前位置的父结点(目录)上这两个符号一般在相对路径上使用较多
我现在在C:/Windows/Users下
../../a.txt 表示C:/a.txt
./hello.jpg 表示C:/Windows/Users/hello.jpg
hello.jpg 表示C:/Windows/Users/hello.jpg此处C:/Windows 等价于C:/Windows/ (前提Windows是个目录)
相对路径:
1.最基本的相对路径
进程运行时的工作目录在哪里?
current working diretory(cwd)JVM下,通常就是进程启动时的目录!
注意,原则上是启动时的目录,而和代码/工程所在目录无关。
开发阶段:开发编译
运行阶段:程序运行变成进程
小结
关于文件的路径:
1. 路径是树上找到一个结点的位置2. 路径存在并不表示文件一定存在
3. 路径分为绝对路径or相对路径
4. 当前位置:进程的当前工作目录
5. 文件路径"/"或者"\\"表示路径分隔符,Java下使用哪个都可以6. "."和".."的含义
树的结点分为:叶子结点和非叶子结点
普通文件:只能是叶子结点
目录文件:叶子结点or非叶子结点都可以,处于叶子节点时是空目录
数据结构中学过树:结点的操作更容易、子树的操作更复杂
文件系统中,以结点为单元进行操作(在代码层面)
文件移动操作(文件重命名、文件剪切+粘贴):结点的移动(重命名or移动到其他结点下)。文件复制操作(复制+粘贴):新建结点+内容的复制。
目录移动操作(目录重命名、目录剪切+粘贴):以该结点为根的一棵子树的移动
目录复制操作:以该结点为根的一棵子树的复制删除:默认情况下只能删除普通文件or空目录。只能删除结点,不能删除子树
删除非空目录:对以当前目录为根整棵子树的删除
树的操作,需要转换成结点的操作:
以目录的复制为例,遍历(深度or广度)整棵树,然后对其中的每个结点进行复制。
3. 在Java中,实现基本的IO操作
通过Java 代码操作文件(File)
文件数据 = 元数据+内容数据
我们只关注元数据本身,暂时不管内容数据。
对文件系统树的操作:判断是否存在、判断是否是目录、创建、删除、重命名....
File对象描述一个文件(结点,结点对应的文件是否存在并不一定)
创建
创建一个新文件返回true:创建成功
返回false:创建失败(文件已经存在)
抛出IOException:发生了IO 异常(最常见的,是文件应该在的目录现在还不存在)
如:D:\\学习\\Java\\new\\hello.txtimport java.io.IOException; public class Demo1 { public static void main(String[] args) { // 1. 绝对路径的方式创建 // 1.1 直接传入字符串的路径 File file1 = new File("D:/学习/Java/hello.txt"); // 1.2 传入父路径 + 子路径 File file2 = new File("D:/学习/Java","hello.txt"); // 1.3 以 File 传入 parent File parent = new File("D:/学习/Java"); File file3 = new File(parent,"hello.txt"); // 负数代表 file1 < file2 // 0 代表 file1 == file2 // 正数代表 file1 > file2 int cmp1 = file1.compareTo(file2); int cmp2 = file2.compareTo(file3); System.out.println(cmp1); System.out.println(cmp2); } }
import java.io.IOException; public class Demo1 { public static void main(String[] args) throws IOException { File file4 = new File("D:/学习/Java/hello.txt"); boolean r1 = file4.createNewFile(); System.out.println(r1);// 这里打印 true // 异常的知识点:Java 中的异常分为 // 受查异常(checked exception) or 非受查异常(uncheck exception) // 方法中如果可能抛出受查异常,有语法要求 // 要么,我们自己 try catch,不再抛出受查异常 // 要么,在方法签名中通过 throws 声明有受查异常可能被抛出 // java.lang.RuntimeException 及其子类是非受查异常 // java.io.IOException 是受查异常 r1= file4.createNewFile(); System.out.println(r1);// 由于文件被创建过了,所以是 false } }
删除
delete() vs deleteOnExit()
delete:立即删除
deleteOnExit:在JVM退出时才真正删除1. 普通文件删除(存在)
import java.io.File; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { File file1 = new File("D:/学习/Java/deleteTxt.txt"); boolean r = file1.delete(); System.out.println(r); } }
2. 普通文件删除(不存在)import java.io.File; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { File file1 = new File("D:/学习/Java/deleteTxt.txt"); boolean r = file1.delete(); System.out.println(r); } }
3. 空目录删除(存在)import java.io.File; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { File file2 = new File("D:/学习/Java/deleteDirectory"); boolean r = file2.delete(); System.out.println(r); } }
4. 非空目录删除(必须递归解决)import java.io.File; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { File file2 = new File("D:/学习/java/test"); traversal(file2); } private static void traversal(File dir) throws IOException { File[] files = dir.listFiles(); for (File file : files) if (file.isDirectory()) { System.out.println(file.getCanonicalPath() + "\\"); traversal(file); // 当深度优先的遍历完成时,则可以认为该目录一定是空目录了 file.delete(); } else { // 得到这个文件的一个标准(去除一切无意义的“.”和“..”) System.out.println(file.getCanonicalPath()); file.delete(); } } }
删除非空目录
1. 先遍历(深度优先——递归),删除这个目录下的所有子孙,让这个目录变成空目录2. 删除该目录
File类常见方法总结
一、构造方法绝对路径or相对路径二、判断文件属性
1.是否存在exists()
2.是否是目录isDirectory()3.是否是普通文件isFile()
三、获取文件标准路径
1.getCanonicalPath() throws IOException四、对于文件树结构的修改
1.创建结点
1)创建目录mkdirs() 2)创建普通文件createNewFile()2.删除结点delete()
3.移动结点(重命名结点) renameTo()五、针对目录,可以获取目录下的所有孩子文件
listFiles() 如何对一棵树进行遍历(深度优先(更常见)or 广度优先)
JDK中只提供了针对结点的操作,没有提供针对一棵树的操作。
一切针对树的操作,都需要我们写代码自己搞定!delete()是不进入回收站的删除,是真正的删除。
windows 上的回收站的删除,实际上只是把文件剪切到一个固定目录。
本篇小结
1. IO设备(数据必须经由IO设备处理并加载到内存之后才能被CPU处理)
2. 硬盘设备(存储的常识:读写速度、易失性等)
3. 文件系统(文件是硬盘数据的抽象)
树形结构、路径、目录or普通文件4. 文件数据=管理数据+内容数据
java.io.File对象
5. createNewFile() + delete()