【文件操作与IO】Java中如何操作文件

目录

 Java 中操作文件

File 概述

属性

构造方法

方法

代码示例

文件内容的读写 —— 数据流

 InputStream 概述

FileInputStream 概述

利用 Scanner 进行字符读取

OutputStream 概述

利用 OutputStreamWriter 进行字符写入

利用 PrintWriter 找到我们熟悉的方法

代码参考

如何按字节进行数据读

如何按字节进行数据写

如何按字符进行数据读

如何按字符进行数据写


 Java 中操作文件


操作系统的一个重要功能就是对文件的管理,每个操作系统都有自己的一套系统API调用,Java作为一个跨平台的语言,JVM针对不同的操作系统做了一层封装,我们只需使用JDK提供的关于文件操作的API就可以完成不同的系统上的文件操作。

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不代表真实存在该文件

File 概述

属性

修饰符及类型 

属性

说明

static String

pathSeparator

依赖于系统的路径分隔符,String 类型的表示

static char

pathSeparator

依赖于系统的路径分隔符,char 类型的表示

构造方法

方法

修饰符及返回

值类型

方法签名

说明

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)

进行文件改名,也可以视为我们平时的剪切、粘贴操

boolean

canRead()

判断用户是否对文件有可读权限

boolean

canWrite()

判断用户是否对文件有可写权限

代码示例

示例1

观察 get 系列的特点和差异

import java.io.File;
import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("..\\hello-world.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());
   }
}

运行结果

..
hello-world.txt
..\hello-world.txt
D:\代码练习\文件示例1\..\hello-world.txt
D:\代码练习\hello-world.txt

示例2

普通文件的创建、删除

import java.io.File;
import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("hello-world.txt"); // 要求该文件不存在,才能看到相同的现象
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile());
   }
}

运行结果

false
false
false
true
true
false
true
false

示例3

观察 deleteOnExit 的现象

import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("some-file.txt"); // 要求该文件不存在,才能看到相同的现象
        System.out.println(file.exists());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());
        file.deleteOnExit();
        System.out.println(file.exists());
   }
}

运行结果

false
true
true
true

程序运行结束后,文件还是被删除了

示例4

观察目录创建

import java.io.File;
import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File dir = new File("some-parent\\some-dir"); // some-parent 和 somedir 都不存在
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        System.out.println(dir.mkdir());
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
   }
}

运行结果

false
false
false
false
false

mkdir() 的时候,如果中间目录不存在,则无法创建成功; mkdirs() 可以解决这个问题。

import java.io.File;
import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File dir = new File("some-parent\\some-dir"); // some-parent 和 somedir 都不存在
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        System.out.println(dir.mkdirs());
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
   }
}

运行结果

false
false
true
true
false

示例5

观察文件重命名

import java.io.File;
import java.io.IOException;
public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("some-file.txt"); // 要求 some-file.txt 得存在,可以是普通文件,可以是目录
        File dest = new File("dest.txt");   // 要求 dest.txt 不存在
        System.out.println(file.exists());
        System.out.println(dest.exists());
        System.out.println(file.renameTo(dest));
        System.out.println(file.exists());
        System.out.println(dest.exists());
   }
}

运行结果

true
false
true
false
true

文件内容的读写 —— 数据流


数据流分类

 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()
关闭字节流

说明

InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream

FileInputStream 概述

构造方法
签名
说明
FileInputStream(File file)
利用 File 构造文件输入流
FileInputStream(String name)
利用文件路径构造文件输入流

示例

这里我们把文件内容中填充中文看看,注意,写中文的时候使用 UTF-8 编码。hello.txt 中填写 "你好中国"

注意:这里我利用了这几个中文的 UTF-8 编码后长度刚好是 3 个字节和长度不超过 1024 字节的现状,但这种方式并不是通用的

