文件IO
狭义的文件: 硬盘上的文件和目录
广义上的文件: 泛指计算机中很多的软硬件资源.OS中,把很多硬件设备和软件资源抽象为文件.按照文件的方式统一管理.网卡也是一个文件.
-
每个文件在硬盘上都有具体的路径.绝对路径和相对路径.
-
绝对路径: 以根目录开头的路径
-
相对路径: 以当前所在目录(工作目录)为基准,以
. ..开头找到指定的路径
-
文件分类大致可分为两类: 文本文件和二进制文件
- 针对文件系统的操作: 删除,创建,重命名
- 针对文件内容的操作: 读写
File类
文件系统操作设置
package IOCode;
import java.io.File;
import java.io.IOException;
public class IODemo1 {
public static void main(String[] args) throws IOException {
//相对路径
File file=new File("./test1.txt");
System.out.println(file.getName());
System.out.println(file.getParent());
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
//test1.txt
//.
//.\test1.txt
//D:\java_projects\javaeeCode\.\test1.txt
//D:\java_projects\javaeeCode\test1.txt
//绝对路径
File file2=new File("d:/test2.txt");
System.out.println(file2.getName());
System.out.println(file2.getParent());
System.out.println(file2.getPath());
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getCanonicalPath());
//test2.txt
//d:\
//d:\test2.txt
//d:\test2.txt
//D:\test2.txt
}
}
package IOCode;
import java.io.File;
import java.io.IOException;
public class IODemo2 {
public static void main(String[] args) throws IOException {
File file=new File("d:/test3.txt");
System.out.println(file.exists());
System.out.println(file.isFile());
System.out.println(file.isDirectory());
//false
//false
//false
File file2 =new File("./test4.txt");
System.out.println(file2.exists());
System.out.println(file2.isFile());
System.out.println(file2.isDirectory());
file2.createNewFile();
System.out.println(file2.exists());
System.out.println(file2.isFile());
System.out.println(file2.isDirectory());
//false
//false
//false
//true
//true
//false
}
}
package IOCode;
import java.io.File;
public class IODemo3 {
public static void main(String[] args) {
File file =new File("./test4.txt");
file.delete();
file.deleteOnExit();
//在程序退出时才会删除.系统结束时的"临时文件"使用这个删除.
// word文件打开时默认生成一个~临时文件.保存了当前实时编辑的内容还未保存的东西.
//下次再次word启动时,提醒提前导入这个临时文件.
}
}
package IOCode;
import java.io.File;
public class IODemo4 {
//目录创建
public static void main(String[] args) {
//创建一级目录
File dir = new File("./testDir1");
dir.mkdir();
//创建多级目录
File dir2 =new File("./testDir2/aaa/bbb");
dir2.mkdirs();
}
}
package IOCode;
import java.io.File;
public class IODemo5 {
public static void main(String[] args) {
File dir1=new File("./testDir1");
File dir2 =new File("./test7");
dir1.renameTo(dir2);
}
}
流对象
文件内容修改
针对文件内容,是采用流对象进行操作的.
"流" 本身就是OS的API接口提供的,所以其他编程语言也继承下来.
- 字节流 以字节为单位读写数据
InputStream OutputStream操作二进制数据
- 字符流 以字符为单位读写数据
Reader Writer操作文本数据
以上四种都是抽象类,不能直接new出对象,所以需要对它进行继承和重写.
抽象 vs 具象 差别就在于给定信息的多和少.抽象的提供的信息是非常少的,但是具象信息量就比较丰富,比较具体.
抽象类:大部分都是确定的,只有一些是不确定的.
接口: 大部分都是不确定的,方法都是抽象方法.(不考虑之后提供的
default)
- 大致过程都是如下:
- 打开文件,构造对象
- 读文件(
read) =>针对InputStream- 写文件(
write)=> 针对OutputStream- 关闭文件(
close)
字节流操作文件
字节流输入read
- read一次就会走一次IO.
- 缓冲区的存在就是为了减少IO的次数,一次读取多个字节放到缓冲区当中.此时可以提升整体的效率.
package IOCode;
import java.io.*;
public class IODemo6 {
//读取多个字节放到缓冲区当中
public static void main(String[] args) throws IOException{
InputStream inputStream =new FileInputStream("./src/IOCode/test1.txt");
while(true){
byte[] buffer =new byte[1024];
int len=inputStream.read(buffer);
//将buffer交给read进行填写,这里是输入输出型参数,使用参数来返回内容
if(len==-1){
//代表读取完成
break;
}
for(int i=0;i<len;i++){
System.out.printf("%x\n",buffer[i]);
}
}
inputStream.close();
//e4
//bd
//a0
//e5
//a5
//bd
}
//每次只读取一个字节
public static void main1(String[] args) throws IOException {
// 读取文件以字节流的方式读取
InputStream inputStream= new FileInputStream("./src/IOCode/test1.txt");
while(true){
int b = inputStream.read();//read返回值是读取到的一个字节byte,因为要表示读写完毕的情况,所以用int 接收
//无参数默认读一个字节
//一个参数: 将读取的内容放到指定字节数组当中.返回值是读取的字节数
//三个参数: 往数组的一部分区间当中写入
if(b==-1){//返回值是int 类型,-1代表读取完成
break;
}
// System.out.println(" "+ (byte)b);
System.out.printf("%x \n",(byte)b);
}
inputStream.close();
//test1.txt: hello 读取出来的就是对应字符的ASCII码值
// 104
// 101
// 108
// 108
// 111
//16进制打印得到结果如下:
//68
//65
//6c
//6c
//6f
//d
//a
//e4
//bd
//a0
//e5
//a5
//bd
}
}
字节流输出write
package IOCode;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo7 {
//保证close操作一定被执行的方式二(推荐)
public static void main(String[] args)throws IOException {
try(OutputStream outputStream=new FileOutputStream("./src/IOCode/test1.txt")){
outputStream.write(99);
outputStream.write(100);
outputStream.write(101);
}
//虽然没有显示的调用close,但是在try语句块执行完毕之后,还是会执行close的.
//这个语法Java中叫做try with resources
//只有实现了Closeable接口的类,才能够放到try的()中自动关闭.
}
//保证close操作一定被执行的方式一
public static void main2(String[] args) throws IOException{
OutputStream outputStream=null;
try{
outputStream =new FileOutputStream("./src/IOCode/test1.txt");
outputStream.write(99);
outputStream.write(100);
outputStream.write(101);
}finally {
outputStream.close();
}
}
public static void main1 (String[] args) throws IOException {
//默认打开文件的时候将原本的内容删除
OutputStream outputStream = new FileOutputStream("./src/IOCode/test1.txt");
outputStream.write(99);
outputStream.write(100);
outputStream.write(101);
outputStream.close();
//关闭文件,文件描述符表(数组)记录了进程打开了哪些文件,将表中元素释放掉
//如果不释放,表中元素会一直存在,可能会一瞬间将表打满,如果满了后续就无法再申请打开文件
//文件描述符表上限也就几百个到几千个
//close并不是必须要执行的,因为进程结束时OS会回收为进程安排的空间,比如PCB以及文件描述符表
//此时表数组被删除了,里面你未曾close的文件对象也会被释放.
//
}
}
字符流
字符流读取
package IOCode;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.*;
public class IODemo8 {
//字符流读取
public static void main(String[] args) throws IOException {
try(Reader reader =new FileReader("./src/IOCode/test1.txt")){
while(true){
int ch= reader.read();//读取到的是一个字符,但是返回值设置为int 类型
if(ch==-1){
break;
}
System.out.println(""+ (char)ch);
}
}catch(IOException e){
e.printStackTrace();
}
//你
//好
//a
//b
//c
}
}
字符流写入
package IOCode;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class IODemo9 {
public static void main(String[] args) throws IOException {
try(Writer writer =new FileWriter("./src/IOCode/test1.txt")){
writer.write("a");
writer.write("b");
writer.write("abcd");
writer.flush();
}catch (IOException e){
e.printStackTrace();
}
}
}
- 写文件内容并没有真的在文件中出现,很可能就是因为缓冲区的存在
write操作,其实是先写到缓冲区当中.OS内核也可能有缓冲区,标准库也有缓冲区.写操作执行完成,内容可能就在缓冲区中,没有真正写入硬盘.
close操作,就会触发缓冲区的刷新(冲刷)
flush.
- 针对
Scanner
package IOCode;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class IODemo10 {
public static void main(String[] args) {
try(InputStream inputStream =new FileInputStream("./src/IOCode/test1.txt")){
Scanner scanner=new Scanner(inputStream);//传给Scanner的就是文件字节输入流对象
scanner.next();
//此时的读取就是从 文件 中进行读取了
}catch (IOException e){
e.printStackTrace();
}
}
public static void main1(String[] args) {
Scanner scanner=new Scanner(System.in);
// public final static InputStream in = null;
//说明这个in也是一个输入流,是一个字符输入流对象
}
}
此时内部的inputStream对象已经被try()关闭了,里面的Scanner不关闭也没关系.
实例练习
文件操作实例1
- 扫描指定目录,并找到名称中包含指定字符的普通文件(不包含目录)
- 用户输入要查询的词,看看当前目录下是否存在
- 查找成功之后,由用户决定是否删除这个文件
package IOCode;
import java.sql.SQLOutput;
import java.util.Scanner;
import java.io.File;
public class IODemo11 {
private static Scanner scanner=new Scanner(System.in);
public static void main(String[] args) {
//1. 让用户输入指定搜索的目录
// Scanner scanner =new Scanner(System.in);
System.out.println("请输入指定搜索的目录# ");
String basePath= scanner.next();
File root= new File(basePath);
//2. 针对用户输入进行判定
if(!root.isDirectory()){
System.out.println("输入的目录名称有误~");
return;
}
//3. 用户输入想要删除的文件名
System.out.println("请输入想要删除的文件名# ");
String nameToDelete=scanner.next();
//针对指定目录进行扫描,递归操作
//从根目录出发,查看是否包含需要删除的文件,是就删除,不是就下一个
//如果遇到目录,再针对这个子目录进行查找删除操作
scanDir(root,nameToDelete);
}
private static void scanDir(File root, String nameToDelete) {
//1. 先列出当前目录下的文件
File[] files=root.listFiles();//将目录下的文件放到数组中,相当于双击一个目录,显示结果
if(files==null){
return ;
}
//2. 遍历当前列出的结果
for (int i = 0; i < files.length; i++) {
if(files[i].isDirectory()){//当前是目录,递归走处理子目录
scanDir(files[i],nameToDelete);
}else{//当前是文件
if(files[i].getName().contains(nameToDelete)){
System.out.println("要删除 "+files[i].getAbsolutePath()+"这个文件吗? Y or N");
String choice = scanner.next();
// if(choice == "Y"){//这种比较java只是比较引用
if(choice.equals("Y")) {//这才是String对象的比较方式
files[i].delete();
System.out.println("删除成功~");
}else {
System.out.println("删除取消~");
}
}
}
}
}
}
文件操作实例2
进行普通文件的复制.读取一个文件,将文件中内容写入到另一个文件当中.
- 以字节流方式拷贝,不管是什么类型的文件都是字节构成的,拷贝之后肯定是一样的.
package IOCode;
import java.io.*;
import java.sql.SQLOutput;
import java.util.Scanner;
public class IODemo12 {
public static void main(String[] args) throws IOException {
//输入源文件目录和目标文件目录
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要拷贝哪个文件#");
String srcPath = scanner.next();
System.out.println("请输入要被复制到哪个目标去#");
String destPath=scanner.next();
File srcFile=new File(srcPath);
if(!srcFile.isFile()){
//源文件不存在/给定的是一个目录
System.out.println("源文件输入有误~");
return ;
}
File destFile= new File(destPath);
if(destFile.isFile()){
//如果复制目标文件已经存在,认为也不能拷贝
System.out.println("目标路径有误~");
return;
}
//支持包含多个流对象
try(InputStream inputStream =new FileInputStream(srcFile);
OutputStream outputStream =new FileOutputStream(destFile)){
while(true){
int b=inputStream.read();
if(b==-1){
break;
}
outputStream.write(b);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
OutputStream查找到没有文件,会创建一个新的文件InputStream没有查找到指定文件名的文件,会报错,不会创建.

被折叠的 条评论
为什么被折叠?



