I/O流
I/O(输入/输出)流在我的理解中是在程序和内存之间传输数据。
通俗一点就是读文件,写文件的工具。
这其中有两大流派
一般来说都是成对出现,有输入就有输出
用完流以后,一定要关流
关闭流的原因:
1、释放资源,防止资源的浪费喝泄露
2、数据完整性,流一般基于缓冲区,数据在流中有可能会被缓存,如果不关闭流,缓冲区的数据可能不会被刷新到目标位置,如:FileWrite需要刷新才能将数据写入文件。
3、内存泄漏,流对象可能会占用一部分内存,如果不关闭,会一直存在于内存中,影响性能。
字节流
字节流中主要包括:
InputStream和OutputStream:字节流的抽象基类,用于处理字节数据
FileInputStream和FileOutputStream:通过字节读写文件。
BufferedInputStream和BufferedOutputStream:提供了缓冲区功能,提高了读写效率。
DataInputStream 和DataOutputStream用于处理基本数据类型的读写
ObjectInputStream 和ObjectOutputStream:序列化和反序列化,通俗的说就是可以把对象保存到文件中。
字符流
Reader和Writer:字符流的基类,用于处理字符数据
FileReader和FileWriter:通过字符读写文件
BufferedReader和BufferedWriter:提供了缓冲区以及读行,写换行的功能,提高了读写效率
InputStreamReader和OutputStreamWriter:用于转换编码
使用说明
在使用I/O流之前,先确定好需要处理的数据
如果是文本数据,要读写文件,处理字符串,那么使用字符流更合适
如果是非文本数据,比如音频,视频,那么就使用字节流。
再根据文件的大小来选择
如果文件比较大, 使用字节流,因为不用将文件转换为字符,会更高效
基本流
按照我的理解,要使用I/O流,
第一步是确定使用字符流还是字节流
第二步是先写基本流,因为一些高级流是需要接收基本流的
//字节输入基本流 FileInputStream fi = new FileInputStream("这里放路径,建议相对路径"); //字节输出基本流 FileOutStream fo = new FileOutStream("这里放路径,建议相对路径"); //字节输入基本流 FileRead fr = new FileRead("这里放路径,建议相对路径"); //字节输出基本流 FileWriter fw = new FileWriter("这里放路径,建议相对路径");
需要注意的是FileWriter
FileWriter
是把数据写进缓冲流里面,如果想要把缓冲流的内容写进文件中,需要flush();
fw.flush();
缓冲流
Buffered+任意:就是缓冲流
缓冲流算是高级流中一种
相较于基本流,缓冲流拥有了缓冲功能。
它会在内存中创建一个缓冲区来存储从底层基本流中读写的数据。相比之下,普通的基本流没有内置的缓冲区。缓冲功能可以提高读写数据的效率,特别是对于需要频繁读取小块数据的情况。
在我的理解中,缓冲流更像是一个加速器的作用,有缓冲流就可以提高效率,但是前提是你前期麻烦自己一下要打开这个加速器。
缓冲流可以接其他流,比如使用DataInputStream之前可以把FileInputStream放进BufferedInputStream里面进行增强,提高效率以后,再放到DataInputStream
try { FileInputStream fi = new FileInputStream("example.dat"); // 创建底层输入流 BufferedInputStream bis = new BufferedInputStream(fi); // 使用BufferedInputStream包装底层输入流 DataInputStream dis = new DataInputStream(bis); // 使用DataInputStream包装BufferedInputStream int intValue = dis.readInt(); // 读取整数数据 double doubleValue = dis.readDouble(); // 读取浮点数数据 System.out.println("Integer value: " + intValue); System.out.println("Double value: " + doubleValue); dis.close(); // 关闭流 } catch (IOException e) { e.printStackTrace(); }
转换流
InputStreamReader和OutStreamWriter
注意,这是字符流!!!
InputStreamReader提供了一种将字节流转换为字符流的方式,具体来说,它将从底层字节流读取的字节数据按照指定的字符编码转换为字符数据。它支持指定字符编码,以便正确处理不同的字符集和文本编码。
常用于读取文本文件中,需要从文本文件中读取字符数据,可以使用InputStreamReader。你可以创建一个FileInputStream来读取文件的字节数据,并将其传递给InputStreamReader来进行字节到字符的转换。
try { FileInputStream fis = new FileInputStream("file.txt"); InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); int c; while ((c = isr.read()) != -1) { char character = (char) c; // 处理字符数据 } isr.close(); } catch (IOException e) { e.printStackTrace(); }
又或者是处理网络输入流:当你需要从网络输入流中读取字符数据时,同样可以使用InputStreamReader。你可以使用Socket或URLConnection等类获取一个InputStream,然后使用InputStreamReader将其转换为字符流进行处理。
try { Socket socket = new Socket("127.0.0.1", 8888); InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "UTF-8"); int c; while ((c = isr.read()) != -1) { char character = (char) c; // 处理字符数据 } isr.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); }
OutputStreamWriter提供了一种将字符流转换为字节流的方式,具体来说,它将从底层字符流接收的字符数据按照指定的字符编码转换为字节数据。它支持指定字符编码,以便正确处理不同的字符集和文本编码。
常用于文本文件:当你需要将字符数据写入文本文件时,可以使用OutputStreamWriter。你可以创建一个FileOutputStream来写入文件的字节数据,并将其传递给OutputStreamWriter来进行字符到字节的转换。
try { FileOutputStream fos = new FileOutputStream("file.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); String text = "Hello, world!"; osw.write(text); osw.close(); } catch (IOException e) { e.printStackTrace(); }
数据流
DataInputStream和DataOutputStream
它们提供了一种方便的方式来读取和写入不同类型的数据,如整数、浮点数、布尔值等。
DataInputStream可以从输入流中读取二进制数据,并使用相应的方法将其转换为Java中的各种数据类型。
DataOutputStream可以将Java中的各种数据类型以二进制形式写入输出流。
这两个类通常一起使用,用于完成二进制数据的输入和输出操作。
常用于通信传输数据
public class Client { public static void main(String[] args) { try { // 连接到服务器 Socket socket = new Socket("127.0.0.1", 8080); // 获取输入流和输出流 DataOutputStream os = new DataOutputStream(socket.getOutputStream()); DataInputStream is = new DataInputStream(socket.getInputStream()); // 发送数据 os.writeInt(42); os.writeUTF("Hello, server!"); // 接收数据 int responseCode = is.readInt(); String responseMessage = is.readUTF(); System.out.println("Response code: " + responseCode); System.out.println("Response message: " + responseMessage); // 关闭连接 socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
序列化流
ObjectOutputStream和ObjectInputStream
序列化流可以将对象转换为字节流以便于存储或传输,以及将字节流转换回对象。
序列化是指将对象转换为字节流的过程,以便于存储或传输。通过将对象写入输出流,对象的状态(即实例变量的值)会被转换为字节序列。这样,可以将字节序列保存到文件中或通过网络发送给其他计算机。
public class SerializationExample { public static void main(String[] args) { // 创建对象 Student student = new Student("John Doe", 20, "Computer Science"); // 将对象序列化到文件 try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.txt"))) { oos.writeObject(student); } catch (IOException e) { e.printStackTrace(); } } }
反序列化是指将字节流转换回对象的过程。通过从输入流读取字节序列,可以重新创建出原始的对象,并恢复其状态。
public class DeserializationExample { public static void main(String[] args) { // 从文件中读取序列化的对象 try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.txt"))) { Student student = (Student) ois.readObject(); System.out.println(student); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
需要注意的是,要使对象能够进行序列化,该对象的类必须实现Serializable接口。该接口标识着类的实例可以被序列化,并提供了一种将其状态转换为字节流的方式。
总结一下:
1、I/O流按照我的理解来说就是对文件的内容进行操作
2、使用什么流需要看使用场景,如果要转换编码就用转换流,如果要保存对象,就用序列化流。
3、用完I/O流一定要关闭!