目录
前言
java.io.File
1. 构造方法
2. 方法
get类方法
文件的创建和删除
目录的创建与删除
输入输出流
InputStream
FileInputStream 概述
代码实例1
代码实例2
字符集问题?
Scanner 读取
OutputStream
Java输入输出流的使用案例
创作不易, 多多支持😶🌫️😘😘
前言
本次内容主要针对java当中的文件读写操作, 文件读写的基本操作包括File对象, InputString, OutputString.及其构造方法, 用法, 使用场景等讲解
java.io.File
对于一个文件, 我们如要使用Java语言对其进行操作, 那么java标准库里面提供了一个File类, 用来描述一个文件, 此处的File类的实例对象就是对应的硬盘上一个文件的抽象, 这个抽象具体指的就是, 文件是存储来硬盘上的, 如果直接用代码操作硬盘是不方便的, 于是就在内存中创建一个与此文件与之对应的文件对象, 便于清楚这个对象的位置, 然后修改这个文件.
1. 构造方法
方法定义 | 说明 |
---|---|
File(File parent, String child) | parent为父目录(一个File实例), 然后加上一个孩子路径, 构成一个新的File实例 |
File(String pathName) | 根绝文件路径创建出一个新的File实例, 这个路径可以是绝对路径或者是相对路径 |
File(String parent, String child) | 使用父目录加子目录的形式,创建一个新的File实例. |
我们创建一个文件夹, 在c盘下的文件夹, 然后在文件夹里面创建这个test.txt文本文件, 如图:
- File(String pathName)
import java.io.File;
public class Main {
public static void main(String[] args) {
File file1 = new File("c:/test/test.txt");
boolean ret = file1.exists();
System.out.println(ret);
}
}
输出: true( 此处的exists()方法是检查这个文件是否存在, 如果不存在返回false)
- File(String parent, String child)
import java.io.File;
public class Main {
public static void main(String[] args) {
File file2 = new File("C:\\c\\code_c","cProject");
boolean ret = file2.exists();
System.out.println(ret);
}
}
输出:true;
- File(File parent, String child)
import java.io.File;
public class Main {
public static void main(String[] args) {
File file1 = new File("C:\\c\\code_c");
File file2 = new File(file1,"cProject");
boolean ret = file2.exists();
System.out.println(ret);
}
}
输出:true;
2. 方法
返回类型 | 方法定义 | 说明 |
---|---|---|
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() | 判断用户是否对文件有可写权限 |
以下方法的实例都是用上面这个文件(cProject.sln)来表示, 其基准目录为C:/c/code_c/cProject
get类方法
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:/c/code_c/cProject/cProject.sln");
String retGetParent = file.getParent();
String retGetName = file.getName();
String retGetPath = file.getPath();
String retGetAbsolutePath = file.getAbsolutePath();
String retGetCanonicalPath = file.getCanonicalPath();
System.out.println("文件:C:/c/code_c/cProject/cProject.sln");
System.out.println("父目录文件路径:"+retGetParent);
System.out.println("文件名称:"+retGetName);
System.out.println("文件路径:"+retGetPath);
System.out.println("文件绝对路径:"+retGetAbsolutePath);
System.out.println("修饰过的绝对路径"+retGetCanonicalPath);
}
}
文件的创建和删除
(1)判断这个文件test.txt是否存在
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:/test/test.txt");
System.out.println(file.exists());
}
}
输出true;
(2) 判断test.txt是否为一个目录 / 判断test是否为一个目录
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/test");
File file2 = new File("C:/test/test.txt");
System.out.println(file1.isDirectory());
System.out.println(file2.isDirectory());
}
}
输出:
说明C:/test/test.txt是一个文件C:/test是一个目录
(3) 在C:/test目录下没有cc空文件, 随后创建一个空目录cc
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/test/cc");
boolean ret = file1.createNewFile();
System.out.println(ret);
}
}
输出true, 然后查看test目录:
cc正确的被创建, 并返回true.
(3) 创建了cc空文件之后, 删除这个cc空文件
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/test/cc");
boolean ret = file1.delete();
System.out.println(ret);
}
}
输出true, 查看test目录, 发现cc空文件已经被删除
目录的创建与删除
(1)在C:/test目录下创建目录cam
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/test/cam");
boolean ret = file1.mkdir();
System.out.println(ret);
}
}
输出:true,
成功在Test目录下创建cam子目录
(2)在test目录中的cam目录中创建多级子目录./a/b/c
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/test/cam/a/b/c");
boolean ret = file1.mkdirs();
System.out.println(ret);
}
}
输出true:
(3) 返回Test目录下所有的文件名(除了test外, 额外添加几个文件a,b,c)
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/Test");
String[] retArr = file1.list();
for(String x :retArr) {
System.out.println(x);
}
}
}
输出:
通过这个我们可以发现, cam是目录, 而其他的abc和test的文本都是文件, 目录cam也被输出
(4) 将C;/Test/test.txt文件进行改名
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("C:/Test/test.txt");
File file2 = new File("C:/Test/cam/test.txt");
boolean ret = file1.renameTo(file2);
System.out.println(ret);
}
}
输出true;
Test目录中的test.txt文件被改名(绝对路径)到了Test目录中的cam目录中去了.
输入输出流
输入输出流是针对文件的内容的一种操作, 针对文本文件, 提供了一组类, 统称为字符流, 针对二进制文本文件, 提供了一组类, 统称为字节流, 字符流的基本单位为字符, 字节流的基本单位为字节.
每一个流对象, 都具有两个方向, 一个是读, 一个是写, 分别对应的Reader和InputString , Writer, outputString.
我们所说的输入输出都是针对CPU来操作的, 为了方便大家理解. 对于一组数据, 由外存或者硬盘等io设备进入CPU, 成为input, 反之, 从CPU中输出数据到主存或者是其他io设备就称为output.
下面使用的代码案例中. 其中的try with resource操作是自动执行close关闭操作的. 例如:
InputStream
方法和说明
返回类型 | 方法签名 | 说明 |
int | read() | 返回一个字节的数据, 如果返回值为-1, 则代表读到文件末尾 |
int | read(byte[] bytes) | 最多读取bytes.length字节的数据到bytes中,返回值为读到的字节数, -1 代表读取到文件莫问 |
int | read(byte[] bytes, int offset, int len) | 最多读取到len - offset字节的数据到bytes中, 放在从offset开始, 返回值为实际读取到的字节数, -1 代表读取完了 |
void | close() | 关闭字节流 |
InputStream只是一个抽象类, 不能创建出InputStream实例来对文件进行操作, 还需要使用具体的实现类, 关于InputStream的实现类有很多, 接下来我们重点介绍他的一个实现类 FileInputStream.
FileInputStream 概述
FileInputStream有两个构造方法, 一个是FileInputStream(File file), 另一个是FileInputStream(String name), 第一个是传入一个File类实例, 第二个是直接传入一个文件路径, 构成一个字节输入流
代码实例1
存在文件C:/Test/cam/test.txt
public class IOStream {
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("C:/Test/cam/test.txt")) {
while (true) {
int readb = inputStream.read();
if (readb == -1) {
// 代表文件已经读取完成
break;
}
System.out.printf("%c",readb);
}
}
}
}
代码实例2
此处的文件案例:C:/Test/cam/test.txt
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("C:/Test/cam/test.txt")) {
byte[] bytes = new byte[2];
int len;
while (true) {
len = inputStream.read(bytes);
if (len == -1) {
break;
}
for (int i = 0; i < len; i++) {
System.out.printf("%c", bytes[i]);
}
}
}
}
字符集问题?
如果我们把下面的字符, 改成中文字符, 然后再使用InputStream的FileInputStream实现类来读取.
此处就会抛出异常, 显示IllegalFormatCodePointException
此处需要使用utf8编码来解决.
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);
}
}
}
}
此处的String有一个构造方法
Scanner 读取
从FileInputStream实现类的实例中可以看到, 我们直接对这种字符读取的话是有很多限制的, 比如字符集就是多种限制的其中之一, 他直接影响到了我们数据的读取.
为么避免这种比较麻烦的读取, 我们可以直接使用Scanner的读取方式, 我们常见的Scanner(System.in)的读取方法之外, 还有一个Scanner(InputStream is, String characterSet)
InputStream is 为输入流, characterSet为指定搞得字符集.
使用实例
还是使用上面的C:/Test/cam/test.txt文件模块, test.txt中写有你好中国:
public static void main(String[] args) throws IOException{
try(InputStream inputStream = new FileInputStream("C:/Test/cam/test.txt")) {
try(Scanner scanner = new Scanner(inputStream, "UTF-8")) {
while (scanner.hasNext()) {
String s = scanner.next();
System.out.println(s);
}
}
}
}
OutputStream
OutputStream同样是一个抽象类, 是对比输入流InputStream的, 相对应的, OutputStream也有其对应方法, 其类型为写入, 如下:
返回类型 | 方法 | 说明 |
void | write(int b) | b为要写入的字节数据 |
void | write(byte[] bArr) | 写入字符数组bArr |
int | write(byte[] b, int offset, int len) | 从b中写入字符数组, 从offset开始, 长度为len |
void | close() | 关闭字节流 |
void | flush() |
重要:我们知道
I/O
的速度是很慢的,所以,大多的
OutputStream
为 了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的 一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写 入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的 数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush
(刷新)操作,将数据刷到设备中。
|
OutputStream只是一个抽象类, 想要真正的对文件进行输出操作, 就需要一个实现类, 也就是FileOutputStream, 接下来看实例
还是以上面C:/Test/a.txt
使用实例1
public static void main(String[] args) throws IOException{
try(OutputStream outputStream = new FileOutputStream("C:/Test/a.txt")) {
outputStream.write('h');
outputStream.write('e');
outputStream.write('l');
outputStream.write('l');
outputStream.write('o');
outputStream.close();
}
}
在这个a.txt的空的文本文件中写入hello, 我们打开这个文件如下:
使用完之后记得使用close来关闭输入输出流
使用实例2
public static void main(String[] args) throws IOException{
try(OutputStream outputStream = new FileOutputStream("C:/Test/a.txt")) {
byte[] barr = new byte[] {(byte)'h', (byte)'e',(byte)'l',(byte)'l',(byte)'o'};
outputStream.write(barr);
}
}
我们往已经存在数据"hello" 的文件a.txt中, 写入了单词"world", 最后的结果为world, 所以这个write为覆盖写模式.
使用实例3
往文件a.txt中写入iLoveYou中的iLve
public static void main(String[] args) throws IOException{
try(OutputStream outputStream = new FileOutputStream("C:/Test/a.txt")) {
byte[] bytes = new byte[] {(byte)'i', (byte)'L',(byte)'o',(byte)'v',(byte)'e',(byte)'Y',(byte)'o',(byte)'u',};
outputStream.write(bytes,0,5);
}
}
使用实例4
如果我们输入的是字符串, 而不是byte[] 数组, 或者是单个字符, 那么就需要将字符串转化为byte数组, 使用String类的getBytes()方法, 如下:
public static void main(String[] args) throws IOException{
try(OutputStream outputStream = new FileOutputStream("C:/Test/a.txt")) {
String a = "hello world";
byte[] bytes = a.getBytes();
outputStream.write(bytes);
}
}
如果这里输入的是中文字符, 需要在getBytes()方法中传入字符串"UTF-8", 但是如果编译器默认的字符集为UTF-8,则可以忽略不计:
Java输入输出流的使用案例
我们可以设计一个, 遍历目录, 来查找文件, 找出文件中包含内容为"hello"的文件绝对路径
import java.io.*;
import java.util.Scanner;
public class IODemo1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("请输入您想要扫描的目录");
File file = new File(in.next());
// 如果file不是目录, 则表示输入的目录有误
if (!file.isDirectory()) {
System.out.println("您输入的为非法目录");
}
System.out.println("请输入您要查找的内容");
String search = in.next();
searchDir(file, search);
}
public static void searchDir(File file, String word) {
// 1. 列出当前目录下的目录集合
File[] files = file.listFiles();
if (files == null) {
// 空目录, 里面啥也没有
return;
}
// 遍历里面的每一个元素, 如果是文件, 就读取, 如果是目录就继续递归
for(File x : files) {
System.out.println("当前搜索到" + x.getAbsolutePath());
if (x.isDirectory()) {
searchDir(file,word);
} else if (x.isFile()) {
String content = readFile(x);
if (content.contains(word)) {
System.out.println(x.getAbsolutePath() + " 包含您想要的内容");
}
}
}
}
public static String readFile(File x) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
try (InputStream inputStream = new FileInputStream(x)) {
while (true) {
int b = inputStream.read();
if (b == -1) {
break;
}
stringBuilder.append((char)b);
}
}
return stringBuilder.toString();
}
}
本节完
😶🌫️