目录
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 操作系统上,还有⼀类⽂件⽐较特殊,就是平时我们看到的快捷⽅式(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:\\");
//构造方法1
File 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());
//构造方法3
File 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.txt
File 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-catch
InputStream 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();
}
}
}