目录
- 3.1.2. ByteArrayInputStream和ByteArrayOutputStream
- 3.1.3. BufferedInputStream和BufferedOutputStream
3.2字符流:Reader和Writer
- 3.2.1. FileReader和FileWriter:
- 3.2.2. InputStreamReader和OutputStreamWriter:
- 3.2.3. BufferedReader和BufferedWriter:
一、前言
Java IO是Java编程中非常重要的一部分,它提供了丰富的输入和输出功能,可以实现对文件、网络和其他设备的读取和写入操作。在开发中,Java IO广泛应用于文件处理、网络通信、序列化等场景。
Java IO主要涉及两个核心概念:输入流和输出流。输入流用于读取数据,输出流用于写入数据。它们支持字节流和字符流两种类型。字节流以字节为单位进行操作,适用于二进制文件或纯文本文件。字符流以字符为单位进行操作,适用于处理文本文件。
Java IO还提供了标准IO和NIO两种模式。传统的标准IO模式以流的方式进行操作,适用于较小的数据量和较低的并发处理需求。新IO(NIO)模式则基于通道和缓冲区进行操作,适用于高并发、高吞吐量的场景。
接下来,我们将详细介绍字节流和字符流的操作方法,并给出相应的代码示例。
二、Java IO 概述
输入和输出流
2.1.1 定义
输入流(InputStream)和输出流(OutputStream)是Java的I/O类库中的基本概念。输入流用于从外部源(例如文件、网络连接等)读取数据,而输出流用于将数据写入到外部目标(例如文件、网络连接等)。
输入流提供了一种逐个读取数据的方式,可以使用一些方法来读取不同类型的数据,如readByte、readChar、readInt等。输出流则提供了一些方法来写入不同类型的数据,如writeByte、writeChar、writeInt等。输入流和输出流可以用于处理各种不同的数据源和目标,例如文件、网络套接字、内存缓冲区等。
在应用中,输入流常用于读取文件内容、读取网络数据等场景,而输出流常用于将数据写入文件、将数据发送到网络等场景。
2.1.2 代码示例
下面是一个示例,演示如何使用输入流和输出流来读写文件:
import java.io.*; public class FileIOExample { public static void main(String[] args) { // 读取文件内容 try (InputStream inputStream = new FileInputStream("input.txt")) { int data = inputStream.read(); while (data != -1) { System.out.print((char) data); data = inputStream.read(); } } catch (IOException e) { e.printStackTrace(); } // 写入文件内容 try (OutputStream outputStream = new FileOutputStream("output.txt")) { String message = "Hello, World!"; outputStream.write(message.getBytes()); } catch (IOException e) { e.printStackTrace(); } } }
2.2 字节流和字符流
2.2.1 定义
字节流和字符流是Java I/O类库中的两种不同类型的流。
字节流(ByteStream)以字节为单位进行读取和写入操作,可以处理任意类型的数据。字节流类库包括InputStream和OutputStream。
字符流(CharacterStream)以字符为单位进行读取和写入操作,只能处理文本类型的数据。字符流类库包括Reader和Writer。
字节流和字符流之间的主要区别在于处理的数据类型不同。字节流可以读取和写入任意类型的数据,适用于处理二进制数据和非文本数据。而字符流则专门用于处理文本数据,可以自动进行字符编码和解码,方便读写文本文件。
在选择流类型时,需要考虑到处理的数据类型。如果处理的是文本数据,应选择字符流;如果处理的是二进制数据或非文本数据,应选择字节流。
2.2.2 代码示例
下面是一个示例,演示如何使用字符流来读写文本文件:
import java.io.*; public class FileIOExample { public static void main(String[] args) { // 读取文本文件内容 try (Reader reader = new FileReader("input.txt")) { int data = reader.read(); while (data != -1) { System.out.print((char) data); data = reader.read(); } } catch (IOException e) { e.printStackTrace(); } // 写入文本文件内容 try (Writer writer = new FileWriter("output.txt")) { String message = "Hello, World!"; writer.write(message); } catch (IOException e) { e.printStackTrace(); } } }
2.3 标准IO和NIO
传统的标准IO(IO是指输入输出)是一种同步阻塞的IO模型,它使用InputStream和OutputStream来进行数据的读取和写入操作。
标准IO的特点是对数据的读取和写入是以阻塞方式进行的,意味着在IO操作完成之前,当前线程会被阻塞,无法进行其他任务。这种模型在处理大量的并发连接时,性能较差。
NIO(New IO)是Java提供的一种新的IO模型,它使用通道(Channel)和缓冲区(Buffer)来进行数据的读取和写入操作。
下面将会介绍NIO、BIO和AIO的区别以及NIO使用通道(Channel)和缓冲区(Buffer)。
三、字节流和字符流
3.1. 字节流:InputStream和OutputStream
字节流是处理字节数据的输入输出流的抽象类。常用的字节流类有FileIn putStream、FileOutputStream、ByteArrayInputStream和ByteArrayOutputStream等。
3.1.1. FileInputStream和FileOutputStream
FileInputStream和FileOutputStream是用于读取和写入文件的字节流类。
以下是一个读取文件内容并打印的示例代码:
try (FileInputStream fis = new FileInputStream("example.txt")) { int data; while ((data = fis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
以下是一个写入文件内容的示例代码:
try (FileOutputStream fos = new FileOutputStream("example.txt")) { fos.write("Hello, World!".getBytes()); } catch (IOException e) { e.printStackTrace(); }
3.1.2. ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream和ByteArrayOutputStream是用于在内存中读取和写入字节数据的字节流类。
以下是一个从字节数组中读取数据并打印的示例代码:
byte[] data = {65, 66, 67, 68, 69}; try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) { int byteData; while ((byteData = bais.read()) != -1) { System.out.print((char) byteData); } } catch (IOException e) { e.printStackTrace(); }
以下是一个将数据写入字节数组并打印的示例代码:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { baos.write("Hello, World!".getBytes()); byte[] data = baos.toByteArray(); System.out.println(new String(data)); } catch (IOException e) { e.printStackTrace(); }
3.1.3. BufferedInputStream和BufferedOutputStream
BufferedInputStream和BufferedOutputStream是用于提升IO性能的装饰器类,它们通过在内部提供缓冲区来实现。
以下是一个使用BufferedInputStream读取文件的示例代码:
try (FileInputStream fis = new FileInputStream("example.txt"); BufferedInputStream bis = new BufferedInputStream(fis)) { int data; while ((data = bis.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); }
以下是一个使用BufferedOutputStream写入文件的示例代码:
try (FileOutputStream fos = new FileOutputStream("example.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos)) { bos.write("Hello, World!".getBytes()); } catch (IOException e) { e.printStackTrace(); }
以上是字节流的基本使用方法和示例代码。接下来,我们将介绍字符流的操作方法。
3.2字符流:Reader和Writer
3.2.1. FileReader和FileWriter:
FileReader是一个用于读取字符文件的类,而FileWriter是一个用于写入字符文件的类。下面是使用FileReader读取字符文件和使用FileWriter写入字符文件的代码示例:
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class FileExample { public static void main(String[] args) { // 使用FileReader读取字符文件 try (FileReader reader = new FileReader("input.txt")) { int data; while ((data = reader.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } // 使用FileWriter写入字符文件 try (FileWriter writer = new FileWriter("output.txt")) { writer.write("Hello, World!"); } catch (IOException e) { e.printStackTrace(); } } }
在上面的示例中,使用FileReader读取名为"input.txt"的字符文件,并将其内容打印到控制台上。接下来,使用FileWriter将字符串"Hello, World!"写入名为"output.txt"的字符文件。
3.2.2. InputStreamReader和OutputStreamWriter:
InputStreamReader是一个字符流和字节流之间的桥梁,它将字节流转换为字符流;而OutputStreamWriter是将字符流转换为字节流的类。
下面是使用InputStreamReader将字节流转换为字符流,并使用OutputStreamWriter将字符流转换为字节流的代码示例:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class StreamExample { public static void main(String[] args) { // 使用InputStreamReader将字节流转换为字符流 try (FileInputStream inputStream = new FileInputStream("input.txt"); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8")) { int data; while ((data = inputStreamReader.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } // 使用OutputStreamWriter将字符流转换为字节流 try (FileOutputStream outputStream = new FileOutputStream("output.txt"); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8")) { outputStreamWriter.write("Hello, World!"); } catch (IOException e) { e.printStackTrace(); } } }
在上面的示例中,使用InputStreamReader将名为"input.txt"的字节流转换为字符流,并将其内容打印到控制台上。
接下来,使用OutputStreamWriter将字符串"Hello, World!"转换为名为"output.txt"的字节流。
3.2.3. BufferedReader和BufferedWriter:
BufferedReader和BufferedWriter 是具有缓冲区功能的字符流,可以提高读取和写入字符数据的效率。
下面是使用BufferedReader读取字符文件和使用BufferedWriter写入字符文件的代码示例:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class BufferExample { public static void main(String[] args) { // 使用BufferedReader读取字符文件 try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } // 使用BufferedWriter写入字符文件 try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) { writer.write("Hello, World!"); } catch (IOException e) { e.printStackTrace(); } } }
在上面的示例中,使用BufferedReader逐行读取名为"input.txt"的字符文件,并将每行内容打印到控制台上。
通过使用BufferedReader和BufferedWriter,可以减少对磁盘的读写次数,从而提高读取和写入字符数据的效率。
四、文件操作
4.1. 文件创建、读取和写入
文件的创建、读取和写入是文件操作中的基本操作。下面是一些常见的文件操作代码示例:
- 创建文件:
file = open("filename.txt", "w") # 打开文件,并指定写入模式 file.close() # 关闭文件
- 写入文件:
file = open("filename.txt", "w") # 打开文件,并指定写入模式 file.write("Hello, World!") # 写入内容 file.close() # 关闭文件
读取文件:
file = open("filename.txt", "r") # 打开文件,并指定读取模式 content = file.read() # 读取文件内容 print(content) # 打印文件内容 file.close() # 关闭文件
4.2. 文件复制和移动
文件复制和移动是常见的文件操作需求。可以使用shutil模块中的函数来执行文件复制和移动。
- 文件复制:
import shutil src_file = "path/to/original_file.txt" dst_file = "path/to/new_file.txt" shutil.copy(src_file, dst_file) # 复制文件
- 文件移动:
import shutil src_file = "path/to/original_file.txt" dst_dir = "path/to/destination_directory/" shutil.move(src_file, dst_dir) # 移动文件
4.3. 文件删除和重命名
文件删除和重命名也是常见的文件操作需求。
- 文件删除:
import os file = "path/to/file.txt" os.remove(file) # 删除文件
文件重命名
import os src_file = "path/to/original_file.txt" dst_file = "path/to/new_file.txt" os.rename(src_file, dst_file) # 重命名文件
4.4. 文件属性和权限
文件属性和权限信息可以使用os模块的函数来获取和设置。
- 获取文件信息:
import os file = "path/to/file.txt" file_info = os.stat(file) # 获取文件信息 print(file_info.st_size) # 打印文件大小 print(file_info.st_mtime) # 打印文件修改时间
设置文件权限:
import os file = "path/to/file.txt" os.chmod(file, 0o777) # 设置文件权限为 777
请注意,这些代码示例仅作为基本的文件操作示例,需要根据具体的应用程序和操作系统做适当的调整。
五、网络通信
5.1. Socket编程基础
Socket编程是一种在计算机网络中进行通信的基本方式。它允许不同的计算机之间通过网络进行数据传输。
Socket编程的基本概念:
服务器端和客户端:在Socket编程中,通信的一方被称为服务器端,而另一方被称为客户端。服务器端通常绑定到一个特定的IP地址和端口,并在该端口上监听客户端的请求。
IP地址和端口:IP地址是网络中唯一标识一个主机的地址,端口是用于标识一个进程的数字。
套接字(Socket):套接字是通信的端点,它在客户端和服务器端之间建立连接,并通过连接进行数据传输。
以下是一个简单的Socket编程示例,展示了服务器端和客户端的基本代码:
5.2. 服务器端示例代码
import java.io.File; import java.io.FileWriter; import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; import java.io.FileNotFoundException; public class FileOperations { public static void main(String[] args) { createFile(); writeFile(); readFile(); copyFile(); moveFile(); deleteFile(); renameFile(); } public static void createFile() { try { File file = new File("filename.txt"); if (file.createNewFile()) { System.out.println("File created: " + file.getName()); } else { System.out.println("File already exists."); } } catch (IOException e) { System.out.println("An error occurred."); e.printStackTrace(); } } public static void writeFile() { try { FileWriter writer = new FileWriter("filename.txt"); writer.write("Hello, World!"); writer.close(); System.out.println("Successfully wrote to the file."); } catch (IOException e) { System.out.println("An error occurred."); e.printStackTrace(); } } public static void readFile() { try { BufferedReader reader = new BufferedReader(new FileReader("filename.txt")); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); } catch (FileNotFoundException e) { System.out.println("File not found."); e.printStackTrace(); } catch (IOException e) { System.out.println("An error occurred."); e.printStackTrace(); } } public static void copyFile() { File srcFile = new File("path/to/original_file.txt"); File destFile = new File("path/to/new_file.txt"); try { Files.copy(srcFile.toPath(), destFile.toPath()); System.out.println("File copied successfully."); } catch (IOException e) { System.out.println("An error occurred."); e.printStackTrace(); } } public static void moveFile() { File srcFile = new File("path/to/original_file.txt"); File destDir = new File("path/to/destination_directory/"); try { Files.move(srcFile.toPath(), destDir.toPath().resolve(srcFile.getName())); System.out.println("File moved successfully."); } catch (IOException e) { System.out.println("An error occurred."); e.printStackTrace(); } } public static void deleteFile() { File file = new File("path/to/file.txt"); if (file.delete()) { System.out.println("File deleted: " + file.getName()); } else { System.out.println("Failed to delete the file."); } } public static void renameFile() { File srcFile = new File("path/to/original_file.txt"); File destFile = new File("path/to/new_file.txt"); if (srcFile.renameTo(destFile)) { System.out.println("File renamed successfully."); } else { System.out.println("Failed to rename the file."); } } }
5.3. 客户端示例代码
import java.io.*; import java.net.*; public class Client { public static void main(String[] args) { try { // 创建客户端套接字 Socket clientSocket = new Socket("localhost", 8888); // 服务器的IP地址和端口号 // 发送数据给服务器 String message = "Hello, server!"; OutputStream outputStream = clientSocket.getOutputStream(); outputStream.write(message.getBytes()); // 接收服务器发送的数据 InputStream inputStream = clientSocket.getInputStream(); byte[] buffer = new byte[1024]; int length = inputStream.read(buffer); String data = new String(buffer, 0, length); System.out.println("收到服务器消息:" + data); // 关闭连接 clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
请注意,这些代码示例仅作为基本的Socket编程示例,并可能需要根据具体的应用程序和网络环境做适当的调整。