【JavaEE】文件操作IO之File 、InputStream、OutputStream 用法详解
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
1.利用 OutputStreamWriter 进行字符写入
一、文件概念
1文件定义与组成
狭义上针对硬盘这种持久化存储的I/O设备当进行数据保存时往往不是保存成一个整体而是独立成一个个的单位进行保存这个独立的单位就被抽象成文件的概念。
每个文件都有属于它自己的不是内容的一些信息。例如文件名、文件类型、文件大小不作为文件数据。这些信息就称作文件的元信息。
2文件的树形结构组织和目录
文件的系统管理是按照层级结构进行组织就是数据结构中所提到的树形结构。
目录一种专门用来存放管理信息的特殊文件。也称文件夹。
3文件路径
文件的绝对路径absolute path从树型结构的角度来看树中的每个结点都可以被一条从根开始一直到达的结点的路径所描述这种描述方式就被称为文件的绝对路径。绝对路径是固定的不会发生改变。
例如以Windows操作系统为例绝对路径就是以盘符为开头。C盘为根目录从C盘开始找到存放jdk的文件。C:\Program Files\Java\jdk1.8.0_131。
文件的相对路径relative path从任意结点出发进行路径的描述而这种描述方式就被称为相对路径相对于当前所在结点的一条路径。相对路径一定要有基准路径。.表示当前路径。..表示当前路径的父目录上级目录。
例如基准路径是C:\Program Files\Java。./表示的路径就代表C:\Program Files\Java。
基准路径是C:\Program Files\Java。../表示的路径就代表C:\Program Files。
/斜杆和\反斜杠小贴士
对于大部分操作系统路径的分隔符都是/斜杠 但是对于Windows来说使用的是\反斜杠。Windows最早的系统是基于Dos开发的Dos系统最早的时候/斜杆已经有了其他用途就接着了反斜杠\。
后期Windows意识到大多数操作系统都是斜杠/当编程的时候也会出现问题。例如D\taa.txt\t会被当成制表符就得使用\\t。随着逐渐发展斜杠和反斜杠都能被识别了。一个注意点是当人为输入/时Windows输出的还是\。
4文件分类
一般简单的划分为文本文件和二进制文件分别指代保存被字符集编码的文本和按照标准格式保存的非被字符集编码过的文件。简而言之能看懂的就是文本文件一堆乱码的就是二进制文件。
5文件操作
Java中对于文件的操作可以分为两类一是文件系统相关的操作包括1创建目录2删除目录3创建文件4删除文件5列出目录下的文件6重命名。二是文件内容相关操作包括1读文件内容2写文件内容。对于文件内容的操作分为二进制文件和文本文件。
二、文件操作File类
Java 中通过 java.io.File 类来对一个文件包括目录进行抽象的描述。注意有 File 对象并不代表真实存在该文件。根据一个路径创建一个File文件假如这个路径不存在这个文件也就不存在但是File对象是存在的。
1File类中的属性
修饰符及类型 | 属性 | 说明 |
static String | pathSeparator | 依赖于系统的路径分隔符String 类型的表示 |
static char | pathSeparator | 依赖于系统的路径分隔符char 类型的表示 |
与系统有关不同的系统分割符不同。
2File类的构造方法
签名 | 说明 |
File(File parent, String child) | 根据父目录 + 孩子文件路径创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例路径可以是绝对路径或者 相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径创建一个新的 File 实例父目录用 路径表示 |
3File类的方法
修饰符及返回 值类型 | 方法签名 | 说明 |
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() | 判断用户是否对文件有可写权限 |
1.get系列用法代码实例
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("..\\hello-world.txt"); // 并不要求该文件真实存在
System.out.println(file.getParent());
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
}
}
运行结果
..
hello-world.txt
..\hello-world.txt
D:\代码练习\文件示例1\..\hello-world.txt
D:\代码练习\hello-world.txt
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("file.txt"); // 并不要求该文件真实存在
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
}
}
运行结果
file.txt
D:\代码练习\文件示例1\file.txt
D:\代码练习\文件示例1\file.txt
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("./file.txt"); // 并不要求该文件真实存在
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
}
}
运行结果
file.txt
D:\代码练习\文件示例1\.\file.txt
D:\代码练习\文件示例1\file.txt
这里的基准路径是D:\代码练习\文件示例1 相对路径是.\file.txt。绝对路径就是基准路径+相对路径。
在ideal里面运行基准路径是项目的工作路径。用不同的方式运行同样一份的代码基准路基也是不一样的。
2.普通文件的创建
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("hello-world.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
3.普通文件的删除
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"); // 要求该文件不存在才能看到相同的现象
System.out.println(file.exists());
System.out.println(file.createNewFile());
System.out.println(file.exists());
System.out.println(file.delete());
System.out.println(file.exists());
}
}
运行结果
false
true
true
true
false
4.deleteOnExit的现象
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"); // 要求该文件不存在才能看到相同的现象
System.out.println(file.exists());
System.out.println(file.createNewFile());
System.out.println(file.exists());
file.deleteOnExit();
System.out.println(file.exists());
}
}
运行结果
false
true
true
true程序运行结束后文件还是被删除了
5.目录的创建
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File dir = new File("some-dir"); // 要求该目录不存在才能看到相同的现象
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
System.out.println(dir.mkdir());
System.out.println(dir.isDirectory());
System.out.println(dir.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 和 somedir 都不存在
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
System.out.println(dir.mkdir());
System.out.println(dir.isDirectory());
System.out.println(dir.isFile());
}
}
运行结果
false
false
false
false
falsemkdir() 的时候如果中间目录不存在则无法创建成功; mkdirs() 可以解决这个问题。
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 和 somedir 都不存在
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
6.文件重命名
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
三、文件操作InputStream
1InputStream概述
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() | 关闭字节流 |
2FileInputStream概述
InputStream 只是一个抽象类要使用还需要具体的实现类。关于 InputStream 的实现类有很多基本可以认为不同的输入设备都可以对应一个 InputStream 类本文只关心从文件中读取所以使用 FileInputStream。
1.FileInputStream 构造方法
构造方法
签名 | 说明 |
FileInputStream(File file) | 利用 File 构造文件输入流 |
FileInputStream(String name) | 利用文件路径构造文件输入流 |
代码实例一
将文件完全读完的两种方式。相比较而言后一种的 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]);
}
}
}
}
}
代码实例二
文件中填写中文。写中文的时候使用 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);
}
}
}
}
}
2.利用Scanner进行读取
由代码实例二可知对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的所以我们使用Scanner 类。
构造方法
构造方法 | 说明 |
Scanner(InputStream is, String charset) | 使用 charset 字符集进行 is 的扫描读取 |
代码示例
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
1OutputStream概述
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刷新操作将数据刷到设备中。 |
2FileOutputStream概述
OutputStream 同样只是一个抽象类要使用还需要具体的实现类。本文只关心写入文件中所以使用 FileOutputStream。
1.利用 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', (byte)'d'
};
os.write(b, 0, 4);
// 不要忘记 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 = "Nothing";
byte[] b = s.getBytes();
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
代码实例五
import java.io.*;
public class Main {
public static void main(String[] args) throw
try (OutputStream os = new FileOutputStr
String s = "你好中国";
byte[] b = s.getBytes("utf-8");
os.write(b);
// 不要忘记 flush
os.flush();
}
}
}
2.利用 PrintWriter 找到熟悉的方法
PrintWriter 类中提供了我们熟悉的 print、println、printf 等方法。故而将 OutputStream 处理下使用PrintWriter 类来完成输出。
第一步OutputStream os = ...;
第二步OutputStreamWriter osWriter = new OutputStreamWriter(os, "utf-8");告知的字符集编码的类型是 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();
}
}
}
}
}