目录
一、文件
Java I/O操作最常见的就是文件了。文件,可以理解为是一种外部设备,是记录或汇聚数据的地方。当然Java的世界里,文件对应的是java.io包下File类,文件本质上是数据,或是路径的抽象。
1、构造器
File类的构造器是用来创建文件对象的,大致有以下三种方式:
// 1:全路径(常用)
String path="D:\\ADC\\xxx.txt";
File file1 = new File(path);
// 2:URL(常用)
Stirng URL="";
File file2 = new file(URL); // 不同操作系统的路径表示不同
// 3:父路径+子路径
File file3 = new file("D:\\ADC\\","xxx.txt"); // 父路径为String
File file4 = new file(new File("D:\\ADC\\"),"xxx.txt"); // 父路径为File
2、文件操作
文件常见的操作方式有:(可以参考File类的相关API)
- 文件类型判断(比如:可读,可写,可执行,是否为隐藏文件、存在、目录、文件等)
- 文件路径API(绝对路径,相对路径等)
文件路径有关的测试:getPath方法、getAbsolutePath方法、getCanonicalPath方法
// 测试绝对路径
File file3 = File.createTempFile("2020-12-09-", ".log"
, new File("E:\\test\\filetest"));
logger.info("------getPath------》" + file3.getPath());
logger.info("------getAbsolutePath------》" + file3.getAbsolutePath());
logger.info("------getCanonicalPath------》" + file3.getCanonicalPath());
结果:
全部为绝对路径
// 测试相当路径 .
File file4 = File.createTempFile("yesterday", ".log", new File(".\\src\\main\\resources\\templates"));
logger.info("------getPath------》" + file4.getPath());
logger.info("------getAbsolutePath------》" + file4.getAbsolutePath());
logger.info("------getCanonicalPath------》" + file4.getCanonicalPath());
logger.info("------getParent------》" + file4.getParent());
结果:
- getPath方法获取的构造器指定的路径;
- getAbsolutePath方法获取的是user.id + getPath方法的结果;
- getCanonicalPath方法则是在getAbsolutePath方法基础上做了路径的规范,去除.。
// 测试相对路径 ..
// 全路径为:E:\test\filetest\abc\rs.txt
File file5 = new File("..\\abc\\rs.txt");
logger.info("------getPath------》" + file5.getPath());
logger.info("------getAbsolutePath------》" + file5.getAbsolutePath());
logger.info("------getCanonicalPath------》" + file5.getCanonicalPath());
logger.info("------getParent------》" + file5.getParent());
结果:
- getPath方法获取的构造器指定的路径;
- getAbsolutePath方法获取的是user.id + getPath方法的结果;
- getCanonicalPath方法则是在getAbsolutePath方法基础上做了路径的规范,去除..。
- 目录/文件的CRUD操作、权限设置等(文件/目录的创建,删除,遍历,设置可读可写可执行等权限)
public static void main(String[] args) throws IOException {
// 创建目录
File dir = new File("E:\\Pock");
if (!dir.exists()) {
System.out.println("目录不存在,正在创建...");
dir.mkdir();
}
// 创建文件
File file = new File("E:\\Pock\\1.txt");
if (!file.isFile()) {
System.out.println("文件不存在,正在创建...");
file.createNewFile();
}
// 删除目录/文件
file.delete();
// file.deleteOnExit();//JVM关闭时删除
dir.delete();
// 创建临时文件:为了避免出错,不指定文件路径
File tempFile = File.createTempFile("222", ".tt");
if (tempFile.exists()) {
System.out.println("临时文件已创建!");
}
tempFile.delete();
if (!tempFile.exists()) {
System.out.println("临时文件已被删除!");
}
// 文件遍历测试:带有文件名称过滤器的list() 或 listFiles()
// 网易云音乐的安装目录
File dirM = new File("D:\\WangYi Software\\云音乐\\CloudMusic");
File[] dirList = dirM .listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
// 过滤后缀为.exe文件
if(name.endsWith(".exe"))
return true;
return false;
}
}); // cloudmusic.exe
for (int i = 0; i < dirList.length; i++) {
// 控制前缀为cloudmusic
if (dirList[i].getName().startsWith("cloudmusic"))
System.out.print(dirList[i].getName() + "\n");
} // cloudmusic_util.exe
File deepFile = new File("D:\\Pock2\\");
deepeach(deepFile);
File widthFile = new File("D:\\POCK2\\");
widthForEach(widthFile);
}
/**
* 深度优先遍历:遍历从根节点开始,先左遍历,再右遍历。
* 利用递归的思想对目录和文件进行遍历。
*/
public static void deepeach(File dir){
if(!dir.exists()){
return;
}
File []file=dir.listFiles();
for (int i = 0; i < file.length; i++) {
if(file[i].isFile()){//如果是文件,直接打印出来
System.out.println("file is:"+file[i].getName());
}else{//如果是目录
System.out.println("dir is="+file[i].getName());
deepeach(file[i]);//递归
}
}
}
/**
* 广度优先遍历:层级输出
*/
public static void widthForEach(File dir){
//创建队列
Queue<File> queue=new LinkedList<File>();
queue.offer(dir);//入队
while(!queue.isEmpty()){
//不知道循环多少层级出队入队,所以用while
File poll = queue.poll();//目录出队
File[] lf = poll.listFiles();//得到子元素并遍历
for (File file : lf) {
if(file.isFile()){
System.out.println("file is"+file.getName());
}else{
System.out.println("dir is"+file.getName());
queue.offer(file);//下一级目录入队
}
}
}
}
二、Java IO
1、I/O 和 Stream
I/O:指的是输入Input方式和输出Output方式,是应用程序与外部设备(如文件、内存、管道、网络连接等)之间的数据传递。Stream:流,可理解为一个传输一串串数据的通道,这里的数据是字节或字符,Java中通过流处理I/O的,应用程序从外部设备读取数据时,是通过输入流InputStream实现的,而向外部设备写入数据,则是通过输出流OutputStream实现的。画个图就很容易理解:
当然,流的特点也很明显:FIFO方式(读数据是先进先出的,写数据也是先进先出的),顺序存取(读取的顺序是按写入的顺序来的,除了RandomAccessFile外),只读或只写(即一个流不能同时提供读和写操作)。
2、I/O流的分类
I/O流的分类方式,主要有以下3种:
- 按数据流的方向:输入流、输出流。
- 按处理数据单位:字节流、字符流。
- 按功能:节点流、处理流。
2.1 输入流 和 输出流
比如文件读写,读取文件是输入流,写文件是输出流。
2.2 字节流 和 字符流
二者用法几乎相同,区别在于操作的数据单元不同。字节流操作的数据单元是8位的字节,一般用来处理图像、视频、音频、PPT、Word等类型的文件;字符流操作的数据单元为16位的字符,一般用于处理纯文本类型的文件,如txt文件等,它不能处理图像、音视频等非文本文件。
字节流本身没有缓冲区的,缓冲字节流相对于字节流来说,效率则非常高。而字符流本身带有缓冲区,缓冲字符流的话,相对于字符流效率就不是那么大。
2.3 节点流 和 处理流
节点流,比如 FileInputStream,用来直接操作数据读写,而处理流,比如 BufferedInputStream,则是对也存在的流进行包装,增强强大而灵活的读写能力。处理流可以看作是节点流的一种增强方式,涉及到的设计模式则是包装模式了。
2.4 I/O流的基类及子类
I/O流有四个抽象基类:
- 字节输入流:InputStream
- 字节输出流:OutputStream
- 字符输入流:Reader
- 字符输出流:Writer
子类的话,总结为以下表格:(红色标记的为基类)
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
特殊流 | DataInputStream | DataOutputStream |
总结:
Java I/O流的简单入门就是这样,接下来会将结合源码的方式,对不同类型的流进行分析和举例。