文件操作和IO(Java版)
在开始本文内容的介绍之前,相信大家都知道,一般情况我们电脑上的数据(长期保存的那种)都是存储在硬件设施--硬盘上的。硬盘上存储的数据又被抽象地叫做“文件”。这里的文件与我们后文操作修改的可以近似等价。
文件的初识
广义文件和狭义文件
可能有人会问,“文件不应该是在文件夹里的吗?怎么又在硬盘里面去了”,这就会涉及到“狭义的文件”和“广义的文件”。
- 狭义的文件:我们文件夹中保存的,一个个独立的存储数据的容器,叫做“狭义的文件”(文件名称,文件类型各不相同)
- 广义的文件:存储在硬盘上的数据,抽象成文件
其中广义的文件又包含两大类:
- 文件夹:别称“目录”,用于存放许多普通文件(类似于“多叉树”的数据结构,文件夹就相当于是一个“根”,对于不同树,就有不同文件夹和“根结点”)
- 普通文件:就是存储数据的“容器”,可以存储不同类型的数据,也有不同的格式
文件路径
那么电脑中那么多文件(普通文件和文件夹),我们该如何才能找到需要的那个文件呢?正常找,猴年马月都找不完,于是我们使用--文件路径来作为寻找文件的线索。
在我们先前说到的,操作系统管理文件,是采取“多叉树目录”的结构,因此,我们做有如下规定:
1.文件的管理是一棵树,树中结点可以是“普通文件”和“文件夹”
2.我们通常将“文件夹”视为某棵树的“根结点”
那么在如此规定下,从最头部的根节点连接到“文件”(硬盘上的概念)的路径,就是“文件路径”。
文件路径又分为:“绝对路径”和“相对路径”。

文件内容
文件也可以通过文件中存储的内容的类型作为分类的标准:
- 二进制文件:像点开乱七八糟的,就是二进制文件。这是交由机器来读取的内容

- 文本文件:像这种里面存储的是文本信息,我们人眼能看懂的正常内容,就是文本文件


操作文件
文件系统操作:
接下来在这部分,我们要介绍的方法都是对文件的创建,移动,复制等直接操作文件的操作,不会涉及到文件内容的读写操作。
File类的构造方法与常见方法:
我们使用创建File类对象(用一个文件路径),来抽象表示一个普通文件/目录,但需要注意的是“file对象存在,不代表对应的文件也存在”。我们就来介绍一下这个能把文件抽象化的类,到底怎么使用。
属性:
| 修饰符及类型 | 属性 | 说明 |
| static String | pathSeparator | 依赖于系统的路径分隔符,String类型的表示,一般是“/” |
| static char | pathSeparator | 依赖于系统的路径分隔符,char类型的表示 |
构造方法:
| 签名 | 说明 |
| File(File parent,String child) |
根据父目录+孩子文件路径,创建一个新的File实例 (parent是一个File对象) |
| File(String pathname) |
根据文件路径创建一个新的File实例,路径可以是绝对路径或者相对路径 |
| File(String parent,String child) | 根据父目录+孩子文件路径,创建一个新的File实例,父目录用路径表示 |
方法:
| 修饰符及返回值类型 | 方法签名 | 说明 |
| 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) | 进行文件改名,也可以视作剪切,粘贴操作 |
方法的使用示例:
关于文件路径相关的方法:
public class demo1 {
public static void main(String[] args) throws IOException {
//这部分内容,主要是对文件路径进行操作
//操作管理文件,不涉及改写文件的内容
//创建文件File对象
//根据一个绝对路径/相对路径创建一个File实例,可以真正创建一个文件
File file=new File("d:/Java.IO/thetest.txt");
//对文件的路径的操作
System.out.println("file对象的文件的父目录路径是"+file.getParent());
System.out.println("file对象的文件的纯文件名称是"+file.getName());
System.out.println("file对象的文件的文件路径是"+file.getPath());
System.out.println("file对象的文件的文件绝对路径是"+file.getAbsolutePath());
System.out.println("file对象的文件的修饰过的绝对路径是"+file.getCanonicalPath());
}
}

