在系统中,我们的文件都是存储在硬盘上的,我们经常听到“硬盘”和“内存”两词,两者虽然都是用于存储数据,但有区别:
文件是存储在硬盘中的,我们要获取文件,就需要通过java中的File类,当然,在正式学习前,应该再了解一下相关知识
绝对路径:某文件被包含的所有路径,以盘符(也就是D盘,C盘等)为开头的就是绝对路径。如我想要打开D盘test文件夹内的的test1文件夹内的test2文件夹内的一个“hello.txt”文件:D:\test\test1\test2
相对路径:文件以某文件为参考物,相对在哪个路径上。
注意:虽然平时windows系统上的打开某文件夹用的是 “\” 反斜杠,但其实普遍情况下大家在表示打开文件夹时使用的是 “/” 正斜杠,只是当年最初的时候DOS的产品经理临时做了一个违背祖宗的决定——将大家平时都在使用的正斜杠/改为反斜杠\。产品上线后大家都在说不行,使用才改为了正斜杠反斜杠都可以,但我们平时在java中使用打开什么路径一般还是使用正斜杠“/”,否则如果我们要使用反斜杠,要经过反义才能使用,例如在编译器中使用正斜杠版本:D:/test/test1/test2;若使用反斜杠版本则变为了:D:\\test\\test1\\test2;
工作目录就是我们java程序默认在上面进行一系列操作的地方,就是我们项目所在的位置。要知道目前工作目录位置,我们可以这么操作:
通常对工作路径的使用,我们要结合相对路径,一般从工作路径开始,我们需要用“ ./ ”来开头。
File srcFile = new File("./src/test"); //打开目前工作路径的src文件夹中的test文件夹
为了找到文件,我们可以使用Java中的File类,来进行获取文件名字,判断是否为文件或是文件夹等操作。
import java.io.File;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Description: 在这里练习IO文件操作
* User: Lenovo
* Date: 2022-11-02
* Time: 20:43
*/
public class demo1 {
public static void main(String[] args) throws IOException {
// File file = new File("F:\\java练习专用\\java\\20221102\\src/hello.txt");
File file = new File("src/test"); //要看目前的工作路径
System.out.println(file.exists()); //判断该文件是否存在
System.out.println(file.getName()); //获取名字
System.out.println(file.getPath()); //获取相对路径
System.out.println(file.getCanonicalPath()); //获取优化后的绝对路径
System.out.println(file.getAbsolutePath()); //获取绝对路径
File[] arr = file.listFiles(); //将目前文件里面的所有文件提取出来
}
}
我们平常所说的IO,也就是输入输出流,全称为InputputStream和OutputStream。
因为文件都是存储在硬盘中的,因为我们无法直接对硬盘进行操作,所以要对文件进行读写操作,我们需要通过InputStream类和OutputStream类在内存中间接地对文件进行读和写的操作,具体示意图如下:
像inputStream这类操作硬盘数据的东西我们统称为“Handler”
在IO中,我们也分为字符流和字节流
InputStream类由于是抽象类,必须得由其子类来实例化,所以我们创建一个InputStream示例应该用FileinputStream类。
InputStream inputStream = new FileInputStream("src/hello.txt");
inputStream类的最主要方法为read(),read有三个版本
read()版本:全部读完
read(byte[] b)版本:读多少个字节
read(byte[] b, int off, int len)版本:从第几个字节开始读,读len个字节
我们要特别注意,在读文件之后,要注意关闭文件,也就是在操作完该文件后,我们要使用close()函数
这是因为在进程的PCB中,会有一个属性,名字为“文件描述符表”,该表是一个顺序表,里面放着的就是一个个这样子的文件类型,其下标对应成为“文件描述符”。
我们每创建一个文件类型,就会占文件描述符表的一个位置,而放满之后就文件描述符表就不会再一次扩容了,若我们要创建一个新的文件IO类型来操作,会失败,所以在每次使用完后,要注意使用close()函数来关闭该文件,也就是将该文件在文件描述符表中删除。
关于InputStream类型的使用,我们可以到Scanner类等,详情看下面代码:
import java.io.*;
public class demo4 {
public static void main(String[] args) throws IOException {
// File file = new File("src/hello.txt");
InputStream inputStream = new FileInputStream("src/hello.txt");
byte[] arr = new byte[1024];
int len = inputStream.read(arr);
String s = new String(arr,0,len,"utf-8");
for (int i = 0; i < len; i++) {
System.out.println(arr[i]);
}
System.out.println(s);
inputStream.close();
}
}
import java.io.*;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-11-02
* Time: 21:39
*/
public class demo5 {
public static void main(String[] args) throws IOException {
//使用该方法可以直接在try中完成后将inoutStream关闭
try(InputStream inputStream= new FileInputStream("src/hello.txt")){
byte[] arr = new byte[1024];
Scanner scan = new Scanner(inputStream);
String s = new String(scan.next());
System.out.println(s);
}catch(IOException e) {
}
}
}
注意,在try中创建流对象可以在try内的代码块完成后自动关闭,我们也可以通过分号在try内创建多个流对象,或者try嵌套来创建多个流对象。
在我们每次写完文件后,记得加一个.flush()函数,这是因为在操作系统中IO通常有些费时间,所以为了减少IO,系统会先将我们要输入的数据放入“缓冲区”先,等这个缓冲区满了,再写入,但是这样子有可能导致我们的一部分数据未写入,所以每次在写完数据后最好都使用flush。
OutputStream的使用方法其实和InputStream的使用方法差不多,详细使用看下面的代码:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class demo6 {
public static void main(String[] args) throws IOException {
try(OutputStream os = new FileOutputStream("src/hello.txt")){
String s = "郑小绿";
byte[] arr = s.getBytes("utf-8");
os.write(arr);
os.flush();
}
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class demo6 {
public static void main(String[] args) throws IOException {
try(OutputStream os = new FileOutputStream("src/hello.txt")){
String s = "郑小绿";
// byte[] arr = s.getBytes("utf-8");
byte[] arr = {'a','b','c','d'};
os.write(arr);
os.flush();
}
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class demo6 {
public static void main(String[] args) throws IOException {
try(OutputStream os = new FileOutputStream("src/hello.txt")){
String s = "郑小绿";
// byte[] arr = s.getBytes("utf-8");
byte[] arr = {'a','b','c','d'};
os.write(arr,1,2);
os.flush();
}
}
}
除了InputStream字节流读文件外,我们还可以使用Reader来读取字符文件。具体使用方法如下:
import java.io.*;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-11-02
* Time: 21:39
*/
public class demo5 {
public static void main(String[] args) throws IOException {
//使用1
Reader reader = new FileReader("src/hello.txt");
char[] arr = new char[1024];
int len = reader.read(arr);
System.out.println(len);
reader.close(); //要记得关闭文件
//使用2
// Scanner scan = new Scanner(reader);
// String s = scan.next();
// System.out.println(s);
// reader.close(); //要记得关闭文件
//使用3
// Reader reader = new FileReader("src/hello.txt");
// char[] arr = new char[1024];
// int len = reader.read(arr);
// String s = new String(arr,0,len);
// for (int i = 0; i < len; i++) {
// System.out.println(arr[i]);
// }
// System.out.println(s);
// reader.close(); //要记得关闭文件
//使用4
// Scanner scan = new Scanner(reader);
// String s = scan.next();
// System.out.println(s);
// reader.close(); //要记得关闭文件
}
}
和OutPutStream差不多
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class demo6 {
public static void main(String[] args) throws IOException {
try(OutputStream os = new FileOutputStream("src/hello.txt")){
String s = "郑小绿";
// byte[] arr = s.getBytes("utf-8");
byte[] arr = {'a','b','c','d'};
os.write(arr,1,2);
os.flush();
}
}
}
在这里着重介绍PrintWriter,在创建完该类后,我们可以像平常使用System.out.println来写入文件,具体使用如下代码:
import java.io.*;
public class demo7 {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
OutputStream os = new FileOutputStream("src/hello.txt");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os,"utf-8");
PrintWriter printWriter = new PrintWriter(outputStreamWriter);
printWriter.print("郑小绿 ");
printWriter.println("超6");
printWriter.println("宇宙无敌牛");
printWriter.flush();
}
}
要求:找到某文件,并让用户选择是否删除
代码:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-11-03
* Time: 0:23
*/
public class demo8 {
public static void scanFile(File srcFile,String del) {
for (File f: srcFile.listFiles()) {
if(f==null){
return;
}
if(f.isDirectory()){
scanFile(f,del);
}
if(f.isFile()){
try {
System.out.println(f.getCanonicalPath());
tryDel(f,del);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void tryDel(File f,String del) {
if(f.getName().contains(del)){
System.out.println("已发现该文件,是否删除?Y/N");
Scanner scan = new Scanner(System.in);
String choose = scan.next();
if(choose.equals("Y")){
f.delete();
}
}
}
public static void main(String[] args) throws IOException {
System.out.println("请输入你要查询的路径:");
Scanner scan = new Scanner(System.in);
String srcFile = scan.next();
File file = new File(srcFile);
if(!file.exists()){
System.out.println("输入的路径不正确或不存在");
return;
}
System.out.println("请输入你要删除的文件名字:");
String delFile = scan.next();
scanFile(file,delFile);
}
}
要求:选择某文件,然后复制到某指定路径内
代码:
import java.io.*;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-11-03
* Time: 9:53
*/
public class demo9 {
public static void main(String[] args) throws IOException {
System.out.println("请输入你要复制的文件路径:");
Scanner scan = new Scanner(System.in);
String src = scan.next();
File srcFile = new File(src);
if(!srcFile.exists()){
System.out.println("该路径错误或不存在");
return;
}
if(srcFile.isDirectory()){
System.out.println("输入的路径为目录,错误");
return;
}
System.out.println("请输入你需要复制到的路径(包含名字):");
String copyPath = scan.next();
try(InputStream inputStream = new FileInputStream(srcFile)){
try(OutputStream os = new FileOutputStream(copyPath)){
// byte[] buf = new byte[1024];
// int len = inputStream.read(buf);
// while(len!=-1){
// len = inputStream.read(buf);
// os.write(buf,0,len);
// os.flush();
// }
// byte[] buf = new byte[1024];
while(true){
byte[] buf = new byte[1024];
int len = inputStream.read(buf);
if(len==-1){
break;
}
os.write(buf);
os.flush();
}
}
}
}
}
在这里我们要注意,不使用注释内的代码原因是因为如果按照上面的代码进行读取,若第一次buf都没有读满,则很可能会导致程序多读了数据,导致文件出错。