Java基础——I/O流超详细讲解
引言
在Java编程中,I/O(Input/Output)流是非常重要的概念,它为程序与外部设备(如文件、网络等)之间的数据传输提供了一种机制。无论是读取文件内容、向文件写入数据,还是进行网络通信,都离不开I/O流的支持。本文将对Java的I/O流进行全面而深入的讲解。
一、I/O流的基本概念
1.1 流的定义
流是一种抽象的概念,它代表了数据的有序传输。就像水流一样,数据从一个源(如文件、网络连接)流向一个目标(如内存、另一个文件)。在Java中,流可以看作是一系列的数据序列,程序可以从流中读取数据(输入流),也可以向流中写入数据(输出流)。
1.2 流的分类
1.2.1 按流向分类
- 输入流:用于从数据源读取数据到程序中。例如,从文件中读取内容到内存。在Java中,所有输入流的基类是
InputStream(字节输入流)和Reader(字符输入流)。 - 输出流:用于将程序中的数据写入到目标设备。比如,将内存中的数据写入到文件。所有输出流的基类是
OutputStream(字节输出流)和Writer(字符输出流)。
1.2.2 按处理数据的单位分类
- 字节流:以字节为单位进行数据处理,适合处理二进制数据,如图片、音频、视频等。
InputStream和OutputStream是字节流的抽象基类。 - 字符流:以字符为单位进行数据处理,主要用于处理文本数据。
Reader和Writer是字符流的抽象基类。
1.2.3 按功能分类
- 节点流:直接与数据源或目标相连,用于实际的数据传输。例如,
FileInputStream和FileOutputStream用于直接操作文件。 - 处理流:也称为包装流,它是对节点流的进一步封装,提供了更高级的功能,如缓冲、加密等。例如,
BufferedInputStream和BufferedOutputStream提供了缓冲功能,提高了数据读写的效率。
二、字节流
2.1 字节输入流(InputStream)
InputStream是所有字节输入流的抽象基类,它定义了一系列用于读取字节数据的方法。常见的子类有FileInputStream、ByteArrayInputStream等。
2.1.1 FileInputStream示例
FileInputStream用于从文件中读取字节数据。以下是一个简单的示例,展示了如何使用FileInputStream读取文件内容:
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,read()方法用于读取一个字节的数据,返回值为读取的字节,如果到达文件末尾则返回 -1。使用try-with-resources语句可以确保流在使用完毕后自动关闭,避免资源泄漏。
2.2 字节输出流(OutputStream)
OutputStream是所有字节输出流的抽象基类,它定义了一系列用于写入字节数据的方法。常见的子类有FileOutputStream、ByteArrayOutputStream等。
2.2.1 FileOutputStream示例
FileOutputStream用于将字节数据写入到文件中。以下是一个简单的示例,展示了如何使用FileOutputStream写入数据到文件:
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamExample {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("test.txt")) {
String data = "Hello, World!";
byte[] bytes = data.getBytes();
fos.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,write(byte[] b)方法用于将字节数组写入到文件中。
三、字符流
3.1 字符输入流(Reader)
Reader是所有字符输入流的抽象基类,它定义了一系列用于读取字符数据的方法。常见的子类有FileReader、BufferedReader等。
3.1.1 FileReader示例
FileReader用于从文件中读取字符数据。以下是一个简单的示例,展示了如何使用FileReader读取文件内容:
import java.io.FileReader;
import java.io.IOException;
public class FileReaderExample {
public static void main(String[] args) {
try (FileReader fr = new FileReader("test.txt")) {
int data;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
与FileInputStream类似,read()方法用于读取一个字符的数据,返回值为读取的字符,如果到达文件末尾则返回 -1。
3.2 字符输出流(Writer)
Writer是所有字符输出流的抽象基类,它定义了一系列用于写入字符数据的方法。常见的子类有FileWriter、BufferedWriter等。
3.2.1 FileWriter示例
FileWriter用于将字符数据写入到文件中。以下是一个简单的示例,展示了如何使用FileWriter写入数据到文件:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterExample {
public static void main(String[] args) {
try (FileWriter fw = new FileWriter("test.txt")) {
String data = "Hello, World!";
fw.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,write(String str)方法用于将字符串写入到文件中。
四、处理流
4.1 缓冲流
缓冲流是一种常见的处理流,它通过在内存中设置缓冲区,减少了与外部设备的直接交互次数,从而提高了数据读写的效率。常见的缓冲流有BufferedInputStream、BufferedOutputStream、BufferedReader和BufferedWriter。
4.1.1 BufferedReader示例
BufferedReader用于高效地读取文本数据,它提供了readLine()方法,可以一次读取一行数据。以下是一个简单的示例:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,readLine()方法用于读取一行文本,返回值为读取的行内容,如果到达文件末尾则返回null。
4.2 转换流
转换流用于在字节流和字符流之间进行转换。常见的转换流有InputStreamReader和OutputStreamWriter。
4.2.1 InputStreamReader示例
InputStreamReader可以将字节输入流转换为字符输入流。以下是一个简单的示例:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(fis)) {
int data;
while ((data = isr.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,InputStreamReader将FileInputStream转换为字符输入流,从而可以按字符读取文件内容。
五、对象流
对象流用于实现对象的序列化和反序列化。序列化是将对象转换为字节流的过程,反序列化则是将字节流恢复为对象的过程。常见的对象流有ObjectInputStream和ObjectOutputStream。
5.1 序列化示例
要实现对象的序列化,对象的类必须实现Serializable接口。以下是一个简单的示例:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class ObjectOutputStreamExample {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
Person person = new Person("John", 30);
oos.writeObject(person);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,ObjectOutputStream将Person对象序列化并写入到文件person.ser中。
5.2 反序列化示例
以下是一个简单的反序列化示例:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("person.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
Person person = (Person) ois.readObject();
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在上述代码中,ObjectInputStream从文件person.ser中读取字节流,并将其反序列化为Person对象。
六、总结
Java的I/O流提供了丰富的类和方法,用于处理各种数据传输需求。通过合理选择字节流、字符流、处理流和对象流,可以高效地完成文件读写、网络通信等任务。在使用I/O流时,要注意资源的正确关闭,避免资源泄漏。同时,要根据具体的应用场景选择合适的流类型,以提高程序的性能和可维护性。希望本文对你理解Java的I/O流有所帮助。

1343

被折叠的 条评论
为什么被折叠?



