跳转至

Java 中的输入输出流

简介

在 Java 编程中,输入输出流(Input and Output Streams)是处理数据传输的关键机制。无论是从文件读取数据,还是将数据写入网络套接字,输入输出流都发挥着至关重要的作用。理解并熟练运用输入输出流是开发高效、可靠的 Java 应用程序的必备技能。本文将深入探讨 Java 输入输出流的基础概念、使用方法、常见实践以及最佳实践。

目录

  1. 基础概念
  2. 使用方法
    • 字节流
    • 字符流
  3. 常见实践
    • 文件读取与写入
    • 网络通信中的 I/O
  4. 最佳实践
    • 资源管理
    • 性能优化
  5. 小结
  6. 参考资料

基础概念

Java 的输入输出流基于流(Stream)的概念。流是一个有序的数据序列,用于在数据源和数据目的地之间传输数据。根据处理的数据类型,流可分为字节流(Byte Streams)和字符流(Character Streams)。 - 字节流:处理 8 位字节数据,主要用于处理二进制数据,如图片、音频等。字节流的基类是 InputStreamOutputStream。 - 字符流:处理 16 位 Unicode 字符数据,更适合处理文本数据。字符流的基类是 ReaderWriter

使用方法

字节流

  1. 读取字节数据 ```java import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream;

    public class ByteInputStreamExample { public static void main(String[] args) { try (InputStream inputStream = new FileInputStream("example.txt")) { int data; while ((data = inputStream.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } } } `` 在上述代码中,FileInputStream用于从文件读取字节数据。read()` 方法每次读取一个字节,返回值为读取的字节数据,如果到达文件末尾则返回 -1。

  2. 写入字节数据 ```java import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream;

    public class ByteOutputStreamExample { public static void main(String[] args) { String data = "Hello, World!"; try (OutputStream outputStream = new FileOutputStream("output.txt")) { byte[] bytes = data.getBytes(); outputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } } } `` 此代码使用FileOutputStream将字符串转换为字节数组后写入文件。write(byte[] b)` 方法将字节数组写入输出流。

字符流

  1. 读取字符数据 ```java import java.io.FileReader; import java.io.IOException; import java.io.Reader;

    public class CharacterReaderExample { public static void main(String[] args) { try (Reader reader = new FileReader("example.txt")) { int data; while ((data = reader.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } } } ``FileReader用于读取字符数据。read()` 方法每次读取一个字符,到达文件末尾时返回 -1。

  2. 写入字符数据 ```java import java.io.FileWriter; import java.io.IOException; import java.io.Writer;

    public class CharacterWriterExample { public static void main(String[] args) { String data = "你好,世界!"; try (Writer writer = new FileWriter("output.txt")) { writer.write(data); } catch (IOException e) { e.printStackTrace(); } } } ``FileWriter用于写入字符数据。write(String str)` 方法将字符串写入输出流。

常见实践

文件读取与写入

  1. 逐行读取文件 ```java import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException;

    public class ReadFileLineByLine { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } } ``BufferedReader提供了readLine()` 方法,用于逐行读取文件内容,这种方式在处理文本文件时非常实用。

  2. 追加内容到文件 ```java import java.io.FileWriter; import java.io.IOException;

    public class AppendToFile { public static void main(String[] args) { String newData = "\nThis is new line added to the file."; try (FileWriter writer = new FileWriter("example.txt", true)) { writer.write(newData); } catch (IOException e) { e.printStackTrace(); } } } `` 使用FileWriter的构造函数FileWriter(String fileName, boolean append),当appendtrue` 时,数据将追加到文件末尾。

网络通信中的 I/O

  1. 简单的客户端 - 服务器通信 服务器端 ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;

    public class Server { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(8080)) { System.out.println("Server started. Waiting for a client..."); Socket clientSocket = serverSocket.accept(); System.out.println("Client connected.");

            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
    
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("Received from client: " + inputLine);
                out.println("Server response: " + inputLine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    } **客户端**java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket;

    public class Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080)) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

            String userInput;
            while ((userInput = stdIn.readLine()) != null) {
                out.println(userInput);
                System.out.println("Server: " + in.readLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    } `` 在这个例子中,服务器和客户端通过套接字进行通信,使用BufferedReaderPrintWriter` 进行数据的读取和写入。

最佳实践

资源管理

  1. 使用 try-with-resources 语句try-with-resources 语句会自动关闭实现了 AutoCloseable 接口的资源,确保资源在使用后被正确释放,避免资源泄漏。例如: java try (InputStream inputStream = new FileInputStream("example.txt")) { // 处理输入流 } catch (IOException e) { e.printStackTrace(); }

性能优化

  1. 缓冲流的使用:使用缓冲流(如 BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter)可以减少 I/O 操作的次数,提高性能。例如: java try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("largeFile.txt"))) { // 处理缓冲输入流 } catch (IOException e) { e.printStackTrace(); }
  2. 字符编码处理:在处理字符流时,确保正确设置字符编码,以避免乱码问题。例如: java try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("file.txt"), "UTF-8"))) { // 处理读取 } catch (IOException e) { e.printStackTrace(); }

小结

Java 的输入输出流为数据的输入输出提供了丰富的类库和灵活的操作方式。通过理解字节流和字符流的区别,掌握它们的基本使用方法,并在实际应用中遵循最佳实践,开发人员可以高效地处理文件读写、网络通信等各种 I/O 操作,构建出稳定、可靠的 Java 应用程序。

参考资料