Java IO 入门

这篇博客介绍了Java IO的基本概念,包括流的分类以及InputStream、OutputStream、Reader、Writer类的作用。详细讲解了如何使用Java IO读写文件,包括文件的复制、随机存取、以及逐行读取。此外,还涵盖了文件和目录信息的获取,以及如何递归列出目录内容。
摘要由CSDN通过智能技术生成


Java 的 IO 包主要关注的是从原始数据源的读取以及输出原始数据到目标媒介。以下是最典型的数据源和目标媒介:

  • 文件
  • 管道
  • 网络连接
  • 内存缓存
  • System.in, System.out, System.error(注:Java 标准输入、输出、错误输出)

1. 几个 IO 概念

1.1 流

在 Java IO 中,流是一个核心的概念:

  • 可以分为字节流 (以字节为单位进行读写)和字符流 (以字符为单位进行读写);
  • 也可以分为输入流(向内存输入)和输出流(为从内存输出)。
1.2 类 InputStream, OutputStream, Reader 和 Writer

一个程序需要 InputStream 或者 Reader 从数据源读取数据,需要 OutputStream 或者 Writer 将数据写入到目标媒介中。

不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符。但是在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。

  • InputStreamReader 实现从字节流解码成字符流;
  • OutputStreamWriter 实现字符流编码成为字节流。

Java IO 中包含了许多 InputStream、OutputStream、Reader、Writer 的子类,汇总如下:
在这里插入图片描述

2. Java IO:文件

2.1 通过 Java IO 读文件

如果你需要在不同端之间读取文件,你可以根据该文件是二进制文件还是文本文件来选择使用 FileInputStream 或者 FileReader。这两个类允许你从文件开始到文件末尾一次读取一个字节或者字符,或者将读取到的字节写入到字节数组或者字符数组。你不必一次性读取整个文件,相反你可以按顺序地读取文件中的字节和字符。

如果你需要跳跃式地读取文件其中的某些部分,可以使用 RandomAccessFile.

通常使用输入流中的 read()方法读取数据。read()方法返回一个整数,代表了读取到的字节的内容 (0 ~ 255)。当达到流末尾没有更多数据可以读取的时候,read() 方法返回 - 1。

字节流示例:

public static void readFile(String fileName) throws IOException {
        InputStream input = new FileInputStream(fileName);
        int data;
        while ((data = input.read()) != -1){
            logger.info("reading..." + data);
        }
        input.close();
    }

你可以将流整合起来以便实现更高级的输入和输出操作。比如,一次读取一个字节是很慢的,所以可以从磁盘中一次读取一大块数据,然后从读到的数据块中获取字节。为了实现缓冲,可以把 InputStream 包装到 BufferedInputStream 中。

BufferedInputStream input = new BufferedInputStream(new FileInputStream(fileName));

字符流示例:

Reader reader = new BufferedReader(new FileReader(fileName));
          while (reader.read() != -1) {
              logger.info("reading..." );
          }
          reader.close();
2.2 通过 Java IO 写文件

如果你需要在不同端之间进行文件的写入,你可以根据你要写入的数据是二进制型数据还是字符型数据选用 FileOutputStream 或者 FileWriter。你可以一次写入一个字节或者字符到文件中,也可以直接写入一个字节数组或者字符数组。数据按照写入的顺序存储在文件当中。

通常使用输出流中的 write 方法写入数据。

字节流示例:

 public static void writeFile(String fileName, byte[] content) throws IOException {
   OutputStream output = new BufferedOutputStream(new FileOutputStream(fileName));
    output.write(content);
    logger.info("writing..." + content.toString());
    output.flush();
    output.close();
    }

字符流示例:

Writer writer = new BufferedWriter(new FileWriter(fileName));
writer.write(content);
writer.flush();
writer.close();

文件内容的覆盖 Override VS 追加 Appending

当你创建了一个指向已存在文件的 FileOutputStream,你可以选择覆盖整个文件,或者在文件末尾追加内容。通过使用不同的构造函数可以实现不同的目的。

  • 其中一个构造函数取文件名作为参数,会覆盖任何此文件名指向的文件。

  • 另外一个构造函数取 2 个参数:文件名和一个布尔值,布尔值表明你是否追加文件。

OutputStream output = new BufferedOutputStream(new FileOutputStream(fileName,true));//不会覆盖文件
 
Writer writer = new BufferedWriter(new FileWriter(fileName,true));//不会覆盖文件

