目录
1.认识文件
1.1.文件结构组织和目录
1.2.文件路径(Path)
1.2.1.绝对路径
1.2.2.相对路径
1.3.文件类型
1.3.1.文本文件(.txt结尾)
1.3.2.二进制文件
1.4.文件权限
1.5.其他
2.Java中操作文件
2.1.File常见属性
2.2.File常用构造方法
2.3.File常用方法
2.3.1.观察get系列的特点和差异
--->PS:getPath() VS getAbsolutePath() VS getCanonicalPath()
2.3.2.文件判断与创建
2.3.3.文件存在删除/不存在创建
2.3.4.观察deleteOnExit
2.3.5.观察目录的创建
2.3.6.观察文件重命名
3.文件内容的读写——数据流
3.1.InputStream:输入流
3.1.1.InputStream常用方法
3.1.2.FileInputStream
3.1.3.使用Scanner进行数据读取
3.2.OutputStream:输出流
3.2.1.OutputStream 常用方法
3.2.3.使用 PrintWriter 进行写入
3.2.4.使用FileWriter追加数据
先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备,当想要进⾏数据保存时,往往不是保存成⼀个整体,⽽是独⽴成⼀个个的单位进⾏保存,这个独⽴的单位就被抽象成⽂件的概念, 就类似办公桌上的⼀份份真实的⽂件⼀般。
⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数据⽽存在,我们把这部分信息可以视为⽂件的元信息。
如何进⾏⽂件的组织:按照层级结构进⾏组织 —— 数据结构中学习过的树形结构。这样,⼀种专⻔⽤来存放管理信息的特殊⽂件诞⽣了,也就是我们平时所谓⽂件夹(folder)或者⽬录(directory)的概念。
PS:⽂件夹是⽤来存放⽂件的,⽐如 A ⽂件夹下有 N 个⽂件,⽽ A ⽂件夹有⾃⼰的⽬录,⽐如在D:\\A。
在⽂件系统中如何定位⼀个唯⼀的⽂件?从树型结构的⻆度来看,树中的每个结点都可以被⼀条从根开始,⼀直到达的结点的路径所描述,⽽这种描述⽅式就被称为⽂件的绝对路径(absolute path)。
Linux必须以"-"开始的全路径;Windows可以省略"此电脑",直接从某个盘符开始。
可以从任意结点出发,进⾏路径的描述,⽽这种描述⽅式就被称为相对路径(relative path),相对于当前所在结点的⼀条路径。
Linux中以".-"表示当前路径。
即使是普通⽂件,根据其保存数据的不同,也经常被分为不同的类型,⼀般简单划分为:
指代保存被字符集编码的⽂本。
按照标准格式保存的非被字符集编码过的⽂件。
Windows 操作系统上,会按照文件名中的后缀来确定文件类型以及该类型文件的默认打开程序。但这个习俗并不是通用的,在 OSX、Unix、Linux 等操作系统上,就没有这样的习惯,一般不对文件类型做如此精确地分类。
⽂件由于被操作系统进⾏了管理,所以根据不同的⽤户,会赋予⽤户不同的对待该⽂件的权限,⼀般地可以认为有可读、可写、可执行权限。
文件权限设置语法:
Windows 操作系统上,还有⼀类⽂件⽐较特殊,就是平时我们看到的快捷⽅式(shortcut),这种⽂件只是对真实⽂件的⼀种引⽤⽽已。其他操作系统上也有类似的概念,例如,软链接(soft link)等。
最后,很多操作系统为了实现接⼝的统⼀性,将所有的 I/O 设备都抽象成了⽂件的概念,使⽤这⼀理念最为知名的就是 Unix、Linux 操作系统 —— 万物皆⽂件。
此篇文章主要涉及⽂件的元信息、路径的操作,暂时不涉及关于⽂件中内容的读写操作。
Java 中通过 java.io.File 类来对⼀个⽂件(包括⽬录)进⾏抽象的描述。注意,有 File 对象,并不代表真实存在该⽂件。
修饰符及类型 | 属性 | 说明 |
static String | pathSeparator | 依赖于系统的路径分隔符,String类型的表示 |
static char | pathSeparator | 依赖于系统的路径分隔符,char类型的表示 |
签名 | 说明 |
File(File parent, String child) | 根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示 |
import java.io.File;public class FileDemo1 {public static void main(String[] args) {File pFile = new File("d:\\");//构造方法1File file = new File(pFile, "a.txt");System.out.println(file.getPath());//构造方法2【重点-常用】File file2 = new File("d:\\b.txt");System.out.println("文件2路径:" + file2.getPath());//构造方法3File file3 = new File("d:\\", "c.txt");System.out.println(file3.getPath());}
}
修饰符及返回值类型 | 方法签名 | 说明 |
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返回 true |
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行。没有返回值。 |
String[] | list() | 返回 File 对象代表的目录下的所有文件名 |
File[] | listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象表示 |
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目录 |
boolean | renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean | canRead() | 判断用户是否对文件有可读权限 |
boolean | canWrite() | 判断用户是否对文件有可写权限 |
import java.io.File;
import java.io.IOException;public class FileDemo2 {public static void main(String[] args) throws IOException {File file = new File("../a.txt");System.out.println("文件名称:" + file.getName());System.out.println("文件目录(getPath):" + file.getPath());System.out.println("文件绝对路径:" + file.getAbsolutePath());System.out.println("文件标准路径:" + file.getCanonicalPath());}
}
--->PS:getPath() VS getAbsolutePath() VS getCanonicalPath()
- 绝对路径时,三者⼀致。
- 相对路径时:
- getPath() 是相对路径本身。
- getAbsolutePath() 是项⽬⽬录 + 相对路径本身。
- getCanonicalPath() 可以解析相对路径,得到争取的路径。
注:文件名不能包含下列任何字符:\、/、:、*、?、"、<、>、|。
import java.io.File;
import java.io.IOException;public class FileDemo3 {public static void main(String[] args) throws IOException {File file = new File("z.txt");System.out.println("文件是否存在:" + file.exists());System.out.println("是否为文件夹:" + file.isDirectory());System.out.println("是否为文件:" + file.isFile());System.out.println();boolean result = file.createNewFile(); //创建文件System.out.println("文件创建:" + result);System.out.println("文件是否存在:" + file.exists());System.out.println("是否为文件夹:" + file.isDirectory());System.out.println("是否为文件:" + file.isFile());System.out.println();File file2 = new File("c.txt");if(!file2.exists()) { //文件不存在,创建文件System.out.println("创建文件:" + file2.createNewFile());}System.out.println("是否为文件夹:" + file2.isDirectory());System.out.println("是否为文件:" + file2.isFile());}
}
如果⽂件或⽂件夹不存在,使⽤ isDirectory 和 isFile 判断都为 false。
import java.io.File;
import java.io.IOException;public class FileDemo4 {public static void main(String[] args) throws IOException {//先得到一个file对象File file = new File("a.txt");//判断file对象是否存在if(file.exists()) {//如果存在则删除文件boolean result = file.delete();System.out.println("文件删除:" + result);} else {//如果不存在则创建文件boolean result = file.createNewFile();System.out.println("新建文件:" + result);}}
}
import java.io.File;
import java.io.IOException;public class FileDemo5 {public static void main(String[] args) throws IOException, InterruptedException {File file = new File("a.txt");if(!file.exists()) {//如果不存在,则新建System.out.println("新建文件:" + file.createNewFile());}//删除文件file.deleteOnExit();Thread.sleep(5 * 1000);}
}
import java.io.File;public class FileDemo6 {public static void main(String[] args) {File file = new File("test/apps");System.out.println("是否为文件夹:" + file.isDirectory());System.out.println("是否为文件:" + file.isFile());System.out.println();// boolean result = file.mkdir(); //只能创建一个文件夹boolean result = file.mkdirs(); //创建多个文件夹System.out.println("创建文件夹:" + result);System.out.println("是否为文件夹:" + file.isDirectory());System.out.println("是否为文件:" + file.isFile());}
}
mkdir() 的时候,如果中间⽬录不存在,则⽆法创建成功; mkdirs() 可以解决这个问题。
import java.io.File;
import java.io.IOException;public class FileDemo7 {public static void main(String[] args) throws IOException {//将a.txt -> 重命名为 -> f.txtFile file = new File("a.txt");File tarFile = new File("f.txt");if(!file.exists()) {//先创建文件file.createNewFile();}//重命名文件boolean result = file.renameTo(tarFile);System.out.println("重命名结果:" + result);}
}
InputStream输入流是用来读取数据的。
修饰符及返回值类型 | ⽅法签名 | 说明 |
int | read() | 读取⼀个字节的数据,返回 -1代表已经完全读完了 |
int | read(byte[] b) | 最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表已经读完了 |
int | read(byte[] b, int off, int len) | 最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表已经读完了 |
void | close() | 关闭字节流 |
InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输⼊设备都可以对应⼀个 InputStream 类,我们现在只关⼼从⽂件中读取,所以使⽤ FileInputStream。
构造方法
签名 | 说明 |
FileInputStream(File file) | 利⽤ File 构造⽂件输⼊流 |
FileInputStream(String name) | 利⽤⽂件路径构造⽂件输⼊流 |
读取文件中的内容
读取方式1
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;public class InputStreamDemo1 {public static void main(String[] args) {//1.创建流对象 try-catchInputStream inputStream = null;try {inputStream = new FileInputStream("c.txt");//2.读写操作while(true) {int c = inputStream.read();//如果流返回的是-1,说明数据已经读取完了if(c == -1) break;Thread.sleep(200);System.out.printf("%c", c);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (InterruptedException exception) {exception.printStackTrace();} finally {//3.关闭流if(inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
}
改进版:
import java.io.FileInputStream;
import java.io.InputStream;public class InputStreamDemo2 {public static void main(String[] args) {//1.创建流对象 try-catch-resource(诞生于JDK1.7)try(InputStream inputStream = new FileInputStream("c.txt")) {//2.读写操作while(true) {int c = inputStream.read();//如果流返回的是-1,说明数据已经读取完了if(c == -1) break;Thread.sleep(200);System.out.printf("%c", c);}} catch (Exception e) {e.printStackTrace();}}
}
读取方式2
import java.io.FileInputStream;
import java.io.InputStream;/*** 一次性读取*/
public class InputStreamDemo3 {public static void main(java.lang.String[] args) {try(InputStream inputStream = new FileInputStream("c.txt")) {byte[] bytes = new byte[1024];while(true) { //如果数据超过了byte容量,会读取多次int c = inputStream.read(bytes);if(c == -1) break;Thread.sleep(200);System.out.println(new String(bytes, "utf-8"));}} catch (Exception e) {}}
}
构造方法 | 说明 |
Scanner(InputStream is, String charset) | 使⽤ charset 字符集进⾏ is 的扫描读取 |
import java.io.FileInputStream;
import java.util.Scanner;public class InputStreamDemo4 {public static void main(String[] args) {try(FileInputStream inputStream = new FileInputStream("c.txt")) {try(Scanner scanner = new Scanner(inputStream, "utf8")) {while(scanner.hasNext()) {System.out.println(scanner.nextLine());}}} catch (Exception e) {}}
}
OutputStream 输出流是进⾏数据写⼊的。
修饰符及返回值类型 | ⽅法签名 | 说明 |
void | write(int b) | 写⼊要给字节的数据 |
void | write(byte[] b) | 将 b 这个字符数组中的数据全部写⼊ os 中 |
int | write(byte[] b, int off, int len) | 将 b 这个字符数组中从 off 开始的数据写⼊ os 中,⼀共写 len个 |
void | close() | 关闭字节流 |
void | flush() | 重要:我们知道 I/O 的速度是很慢的,所以,⼤多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写⼊内存的⼀个指定区域⾥,直到该区域满了或者其他指定条件时才真正将数据写⼊设备中,这个区域⼀般称为缓冲区。但造成⼀个结果,就是我们写的数据,很可能会遗留⼀部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。 |
OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件中,所以使⽤ FileOutputStream。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;/*** 写入,每次写入一个字符*/
public class OutputStreamDemo1 {public static void main(String[] args) throws IOException {File file = new File("mytest.txt");if(!file.exists()) {//新建文件System.out.println("新建文件:" + file.createNewFile());}//文件写入操作try(OutputStream outputStream = new FileOutputStream(file)) {outputStream.write('H');outputStream.write('e');outputStream.write('l');outputStream.write('l');outputStream.write('o');outputStream.flush();}}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class OutputStreamDemo2 {public static void main(String[] args) throws IOException {File file = new File("mytest.txt");if(!file.exists()) {file.createNewFile();}//写入操作try(OutputStream outputStream = new FileOutputStream(file)) {byte[] bytes = new byte[]{'H', 'i'};outputStream.write(bytes);outputStream.flush();}}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;public class OutputStreamDemo3 {public static void main(String[] args) throws IOException {File file = new File("mytest.txt");if(!file.exists()) {file.createNewFile();}//写入操作try(OutputStream outputStream = new FileOutputStream(file)) {String msg = "hello, world";outputStream.write(msg.getBytes(StandardCharsets.UTF_8));outputStream.flush();}}
}
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;public class OutputStreamDemo4 {public static void main(String[] args) throws IOException {File file = new File("mytest.txt");if(!file.exists()) file.createNewFile();try(PrintWriter printWriter = new PrintWriter(file)) {printWriter.println("这是第一行数据");printWriter.println("这是第二行数据");printWriter.printf("我叫:%s,今年:%d,至今未婚", "张三", 22);printWriter.flush();}}
}
以上都是覆盖数据。
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;public class OutputStreamDemo4 {public static void main(String[] args) throws IOException {File file = new File("mytest.txt");if(!file.exists()) file.createNewFile();//数据追加try(FileWriter fileWriter = new FileWriter(file, true)) {fileWriter.append("我是追加的数据II\n");fileWriter.flush();}}
}
上一篇:前端资源浏览器渲染原理
下一篇:Flask的学习笔记2