文章目录
认识文件
我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进⾏数据保存时,往往不是保存成⼀个整体,⽽是独⽴成⼀个个的单位进⾏保存,这个独⽴的单位就被抽象成⽂件的概念,就类似办公桌上的⼀份份真实的⽂件⼀般。
⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数据⽽存在,我们把这部分信息可以视为⽂件的元信息。
文件路径(Path)
如何在⽂件系统中如何定位我们的⼀个唯⼀的⽂件就成为当前要解决的问题,但这难不倒计算机科学家,因为从树型结构的⻆度来看,树中的每个结点都可以被⼀条从根开始,⼀直到达的结点的路径所描述,⽽这种描述⽅式就被称为⽂件的绝对路径(absolute path)。
除了可以从根开始进⾏路径的描述,还有相对路径,先指定一个”当前目录“/ “工作目录”/"基准目录“,从当前目录出发,找到目标文件。
在实际开发中用的更多的是相对路径
文件分类
1.文本文件:是按照”文本“ / 字符串方式来理解文件内容(文本文件里面的二进制内容都是表示的字符串),进一步的,可以认为,二进制文件的内容,都是合法的字符(字符编码/普通字母/汉字)
2.二进制文件:没有上述限制,这里的内容任何数据都可以
如何判断呢?
使用记事本打开文件,如果是乱码,就是二进制文件,否者是文本文件
Java 中操作⽂件
Java 中通过 java.io.File 类来对⼀个⽂件(包括⽬录)进⾏抽象的描述。注意,有 File 对象,
并不代表真实存在该⽂件。
File 概述
我们先来看看 File 类中的常⻅属性、构造⽅法和⽅法
属性
构造方法
方法
代码示例
相对路径:
public class Test1 {
public static void main(String[] args) throws IOException {
// File file = new File("D:\\java_cc\\javase\\IODemo/11.txt");
//ctrl+D直接复制上一行内容
File file = new File("./11.txt");
System.out.println(file.exists());
System.out.println(file.getParent());
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.getAbsoluteFile());
System.out.println(file.getCanonicalFile());
}
}
运行结果
true
.
11.txt
.\11.txt
D:\java_cc\javase\IODemo.\11.txt
D:\java_cc\javase\IODemo\11.txt
绝对路径:
public class Test1 {
public static void main(String[] args) throws IOException {
File file = new File("D:\\java_cc\\javase\\IODemo/11.txt");
//ctrl+D直接复制上一行内容
System.out.println(file.exists());
System.out.println(file.getParent());
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.getAbsoluteFile());
System.out.println(file.getCanonicalFile());
}
}
运行结果:
true
D:\java_cc\javase\IODemo
11.txt
D:\java_cc\javase\IODemo\11.txt
D:\java_cc\javase\IODemo\11.txt
D:\java_cc\javase\IODemo\11.txt
对比相对路径和绝对路径,get的运行结果有所差异
普通文件的创建与删除
public class Test2 {
public static void main(String[] args) throws IOException {
File file = new File("22.txt");//开始不存在
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.createNewFile());
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.createNewFile());
}
}
运行结果
false
false
false
true
true
false
true
false
public class IODemo3 {
public static void main(String[] args) throws InterruptedException {
File file = new File("./test.txt");
// boolean ret = file.delete();
file.deleteOnExit();
Thread.sleep(5000);
// System.out.println(ret);
}
}
程序运行结束后被删除
目录的创建
public class Test3 {
public static void main(String[] args) {
File file = new File("some-dir");
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.mkdir());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
}
}
运行结果:
false
false
true
true
false
创建多级目录
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File dir = new File("some-parent\\some-dir"); // some-parent 和 so
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
System.out.println(dir.mkdirs());
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
}
}
运行结果:
false
false
true
true
false
创建some-parent下的some-dir目录
文件的重命名
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("some-file.txt"); // 要求 some-file.txt 得存在
File dest = new File("dest.txt"); // 要求 dest.txt 不存在
System.out.println(file.exists());
System.out.println(dest.exists());
System.out.println(file.renameTo(dest));
System.out.println(file.exists());
System.out.println(dest.exists());
}
}
运行结果:
true
false
true
false
true
文件的读写——数据流
流是操作系统提供的概念
Java标准库对于流进行了一系列的封装,提供了一组类来负责进行这些工作
大致分为两大类别:
1.字节流:以字节为单位进行读写,一次最少读写一个字节
代表类:InputStream(输入),OutputStream(输出)
2.字符流:以字符为单位进行读写,比如,如果utf8表示汉字,三个字节就是一个汉字,每次读写都得是以三个字节为一个单位,来进行读写,不能一次读写半个汉字
代表类:Reader(输入) Writer(输出)
InputStream概述
方法
说明
InputStream只是⼀个抽象类,要使⽤还需要具体的实现类。关于InputStream的实现类有很多,基
本可以认为不同的输⼊设备都可以对应⼀个InputStream类,我们现在只关⼼从⽂件中读取,所以使⽤FileInputStream
FileInputStream概述
构造方法
代码⽰例
⽰例1
将⽂件完全读完的两种⽅式。相⽐较⽽⾔,后⼀种的IO次数更少,性能更好。
import java.io.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "Hello" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
while (true) {
int b = is.read();
if (b == -1) {
// 代表⽂件已经全部读完
break;
}
System.out.printf("%c", b);
}
}
}
}
import java.io.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "Hello" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
byte[] buf = new byte[1024];
int len;
while (true) {
len = is.read(buf);
if (len == -1) {
// 代表⽂件已经全部读完
break;
}
for (int i = 0; i < len; i++) {
System.out.printf("%c", buf[i]);
}
}
}
}
}
⽰例2
这⾥我们把⽂件内容中填充中⽂看看,注意,写中⽂的时候使⽤UTF-8编码。hello.txt中填写"你好中国"
注意:这⾥我利⽤了这⼏个中⽂的UTF-8编码后⻓度刚好是3个字节和⻓度不超过1024字节的现
状,但这种⽅式并不是通⽤的
import java.io.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "你好中国" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
byte[] buf = new byte[1024];
int len;
while (true) {
len = is.read(buf);
if (len == -1) {
// 代表⽂件已经全部读完
break;
}
// 每次使⽤ 3 字节进⾏ utf-8 解码,得到中⽂字符
// 利⽤ String 中的构造⽅法完成
// 这个⽅法了解下即可,不是通⽤的解决办法
for (int i = 0; i < len; i += 3) {
String s = new String(buf, i, 3, "UTF-8");
System.out.printf("%s", s);
}
}
}
}
}
利⽤Scanner进⾏字符读取
上述例⼦中,我们看到了对字符类型直接使⽤InputStream进⾏读取是⾮常⿇烦且困难的,所以,我们使⽤⼀种我们之前⽐较熟悉的类来完成该⼯作,就是Scanner类。
import java.io.*;
import java.util.*;
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "你好中国" 的内容
public class Main {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("hello.txt")) {
try (Scanner scanner = new Scanner(is, "UTF-8")) {
while (scanner.hasNext()) {
String s = scanner.next();
System.out.print(s);
}
}
}
}
}
OutputStream概述
说明
OutputStream同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件
中,所以使⽤FileOutputStream
利⽤OutputStreamWriter进⾏字符写入
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
os.write('H');
os.write('e');
os.write('l');
os.write('l');
os.write('o');
// 不要忘记 flush
os.flush();
}
}
}
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
byte[] b = new byte[] {
(byte)'G', (byte)'o', (byte)'o', (byte)'d'
};
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
byte[] b = new byte[] {
(byte)'G', (byte)'o', (byte)'o', (byte)'d', (byte)'B', (byte)'a'
};
os.write(b, 0, 4);
// 不要忘记 flush
os.flush();
}
}
}
mport java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
String s = "Nothing";
byte[] b = s.getBytes();
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
String s = "你好中国";
byte[] b = s.getBytes("utf-8");
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
利⽤PrintWriter找到我们熟悉的⽅法
上述,我们其实已经完成输出⼯作,但总是有所不⽅便,我们接来下将OutputStream处理下,使⽤PrintWriter类来完成输出,因为PrintWriter类中提供了我们熟悉的print/println/printf⽅法
OutputStream os = ...;
OutputStreamWriter osWriter = new OutputStreamWriter(os, "utf-8"); // 告诉
PrintWriter writer = new PrintWriter(osWriter);
// 接下来我们就可以⽅便的使⽤ writer 提供的各种⽅法了
writer.print("Hello");
writer.println("你好");
writer.printf("%d: %s\n", 1, "没什么");
// 不要忘记 flush
writer.flush();
示例:
import java.io.*;public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
try (OutputStreamWriter osWriter = new OutputStreamWriter(os, "UTF-8
try (PrintWriter writer = new PrintWriter(osWriter)) {
writer.println("我是第⼀⾏");
writer.print("我的第⼆⾏\r\n");
writer.printf("%d: 我的第三⾏\r\n", 1 + 1);
writer.flush();
}
}
}
}
}