import java.io.*;
// 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "你好中国" 的内容
public class Main {
    public static void main(String[] args) throws IOException {
        try (InputStream is = new FileInputStream("hello.txt")) {
            byte[] buf = new byte[1024];
            int len;
            while (true) {
                len = is.read(buf);
                if (len == -1) {
                    // 代表文件已经全部读完
                    break;
               }
                // 每次使用 3 字节进行 utf-8 解码,得到中文字符
                // 利用 String 中的构造方法完成
                // 这个方法了解下即可,不是通用的解决办法
                for (int i = 0; i < len; i += 3) {
                    String s = new String(buf, i, 3, "UTF-8");
                    System.out.printf("%s", s);
               }
           }
       }
   }
}

利用 Scanner 进行字符读取

上述例子中,我们看到了对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类。

构造方法
说明
Scanner(InputStream is, String charset)
使用 charset 字符集进行 is 的扫描读取
示例
import java.io.*;
import java.util.*;
// 需要先在项目目录下准备好一个 hello.txt 的文件,里面填充 "你好中国" 的内容
public class Main {
    public static void main(String[] args) throws IOException {
        try (InputStream is = new FileInputStream("hello.txt")) {
           try (Scanner scanner = new Scanner(is, "UTF-8")) {
               while (scanner.hasNext()) {
                   String s = scanner.next();
                   System.out.print(s);
               }
           }
       }
   }
}

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()
重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream
了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的
一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写
入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的
数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,
调用 flush (刷新)操作,将数据刷到设备中。

说明

OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream

利用 OutputStreamWriter 进行字符写入

import java.io.*;
public class Main {
    public static void main(String[] args) throws IOException {
        try (OutputStream os = new FileOutputStream("output.txt")) {
            String s = "你好中国";
            byte[] b = s.getBytes("utf-8");
            os.write(b);
            // 不要忘记 flush
            os.flush();
       }
   }
}

利用 PrintWriter 找到我们熟悉的方法

上述,我们其实已经完成输出工作,但总是有所不方便,我们接来下将 OutputStream 处理下,使用PrintWriter 类来完成输出,因为

PrintWriter 类中提供了我们熟悉的 print/println/printf 方法
import java.io.*;
public class Main {
    public static void main(String[] args) throws IOException {
        try (OutputStream os = new FileOutputStream("output.txt")) {
            try (OutputStreamWriter osWriter = new OutputStreamWriter(os, "UTF-8")) {
                try (PrintWriter writer = new PrintWriter(osWriter)) {
                    writer.println("我是第一行");
                    writer.print("我的第二行\r\n");
                    writer.printf("%d: 我的第三行\r\n", 1 + 1);
                    writer.flush();
               }
           }
       }
   }
}

代码参考


如何按字节进行数据读

try (InputStream is = ...) {
    byte[] buf = new byte[1024];
    while (true) {
        int n = is.read(buf);
        if (n == -1) {
            break;
       }
        // buf 的 [0, n) 表示读到的数据,按业务进行处理
   }
}

如何按字节进行数据写

try (OutputStream os = ...) {
    byte[] buf = new byte[1024];
    while (/* 还有未完成的业务数据 */) {
        // 将业务数据填入 buf 中,长度为 n
        int n = ...;
        os.write(buf, 0, n);
   }
    os.flush(); // 进行数据刷新操作
}

如何按字符进行数据读

try (InputStream is = ...) {
    try (Scanner scanner = new Scanner(is, "UTF-8")) {
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            // 根据 line 做业务处理
       }
   }
}

如何按字符进行数据写

try (OutputStream os = ...) {
    try (OutputStreamWriter osWriter = new OutputStreamWriter(os, "UTF-8")) {
        try (PrintWriter writer = new PrintWriter(osWriter)) {
            while (/* 还有未完成的业务数据 */) {
                writer.println(...);
           }
            writer.flush(); // 进行数据刷新操作
       }
   }
}

猜你喜欢

转载自blog.csdn.net/m0_59952648/article/details/131278030