关于判断文件类型和存在的方法:
public class demo2 {
public static void main(String[] args) {
//判断file对象对应的文件的属性(存在/类型)
File file=new File("d:/Java.IO/test.txt");
System.out.println("file对象对应的文件是否存在:"+file.exists());
System.out.println("file对象代表的文件是否是一个目录(文件夹)"+file.isDirectory());
System.out.println("file对象代表的文件是否是一个普通文件"+file.isFile());
}
}

关于创建指定位置的文件/目录的方法:
public class demo3 {
public static void main(String[] args) throws IOException {
File file=new File("d:/Java.IO/one.txt");
//根据file对象(传入的绝对路径)自动创建一个空文件
System.out.println("指定文本文件是否创建成功:"+file.createNewFile());
//根据file对象(传入的绝对路径)删除该文件
//System.out.println("指定文本文件是否删除成功:"+file.delete());
//根据file对象(传入的绝对路径)在该进程结束后删除这个文件
//file.deleteOnExit();
}
}

关于取出指定目录下的所有文件相关的方法:
public class demo4 {
public static void main(String[] args) {
File file=new File("d:/Java.IO");
//返回file对象目录下所有文件名,注意返回的是String类型的文件名字
// String[] s=file.list();
// if(s==null){
// System.out.println("该目录是空的");
// }
// //通过for each的遍历打印方式(前:打印的数据类型,后:数组的名字)
// for (String a:s){
// System.out.println(s);
// }
//同样返回目录下所有文件名字,但是接受数组是File[]
File[] s= file.listFiles();
if(s==null){
System.out.println("该目录是空的");
}
for (File a:s){
System.out.println(a.getName());
}
}
}

关于创建目录以及重命名文件(移动文件)的方法:
public class demo5 {
public static void main(String[] args) {
File file=new File("d:/Java.IO/aaa");
//创建file对象代表的目录
System.out.println("指定的单层目录是否创建成功:"+file.mkdir());
//创建多个目录(可能给定的路径中的目录不是都存在,就需要我们一起都创建了)
File file1=new File("d:/Java.IO/bbb/ccc");
System.out.println("指定的多层目录是否创建成功:"+file1.mkdirs());
//对文件进行改名(本质就是移动文件)->变成目标名字(对你的路径中名字进行修改,其实也可以更改路径实现粘贴(移动文件)到其他目录中)
File file2=new File("d:/Java.IO/test.txt");
//test文本文件要更改成的目标名字
File file2des=new File("d:/Java.IO/the test.txt");
System.out.println("指定的文件是否成功重命名成功:"+file2.renameTo(file2des));
File file3=new File("d:/Java.IO/one.txt");
//one文件要移动去的新地址
File file3des=new File("d:/Java.IO/aaa/one.txt");
System.out.println("指定的文件是否成功移动到了指定的目录下:"+file3.renameTo(file3des));
}
}

