Java

Java 知识量:11 - 45 - 220

10.1 经典的Java I/O><

File类- 10.1.1 -

java.io.File 是 Java 中的一个类,用于表示文件或目录的路径名。这个类提供了许多有用的方法,可以用来操作文件和目录。以下是一些 File 类的主要方法和用法:

1、创建文件或目录

使用 createNewFile() 方法创建新文件,或使用 mkdir() 或 mkdirs() 方法创建新目录。

File file = new File("filename.txt");  
if (file.createNewFile()) {  
    System.out.println("文件创建成功");  
}  
  
File dir = new File("dirpath");  
if (dir.mkdir()) {  
    System.out.println("目录创建成功");  
}

2、判断文件或目录是否存在

使用 exists() 方法来检查文件或目录是否存在。

File file = new File("filename.txt");  
if (file.exists()) {  
    System.out.println("文件存在");  
}  
  
File dir = new File("dirpath");  
if (dir.exists()) {  
    System.out.println("目录存在");  
}

3、获取文件或目录的属性

使用 getName(), getParent(), getPath() 等方法获取文件或目录的属性。使用 lastModified() 和 length() 方法获取文件修改时间和大小。

File file = new File("filename.txt");  
System.out.println("文件名: " + file.getName());  
System.out.println("父路径: " + file.getParent());  
System.out.println("完整路径: " + file.getPath());  
System.out.println("修改时间: " + new Date(file.lastModified()));  
System.out.println("文件大小: " + file.length());

4、删除文件或目录

使用 delete() 方法删除文件或目录。如果要删除目录及其所有内容,可以使用 deleteOnExit() 方法。

File file = new File("filename.txt");  
if (file.delete()) {  
    System.out.println("文件删除成功");  
}  
  
File dir = new File("dirpath");  
dir.deleteOnExit(); // 当 JVM 退出时,删除目录及其所有内容

5、比较文件或目录

使用 equals() 方法比较两个文件或目录是否相等。

File file1 = new File("filename1.txt");  
File file2 = new File("filename2.txt");  
if (file1.equals(file2)) {  
    System.out.println("两个文件相等");  
}

6、获取文件或目录的路径

为了获取文件的绝对路径,可以使用 getAbsolutePath() 方法。对于目录,还可以使用 listFiles() 方法列出其下的所有文件和子目录。

综上所述,File类中有相当多的方法,但也存在许多问题。例如,没有直接提供一些基本功能(尤其是无法读取文件的内容)。

I/O流- 10.1.2 -

Java中的I/O流(输入/输出流)是用于在内存和外部设备(如文件、网络连接等)之间进行数据传输的抽象。Java提供了多种I/O流类,以便根据需要选择最合适的方法进行输入和输出。

Java的I/O流主要分为以下几类:

1、字节流(Byte Streams):字节流是以字节为单位进行读写的流。Java提供了以下两种类型的字节流:

  • FileInputStream 和 FileOutputStream:用于读写文件中的字节数据。

  • InputStream 和 OutputStream:用于读写字节数据,可以是文件、网络连接或其他数据源。

2、字符流(Character Streams):字符流是以字符为单位进行读写的流。Java提供了以下两种类型的字符流:

  • Reader 和 Writer:用于读写字符数据,可以是文件、网络连接或其他数据源。

  • InputStreamReader 和 OutputStreamWriter:用于将字节流转换为字符流,以便进行字符读写操作。

3、对象流(Object Streams):对象流用于将Java对象进行序列化和反序列化,以便在内存和外部设备之间传输。Java提供了以下两种对象流:

  • ObjectOutputStream 和 ObjectInputStream:用于将对象序列化成字节数据,并从字节数据中反序列化出对象。

4、转换流(Conversion Streams):转换流用于将不同类型的数据进行转换。例如,DataInputStream和DataOutputStream可以用于将基本数据类型(如int、double等)写入文件,并从文件中读取这些数据类型。

5、缓冲流(Buffered Streams):缓冲流可以提高I/O操作的效率。它们在内存中创建一个缓冲区,以便一次性读写多个数据,减少系统调用的次数,提高性能。Java提供了以下缓冲流:

  • BufferedInputStream 和 BufferedOutputStream:用于缓冲字节流。

  • BufferedReader 和 BufferedWriter:用于缓冲字符流。

6、数据流(Data Streams):数据流用于将Java的基本数据类型(如int、double等)和字符串写入到输出流,并从输入流中读取这些数据类型。Java提供了以下数据流:

  • DataOutputStream 和 DataInputStream:用于进行基本数据类型的读写操作。

7、Print 流:Print 流用于格式化输出到文本文件或其他数据源。Java提供了以下Print流:

  • PrintWriter 和 PrintStream:用于以格式化的方式打印数据到文件或其他数据源。

8、Scanner 流:Scanner 流用于从文本文件或其他数据源读取格式化的输入。Java提供了以下Scanner流:

  • Scanner:用于从文件或其他数据源读取格式化的输入。

9、ZIP 流:Java提供了一些ZIP流类,用于读取和写入ZIP压缩文件。例如,ZipInputStream和ZipOutputStream可以用于解压缩和压缩ZIP文件。

10、网络流(Network Streams):Java还提供了一些用于网络通信的流类,例如Socket和ServerSocket,可以用于在TCP协议下进行数据的发送和接收。

