文章目录
- @[toc]
- 文件IO
- 一、文件的概念
- 文件系统
- 文件路径:
- 文件类型
- 二、文件操作
- 1.文件系统的操作:
- File的构造和方法
- 创建文件
- 删除文件
- 等线程结束后删除文件
- 列出目录内容
- 创建目录
- 重命名
- 2.文件内容的操作:
- 1.字节流:对应二进制文件
- InputStream 输入
- OutStream 输出
- 2.字符流:对应文本文件
- Reader 输入
- Writer 输出
- demo
文章目录
- @[toc]
- 文件IO
- 一、文件的概念
- 文件系统
- 文件路径:
- 文件类型
- 二、文件操作
- 1.文件系统的操作:
- File的构造和方法
- 创建文件
- 删除文件
- 等线程结束后删除文件
- 列出目录内容
- 创建目录
- 重命名
- 2.文件内容的操作:
- 1.字节流:对应二进制文件
- InputStream 输入
- OutStream 输出
- 2.字符流:对应文本文件
- Reader 输入
- Writer 输出
- demo
文件IO
一、文件的概念
“文件”是一个广义的概念
在操作系统中,会把很多的 硬件设备 和 软件资源 都抽象成“文件”,同一进行管理。大部分情况下,谈到的文件,都是指硬盘的文件。文件就相当于是针对“硬盘”数据的一种抽象。
在编程的过程中,并不需要知道具体的存储细节,只是根据文件来进行操作
机械硬盘(HDD)
适合顺序读写,不适合随机读写,因为磁头的移动需要花费时间。
固态硬盘(SSD)
- 往往都是通过文件的方式来操作硬盘。
文件系统
文件是通过”文件系统“来进行组织管理的,是操作系统提供的模块。操作系统使用“目录”(树形结构)来组织文件,“此电脑”就是目录树的根节点。而一个个文件夹,就是目录(directory)。目录可以包含目录或者文件。
文件路径:
- 使用目录的层次结构来描述文件所在的位置
绝对路径:以盘符开头,到达指定文件。
相对路径:以.或者…开头的。先指定一个目录,作为基准目录,从基准目录出发,到达指定文件。
.当前目录 …当前目录的上一级
如果是命令行进行操作,基准目录就是当前所处的目录
对于IDEA来说,基准目录就是项目目录。
文件类型
从编程的角度出发,文件的类型分为两大类:
1.文本文件:文件中保存的数据都是字符串,保存的内容都是合法的字符
2.二进制文件:文件中保存的数据仅仅是二进制数据,不要求保存的内容合法。
虽然本质上存储的数据都是二进制的,但是区别就是是否能转换成合法的字符。
合法字符:符合字符集/字符编码 utf-8的字符
二、文件操作
Java针对文件的操作,分为两类
1.文件系统的操作:
例如创建文件、删除文件、判定文件、重命名等
这些操作同样可以在Java代码中完成。这些操作依赖了File类,封装了这些操作。
File的构造和方法
pathSeparator属性 :依赖于系统的路径分隔符 :
windows \ 和 / 都可以 ,但是Linux和Mac 上是 “ / ”
一个File对象,就表示了一个硬盘上的文件。在构造对象的时候,需要制定这个文件的路径
public static void main(String[] args) throws IOException {File file = new File("./test.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());//获取当前文件的修饰过的绝对路径 (简化) windows上的盘符不区分大小写}
.
test.txt
.\test.txt
F:\java\multi-thread\.\test.txt
F:\java\multi-thread\test.txt
创建文件
public static void main(String[] args) throws IOException {File file= new File("e:/test.txt");System.out.println(file.exists());//判断当前文件是否存在System.out.println(file.isDirectory());//判断是不是目录System.out.println(file.isFile());//判断是不是文件//创建文件boolean ret = file.createNewFile();System.out.println("ret= "+ret);System.out.println(file.exists());System.out.println(file.isDirectory());System.out.println(file.isFile());}
false
false
false
ret= true
true
false
true
删除文件
public static void main1(String[] args) {File file = new File("e:/test.txt");boolean ret = file.delete();//删除文件System.out.println("ret = "+ret);}
等线程结束后删除文件
public static void main(String[] args) throws InterruptedException, IOException {File file = new File("e:/test.txt");file.createNewFile();file.deleteOnExit();//进程结束之后再进行删除Thread.sleep(5000);System.out.println("进程结束");}
列出目录内容
public static void main(String[] args) {File file = new File("e:/");String[] files = file.list();//System.out.println(files);如果直接打印,打印的是这个数组对应的hashcodeSystem.out.println(Arrays.toString(files));//打印目录列表}
创建目录
public static void main(String[] args) {File file = new File("e:/test111/222/333");boolean ret = file.mkdirs();System.out.println(ret);}
重命名
public static void main(String[] args) throws IOException, InterruptedException {File scrFile = new File("e:/test.txt");scrFile.createNewFile();Thread.sleep(5000);File destFile = new File("e:/test2.txt");boolean ret = scrFile.renameTo(destFile);System.out.println(ret);}
2.文件内容的操作:
利用流对象(Steam)对文件进行操作
像水流一样,可以分成无数种方案,称为文件流
1.字节流:对应二进制文件
InputStream 输入
- read的返回值是int,实际表示的是byte(0~255之间的数据),使用-1表示读到文件末尾
- 读取的是内容的ascii码
try(InputStream inputStream = new FileInputStream("e:/test.txt")){byte[] buffer = new byte[1024];int n = inputStream.read(buffer);System.out.println("n= "+n);for (int i = 0; i < n; i++) {System.out.printf("%x\n",buffer[i]);}} catch (IOException e) {throw new RuntimeException(e);}
字节流转化成字符流
public static void main(String[] args) {try(InputStream inputStream = new FileInputStream("e:/test.txt")){Scanner scanner = new Scanner(inputStream);//字节流转化成字符流String s = scanner.next();System.out.println(s);} catch (IOException e) {throw new RuntimeException(e);}}
OutStream 输出
每读写的最小单位,都是“字节”(8bit)
try (OutputStream outputStream = new FileOutputStream("e:/test.txt",true)){String s = "你好世界";outputStream.write(s.getBytes());} catch (IOException e) {throw new RuntimeException(e);}
把字节流转化创了字符流
public static void main(String[] args) {try(OutputStream outputStream = new FileOutputStream("e:/test.txt")){PrintWriter writer = new PrintWriter(outputStream);//把字节流转化创了字符流//PrintWriter 这样的类,在进行写入的时候,不一定直接写进硬盘,而是存进内存构成的“缓冲区中(buffer)”//为了确保数据被写进硬盘,需要用flush方法手动刷新缓冲区writer.println("hello");writer.flush();//刷新缓冲区} catch (IOException e) {throw new RuntimeException(e);}}
2.字符流:对应文本文件
Reader 输入
Reader是一个抽象类,不能直接new 。
read方法的三种版本:
1.无参数read,一次读一个字符。
File file = new File("e:/test.txt");Reader reader = new FileReader("e:/test.txt");while (true){int c = reader.read();if (c==-1){break;}char ch = (char) c;System.out.println(ch);}
2.一次会读取若干个字符,会把参数指定的cbuf数组填充满,填不满也没关系,读的是所有的数据
- 往read中传入一个空的数组,由read方法来对数组内容进行填充。
- cbuf 称为”输出型参数“,类似于拿着餐盘打饭
//一次read多个while (true){char[]cbuf = new char[1024];//数组大小int n = reader.read(cbuf); //n表示当前读到的字符个数if (n==-1){break;}System.out.println("n= "+n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}
3.一次会读取若干个字符,会把参数指定的cbuf数组,从off到len的范围填满
reader.close();
- 在读取完成之后,一定要进行close操作!!!
防止文件资源泄露:使用close方法,最主要的目的,是为了释放文件描述符。文件描述符表是一个顺序表的结构,一个进程每打开一个文件,就需要在这个表里分配一个元素,但是整个顺序表的大小是有上限的。如果代码一直打开文件,而不去关闭文件,就会占满顺序表,后续打开文件就会出错。
try {while (true){char[]cbuf = new char[1024];int n = reader.read(cbuf);//n表示当前读到的字符个数if (n==-1){break;}System.out.println("n= "+n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}}finally {reader.close();}
无论try当中的代码是正常执行的,还是出现异常终止,都不会影响finally当中的close执行。
- try with resources 语法:在()中定义的变量(实现closeable接口的对象),会在try结束的时候自动调用其close方法。
try ( Reader reader = new FileReader("e:/test.txt")){while (true){char[]cbuf = new char[1024];int n = reader.read(cbuf);if (n==-1){break;}System.out.println("n= "+n);for (int i = 0; i < n; i++) {System.out.println(cbuf[i]);}}}
-
read方法的返回值是int类型的。如果真的读到了字符,会返回0~65535(无符号 char能表示的范围),如果到达了流的末尾,就会返回-1,表示文件读完了。
-
同时Java标准库内部,对字符编码进行了很多处理。如果只使用char,字符集就固定是unicode。如果使用String,就会自动的把每个字符的unicode转换成utf-8。
Writer 输出
public static void main(String[] args) {try(Writer writer = new FileWriter("e:/test.txt")) {writer.write("学习writer.write方法");} catch (IOException e) {throw new RuntimeException(e);}}
-
Writer写入文件,默认会把原有的文件内容清空,再写入。如果不想清空,需要在构造方法中多加参数
try(Writer writer = new FileWriter("e:/test.txt",true)) {
每次读写的最小单位,都是“字符”(一个字符可能对应多个字节)一个中文字符:GBK(2字节)UTF-8 (3字节)
字符流本质上是对字节流的进一步封装。字符流可以自动的把文件中相邻的字节,转换成一个字符。(自动查字符集表)
输入和输出,是根据CPU的视角出发的。
demo
- 扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件
public static void main(String[] args) {//先让用户输入一个要扫描的目录Scanner sc = new Scanner(System.in);System.out.println("请输入要扫描的路径");String path = sc.next();File rootPath = new File(path);if (!rootPath.isDirectory()) {System.out.println("你输入的扫描路径有误");return;}//输入要查询的关键词System.out.println("请输入要删除文件的关键词");String word = sc.next();//进行递归扫描scanDir(rootPath, word);}private static void scanDir(File rootPath, String word) {//列出所有的文件和目录File[] files = rootPath.listFiles();if (files == null) {return;}for (File f : files) {System.out.println("当前扫描的路径"+f.getAbsolutePath());if (f.isFile()) {//文件checkDelete(f, word);//检查文件是否需要删除} else {//目录scanDir(f, word);//递归子目录}}}private static void checkDelete(File f, String word) {if (!f.getName().contains(word)){return;}System.out.println("当前文件为:"+f.getAbsolutePath()+"请确认是否删除(Y/N)");Scanner scanner = new Scanner(System.in);String choice = scanner.next();if (choice.equals("Y")||choice.equals("y")){f.delete();System.out.println("删除成功");}else {System.out.println("取消删除");}}
点击移步博客主页,欢迎光临~