因为我们先前已经实验操作过了,因此,这里显示的结果是false
注:这里的移动文件是因为本方法的本质是:“改写文件路径名”,从而可以实现移动
文件内容操作:
文件内容操作:对文件内容进行读和写操作
对文件内容的操作,我们都是使用“流对象”,Java标准库中给我们提供了一系列“流”的类
其中根据不同的读和写的单位,分为“字节流”和“字符流”
1.字节流:在读写过程中,以字节为单位,针对“二进制文件”
- InputStream:输入,在读取文件内容时使用
- OutputStream:输出,在写入文件内容时使用
2.字符流:在读写过程中,以字符为单位,针对“文本文件”
- Read:输入,从文件读取内容
- Write:输出,对文件写入内容
字节流:
对于InputStream和OutputStream,它们两个是抽象类,我们想要具体实现操作要使用它们的继承类--FileInputStream和FileOutputStream才能真正进行文件内容操作。
InputStream概述:
| 修饰符及返回值类型 | 方法签名 | 说明 |
| int | read() | 读取一个字节的数据,返回-1代表已经完全读完了 |
| int | read(byte[] b) | 最多读取b,length字节的数据到b中,返回实际读到的数量;-1代表已经读完了 |
| int | read(byte[] b,int off,int len) | 最多读取len-off字节的数据到b中,放在从off开始,返回实际读到的数量;-1代表已经读完了 |
| void | close() | 关闭字节流 |
FileInputStream概述
| 签名 | 说明 |
| FileInputStream(File file) | 利用File构造文件输入流 |
| FileInputStream(String name) |
利用文件路径构造文件输入流 |
注意!!!因为我们FileInputStream是继承的子类,因此可以直接使用父类的方法
代码示例:
public class demo6 {
//从现在开始进入对文件内容读写(对文件内容修改)的部分
public static void main(String[] args) throws IOException {
File file=new File("d:/Java.IO/the test.txt");
//此处是字节流的读写操作(操作的单位是一个字节)
//读操作
//InputStream inputStream=new FileInputStream(file);
//读取一个字节的数据,返回-1即读完
//本质是:每次都会返回一个数字(一般是按照ASCLL码对应的数字(每个对应一个符号),当读完时,则返回-1)
// while (true){
// int n=inputStream.read();
// if(n==-1){
// break;
// }
// System.out.printf("此时读到的时"+"%x\n",n);
// }
//输出型函数的读取,本质是传入一个数组,然后把读取结果全部放在这个数组里面返回,函数的返回值只是“结束”的标志
byte[] a=new byte[100];
// while (true) {
// int n = inputStream.read(a);
// if(n==-1){
// //第二次读,会发现文件已经读完,会返回-1
// break;
// }
// //由于第一次读完会直接返回读到的数量,因此n此时是读取到的有效的个数
// for (int i=0;i<n;i++){
// System.out.printf("%x\n",a[i]);
// }
// }
//如果遇到文本文件中是中文字符的情况,使用scanner来读取获得最好
// int n=inputStream.read(a);
// if(n==-1){
// break;
// }
try(InputStream inputStream=new FileInputStream(file)) {
try (Scanner scanner = new Scanner(inputStream, "UTF-8")) {
while (scanner.hasNext()) {
String s = scanner.next();
System.out.print(s);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
}
}

注:如果我们遇到了文件中是中文的情况,可以使用Scanner来处理更方便!!!
OutputStream概述:
| 修饰符及返回值类型 | 方法签名 | 说明 |
| void | write(int b) | 写入要给字节的数据 |
| void | write(byte[] b) | 将b这个字符数组中数据全部写入os中 |
| int | write(byte[] b,int off,int len) |
将b这个字符数组中从 off开始的数据写入os中,一共写len个 |
| void | close() | 关闭字节流 |
| void | flush() | 背景:文件的读写操作是很慢的,因此OutputStream为了减少设备操作的次数,写入数据会写入缓存区,等到缓存区满了之后才会真正写入设备中。但可能会造成我们上一部分的数据遗留到下一部分,这就需要我们手动刷新发送过去 |
FileOutputStream概述:
| 签名 | 说明 |
| FileOutputStream(File file) | 利用File构造文件输入流 |
| FileOutputStream(String name) | 利用文件路径构造文件输入流 |
代码示例:
public static void main(String[] args) throws IOException {
//每次写都是把文件里的内容清空重写
File file=new File("d:/Java.IO/aaa/one.txt");
// try (OutputStream outputStream=new FileOutputStream(file);) {
// //写入一个字节一次
// for (int i = 65; i < 70; i++) {
// outputStream.write(i);
// }
// }
//使用写入整个字节数组中的数据
// byte[] a={97,98,99,100,101};
// try(OutputStream outputStream=new FileOutputStream(file)) {
// outputStream.write(a);
// outputStream.flush();
// }
//写入一个字符串
// String s="hello world";
// byte[] a=s.getBytes();
// try (OutputStream outputStream=new FileOutputStream(file)){
// outputStream.write(a);
// outputStream.flush();
// }
//写入一个中文字符串
String s="你好,牢大";
byte[] a=s.getBytes("UTF-8");
try (OutputStream outputStream=new FileOutputStream(file)){
outputStream.write(a);
outputStream.flush();
}
//可以指定,我们的内容是追加写入,不会清空文件内容
s="see you again";
a=s.getBytes();
try (OutputStream outputStream=new FileOutputStream(file,true)){
outputStream.write(a);
outputStream.flush();
}
}
注:1.每次写入文件内容,记得调用flush方法刷新文件写入的数据缓存区,否则会造成写入的信息不完全
2.如果要写入中文字串,需要我们把写入的“中文字符串”转成字节数组,并且规定“UTF-8”的字符集
3.可以在创建OutputStream对象中规定true(规定内容是追加写入的,不会情况文件内容)
写入的优化操作:
对于写入文件,我们还可以使用另一个类(使用输出流来创建对象)来写入--PrintStream。这个类来进行写入其实更加方便。优势是:可以连贯写入内容(不会清空文件),还能指定单行写入(换行)
代码示例:
File file=new File("d:/Java.IO/the.txt");
file.createNewFile();
//按照字节进行写操作
try (OutputStream outputStream=new FileOutputStream(file,true);
PrintStream printStream=new PrintStream(outputStream
)){
printStream.print("再见了,所有的man");
printStream.print("see you again");
printStream.flush();
}catch (IOException e){
e.printStackTrace();
}
字符流:
同样对于Reader和Writer类也是抽象类,我们要使用的话也是使用继承它的子类FileReader和FileWriter。字符流一般适用于文本文件的书写。
Reader概述:

同样,我们重点关注读取内容的方法,至于这些方法使用时的注意事项与InputStream类似,这里就不再赘述。
Writer概述:

写入的优化操作:
类似于OutStream,我们Writer也有一个更好的优化操作:PrintWriter
File file=new File("d:/Java.IO/ret.txt");
file.createNewFile();
//按字符进行写操作
try (OutputStream outputStream=new FileOutputStream(file,true)){
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.print("Man,What can I say?");
printWriter.print("manba out!!");
printWriter.print("牢大想你了!!!");
printWriter.flush();
}catch (IOException E){
E.printStackTrace();
}
代码示例:
public class demo13 {
//字符流的书写
public static void main(String[] args) throws IOException {
File file=new File("d:/Java.IO/main.txt");
try(Reader reader = new FileReader(file);
Writer writer = new FileWriter(file,true)) {
while(true){
//往文件写数据
writer.write("你好呀!");
char[] ch = new char[]{'哦','哦'};
writer.write(ch);
//读数据,一次最多读取4096个字符
char[] chars=new char[4096];
int a = reader.read(chars);
if(a==-1){
break;
}
for(int b=0;b<a;b++){
System.out.println(chars[b]);
}
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
总结的书写模板
按照字节进行读写:
代码案例:
public class demo15 {
public static void main(String[] args) throws IOException {
//按照字节读取的模板
File file=new File("d:/Java.IO/the.txt");
file.createNewFile();
//按照字节进行写操作
try (OutputStream outputStream=new FileOutputStream(file,true);
PrintStream printStream=new PrintStream(outputStream
)){
printStream.print("再见了,所有的man");
printStream.print("see you again");
printStream.flush();
}catch (IOException e){
e.printStackTrace();
}
//按照字节进行读操作
try (InputStream inputStream=new FileInputStream(file)){
byte[] a=new byte[1024];
while (true){
int n=inputStream.read(a);
if(n==-1){
break;
}
for (int i=0;i<n;i++){
System.out.printf("%x\n",a[i]);
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
按照字符进行读写:
代码示例:
public class demo14 {
public static void main(String[] args) throws IOException {
//这里是关于按照字符读写操作的规范模板
File file=new File("d:/Java.IO/ret.txt");
file.createNewFile();
//按字符进行写操作
try (OutputStream outputStream=new FileOutputStream(file,true)){
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.print("Man,What can I say?");
printWriter.print("manba out!!");
printWriter.print("牢大想你了!!!");
printWriter.flush();
}catch (IOException E){
E.printStackTrace();
}
//按字符进行读操作,可以处理中文的情况
try (InputStream inputStream=new FileInputStream(file);
Scanner scanner=new Scanner(inputStream,"UTF-8")){
while (scanner.hasNext()){
String s=scanner.next();
System.out.println(s);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
本篇算是一个IO方法的小总结,如有错误还望诸位谅解,也期望大家指出在下的不足。
更多推荐


所有评论(0)