使用这些I/O流类时,一般遵循以下步骤:

  1. 创建流的实例,指定输入/出的源或目标。

  2. 使用流的 read() 或 write() 方法进行数据的读取或写入。

  3. 关闭流以释放系统资源。

注意:在使用I/O流时,通常需要进行异常处理,因为I/O操作可能会发生IOException。

标准输入和输出流- 10.1.3 -

标准输入流和标准输出流分别是System.in和System.out。

System.in是一个InputStream,它表示的是从控制台输入数据。可以使用Scanner类或者BufferedReader类从System.in读取数据。例如:

import java.util.Scanner;  
  
public class Main {  
    public static void main(String[] args) {  
        Scanner scanner = new Scanner(System.in);  
        System.out.print("请输入一个数字:");  
        int number = scanner.nextInt();  
        System.out.println("你输入的数字是:" + number);  
    }  
}

在上面的代码中,程序会等待用户在控制台输入一个数字,然后读取这个数字并打印出来。

System.out是一个OutputStream,它表示的是向控制台输出数据。可以使用PrintStream类或者BufferedWriter类向System.out写入数据。例如:

import java.io.PrintStream;  
  
public class Main {  
    public static void main(String[] args) {  
        PrintStream out = System.out;  
        out.println("Hello, World!");  
    }  
}

在上面的代码中,程序会向控制台输出"Hello, World!"。

注意:虽然System.in和System.out是Java的标准输入和输出流,但它们一般不直接用于与用户进行交互。在开发更复杂的程序时,可能会使用其他类(如JFrame或Swing库中的类)来处理用户输入并显示输出。

Reader和Writer类- 10.1.4 -

Reader和Writer是两个用于处理字符流的基类。它们都位于java.io包中,提供了一种方式来读取和写入字符数据,分别继承自CharStream和Writer类。

Reader类:Reader类是所有字符输入流的超类。它提供了读取字符流的基本方法,如read(), mark(), skip()等。以下是一些常见的Reader子类:

  • BufferedReader:可以从输入流中读取文本,提供字符缓冲,以改善读取性能或读取行操作。

  • CharArrayReader:从字符数组中读取字符数据。

  • StringReader:从字符串中读取字符数据。

  • InputStreamReader:将字节流转换为字符流,典型的用例是解码从InputStream读取的字节数据。

Writer类:Writer类是所有字符输出流的超类。它提供了写入字符流的基本方法,如write(), flush()等。以下是一些常见的Writer子类:

  • BufferedWriter:可以写入文本,提供字符缓冲,以改善写入性能或写入行操作。

  • CharArrayWriter:将字符写入到字符数组中。

  • StringWriter:将字符写入到字符串中。

  • OutputStreamWriter:将字符流转换为字节流,典型的用例是编码要写入到OutputStream的字符数据。

以下是一个简单的示例,展示如何使用Reader和Writer类来读取和写入数据:

import java.io.*;  
  
public class ReaderWriterExample {  
    public static void main(String[] args) {  
        try {  
            // 创建FileReader和FileWriter  
            FileReader fileReader = new FileReader("input.txt");  
            FileWriter fileWriter = new FileWriter("output.txt");  
  
            // 创建BufferedReader和BufferedWriter以提高效率  
            BufferedReader bufferedReader = new BufferedReader(fileReader);  
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);  
  
            // 读取并写入数据  
            String line;  
            while ((line = bufferedReader.readLine()) != null) {  
                bufferedWriter.write(line);  
                bufferedWriter.newLine(); // 换行  
            }  
  
            // 关闭流  
            bufferedReader.close();  
            bufferedWriter.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}

在这个示例中,程序从一个名为input.txt的文件中读取文本,并将其写入一个名为output.txt的新文件。为了提高效率,它使用了BufferedReader和BufferedWriter。注意:在使用文件流后一定要关闭它们以释放资源。

经典I/O存在的问题- 10.1.5 -

Java I/O(输入/输出)在经典实现中存在一些常见问题,主要包括以下几个方面:

  1. 阻塞性I/O:在Java经典I/O模型中,I/O操作通常是阻塞的。这意味着在数据未准备就绪的情况下,线程将等待直到数据可用。这会导致线程利用率低,尤其是在处理大量并发请求时。

  2. 单线程I/O:经典I/O模型通常使用单个线程来处理I/O操作。这意味着处理大量并发请求时,每个请求都需要在队列中等待,导致性能瓶颈。

  3. 不适用于高并发:由于阻塞和单线程的限制,Java经典I/O模型在高并发场景下性能表现不佳。在高并发环境中,需要更高的线程利用率和更高效的I/O处理机制。

  4. 内存限制:经典I/O模型在处理大量数据时可能遇到内存限制。这是因为所有数据都必须在内存中处理,这可能会导致内存溢出或降低了程序的性能。

  5. 错误处理:Java经典I/O模型在错误处理方面可能不够健壮。例如,当发生异常时,可能需要额外的代码来捕获和处理这些异常,以确保程序的稳定性。

  6. 无法利用现代硬件:现代硬件通常具有多核处理器和高速缓存,但经典I/O模型无法充分利用这些优势。这限制了I/O操作的性能和效率。

为了解决这些问题,Java提供了NIO(New I/O)库,也称为Java IO API的“新”版本,它支持非阻塞I/O、多线程和更高效的I/O操作。