flush()

当你往 FileOutputStream 里写数据的时候,这些数据有可能会缓存在内存中。在之后的某个时间,比如,每次都只有 X 份数据可写,或者 FileOutputStream 关闭的时候,才会真正地写入磁盘。当 FileOutputStream 没被关闭,而你又想确保写入到 FileOutputStream 中的数据写入到磁盘中,可以调用 flush() 方法,该方法可以保证所有写入到 FileOutputStream 的数据全部写入到磁盘中。

close()

每次读/写文件结束之后,都应该调用流的 close() 方法,以节约资源

一般可以 finnally 块中显示关闭流,在 Java 7 之后,增强了try语句的功能,它允许在try关键字后紧跟一对圆括号,圆括号可以声明、初始化一个或多个资源(此处的资源是指那些必须在程序结束时显式关闭的资源,比如数据库连接,网络连接等),try-with-resources 是一个定义了一个或多个资源的try 声明,try语句在该语句结束时自动关闭这些资源。try-with-resources确保每一个资源在处理完成后都会被关闭。这些资源必须实现AutoCloseable或者Closeable接口,实现这两个接口就必须实现close() 方法。

 try ( Writer writer = new BufferedWriter(new FileWriter(fileName,false));){
            writer.write(content);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
2.3 通过 Java IO 随机存取文件

随机存取并不意味着你可以在真正随机的位置进行读写操作,它只是意味着你可以跳过文件中某些部分进行操作,并且支持同时读写,不要求特定的存取顺序。这使得 RandomAccessFile 可以覆盖一个文件的某些部分、或者追加内容到它的末尾、或者删除它的某些内容,当然它也可以从文件的任何位置开始读取文件。

创建一个 RandomAccessFile

String fileName = "test.txt";
RandomAccessFile file = new RandomAccessFile(fileName, "rw");

请注意构造函数的第二个参数:“rw”,表明你以读写方式打开文件。

在 RandomAccessFile 中来回读写

在 RandomAccessFile 的某个位置读写之前,必须把文件指针指向该位置。通过 seek() 方法可以达到这一目标。可以通过调用 getFilePointer() 获得当前文件指针的位置。

 RandomAccessFile file = new RandomAccessFile(fileName,"rw");
 ile.seek(2);
 long pointer = file.getFilePointer();
 System.out.println(pointer);
 file.close();
2.4 文件和目录信息的获取

有时候你可能需要读取文件的信息而不是文件的内容,举个例子,如果你需要知道文件的大小和文件的属性。对于目录来说也是一样的,比如你需要获取某个目录下的文件列表。通过 File 类可以获取文件和目录的信息。

Java IO API 中的 FIle 类可以让你访问底层文件系统,通过 File 类,你可以做到以下几点:

  • 创建文件对象
String fileName = "test.txt";
File file = new File(fileName);
  • 检测文件是否存在
	boolean fileExists = file.exists();
  • 读取文件长度
long length = file.length();
  • 重命名或移动文件
	boolean success = file.renameTo(new File("c:\\data\\new-file.txt"));
  • 删除文件
	boolean success = file.delete();
  • 检测某个路径是文件还是目录
boolean isDirectory = file.isDirectory();
boolean isFile = file.isFile();
  • 读取目录中的文件列表
String[] fileNames = file.list();
File[] files = file.listFiles();
2.5 递归地列出一个目录下的所有内容

File 类可以用于表示文件和目录的信息,但是它不表示文件的内容。

 public static void AllFiles(String dir) {
        File file = new File(dir);
        if (file == null || !file.exists())
            return;

        if (file.isFile()) {
            System.out.println(file.getName());
            return;
        }

        for (File f : file.listFiles()) {
            AllFiles(dir + "\\" + f.getName());
        }
    }

2.6 实现文件的复制
public static void copyFile(String src, String dest) {
        try (FileInputStream in = new FileInputStream(src);
             FileOutputStream out = new FileOutputStream(dest)
        ) {
            byte[] buffer = new byte[20 * 1024];
            int data;
            while ((data = in.read(buffer, 0, buffer.length)) != -1) {
                out.write(buffer, 0, data);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
2.7 逐行读取文件
 public static void readFile(String fileName){
        try ( BufferedReader bf = new BufferedReader(
                new FileReader(fileName))){
            String line;
            while((line = bf.readLine()) != null){
                System.out.println(line);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值