本文将从理论+代码的方式由浅入深的带大家学习IO流,通过图解的方式来记忆常用的IO流。
文末有IO总结的思维导图,很多博文采用的都是上来一张图,我觉得对于阅读者来说很容易陷进去,所以建议理清各个流后再去看思维导图。
在正式的介绍IO流之前,我觉得应该介绍一下File类,该类主要是对文件和目录的抽象表示,因为学习io流第一反应就是文件,该类提供了对文件的创建、删除、查找等操作。主要有以下特点
构造方法 | 方法说明 |
---|---|
File(String pathname) | 将路径字符串抽象为File实例,路径字符串可以是相对路径,也可以为绝对路径 |
File(String parent, String child) | 从父路径名和子路径名来构建File实例 |
File(File parent, String child) | 根据父File实例和子路径名来构建File实例 |
如下示例,表示这几种文件和目录的代码
// pathname
File liuBei = new File("D:/三国/刘备.jpg");
// String parent, String child
File guanYu = new File("D:/三国", "关羽.jpg");
// 目录
File sanGuo = new File("D:/三国");
// File parent, String child
File zhangFei = new File(sanGuo, "张飞.txt");
// 可以声明不存在的文件
File zhuGeLiang = new File(sanGuo, "诸葛亮.txt");
绝对路径:从盘符开始的路径,表示一个完整的路径。(经常使用) 相对路径:相对于当前项目目录的路径
File f = new File("D:/bbb.java");
// D:\bbb.java
System.out.println(f.getAbsolutePath());
File f2 = new File("bbb.java");
// F:\code\ad\bbb.java
System.out.println(f2.getAbsolutePath());
路径分隔符
java有常量separator表示路径分隔符
public static final String separator = "" + separatorChar;
换行符
方法名 | 方法说明 |
---|---|
boolean createNewFile() throws IOException | 当该名称的文件不存在时,创建一个由该抽象路径名的空文件并返回true,当文件存在时,返回false |
boolean mkdir() | 创建由此抽象路径名命名的目录 |
boolean mkdirs() | 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。级联创建目录 |
boolean delete() | 删除由此抽象路径名表示的文件或目录 |
’上述方法比较简单,其中需要注意的是
File shuiHu = new File("D:/四大名著/水浒传");
// 返回false 创建失败
boolean mkdir = shuiHu.mkdir();
// 返回true 创建失败
boolean mkdirs = shuiHu.mkdirs();
File four = new File("D:/四大名著");
// 返回false 删除目录时必须目录为空才能删除成功
boolean delete = four.delete();
File shuiHu = new File("D:/四大名著/水浒传");
// true 正确删除了水浒传目录
boolean delete1 = shuiHu.delete();
File liuBei = new File("D:/三国/刘备.jpg");
// 返回true 正确删除了刘备.jpg文件
boolean delete2 = liuBei.delete();
方法名 | 方法说明 |
---|---|
boolean isDirectory() | 判断是否是目录 |
boolean isFile() | 判断是否是文 |
boolean exists() | 判断文件或目录是否存在 |
boolean canWrite() | 文件是否可写 |
boolean canRead() | 文件是否可读 |
boolean canExecute() | 文件是否可执行 |
long lastModified | 返回文件的上次修改时间 |
注意的是
File xiYou = new File("D:/西游记");
// 文件或目录不存在时 返回false
System.out.println(xiYou.isDirectory());
方法名 | 方法说明 |
---|---|
String getAbsolutePath() | 返回File对象的绝对路径字符串 |
String getPath() | 将此抽象路径名转换为路径名字符串 |
String getName() | 返回文件或目录的名称 |
long length() | 返回由此File表示的文件的字节数 |
String[] list() | 返回目录中的文件和目录的名称字符串数组 |
File[] listFiles() | 返回目录中的文件和目录的File对象数 |
注意
File shuiHu = new File("D:/水浒传");
// 0
System.out.println(shuiHu.length());
File liuBei = new File("D:/三国/刘备.jpg");
// 24591
System.out.println(liuBei.length());
File f = new File("D:/bbb.java");
// D:\bbb.java
System.out.println(f.getPath());
File f2 = new File("bbb.java");
// bbb.java
System.out.println(f2.getPath());
File sanGuo2 = new File("D:/三国2");
// 该目录不存在,返回null
String[] list = sanGuo2.list();
过滤文件的接口
@FunctionalInterface
public interface FilenameFilter {
// 参数为目录和指定过滤名称
boolean accept(File dir, String name);
}
扩展(由读者自己实现)
读取目录下所有的文件以及目录,包括子目录下所有的文件及目录
上一章节学习了使用File类创建、查找、删除文件,但是无法读取、传输文件中的内容。
IO流主要是读取、传输、写入数据内容的。
I: input,O:output
这里的主体说的都是程序(即内存),从外部设备中读取数据到程序中 即为输入流,从程序中写出到外部程序中即为输出流
IO的分类
本地IO和网络IO
本地IO主要是操作本地文件,例如在windows上复制粘贴操作文件,都可以使用java的io来操作
网络IO主要是通过网络发送数据,或者通过网络上传、下载文件,我们每天上网无时无刻不在体验着IO的传输
按流向分,输入流和输出流
按数据类型分:字节流和字符流
按功能分:节点流和处理流
程序直接操作目标设备的类称为节点流
对节点流进行装饰,功能、性能进行增强,称为处理流
IO流主要的入口是数据源,下面列举常见的源设备和目的设备
源设备
目的设备
本文先探讨本地IO的字节流和字符流,先列举字节流和字符流的公共方法
方法名 | 方法说明 |
---|---|
void close() throws IOException | 流操作完毕后,必须释放系统资源,调用close方法,一般放在finally块中保证一定被执行! |
注意:
一切皆为字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制的形式保存,都可以通过使用字节流传输。
InputStream是字节输入流的顶层抽象
// Closeable有close()方法
public abstract class InputStream implements Closeable {}
核心方法如下
方法名 | 方法说明 |
---|---|
int read() throws IOException; | 每次读取一个字节的数据,提升为int类型,读取到文件末尾时返回 -1 |
int read(byte b[])throws IOException | 每次读取到字节数组中,返回读取到的有效字节个数,读取到末尾时返回 -1(常用) |
int read(byte b[], int off, int len) | 每次读取到字节数组中,从偏移量off开始,长度为len,返回读取到的有效字节个数,读取到末尾时返回 -1 |
OutputStream是字节输出流的顶层抽象
// Flushable里面有flush()方法
public abstract class OutputStream implements Closeable, Flushable {}
核心方法如下
方法名 | 方法说明 |
---|---|
void write(int b) throws IOException; | 将int值写入到输出流中 |
void write(byte[] b) throws IOException; | 将字节数组写入到输出流 |
void write(byte b[], int off, int len) throws IOException | 将字节数组从偏移量off开始,写入len个长度到输出流中 |
void flush() throws IOException | 刷新输出流并强制缓冲的字节被写出 |
InputStream有很多的实现类,先介绍下文件节点流,即目标设备是文件,输入流和输出流对应的是
FileInputStream和FileOutputStream
FileInputStream主要从磁盘文件中读取数据,常用构造方法如下
public FileInputStream(File file) throws FileNotFoundException{}
public FileInputStream(String name) throws FileNotFoundException{};
当传入的文件不存在时,运行时会抛出FileNotFoundException异常
File file = new File("D:/三国/诸葛亮.txt");
FileInputStream fileInputStream = new FileInputStream(file);
// 核心代码
int b;
while ((b = fileInputStream.read()) != -1 ){
System.out.print((char) b);
}
// 输出结果
abcde
2 . read(byte[])读取
File file = new File("D:/三国/诸葛亮.txt");
FileInputStream fileInputStream = new FileInputStream(file);
// 核心代码
byte[] data = new byte[2];
while (fileInputStream.read(data) != -1) {
System.out.println(new String(data));
}
// 输出结果
ab
cd
ed
上述代码由于最后一次读取时,只读取一个字节 e ,数组中还是上次的数据cd,只替换了e,所以最后输出了ed
下面是使用FileInputStream读取的正确姿势
File file = new File("D:/三国/诸葛亮.txt");
FileInputStream fileInputStream = new FileInputStream(file);
// 核心代码
byte[] data = new byte[2];
int len;
while ((len = fileInputStream.read(data)) != -1) {
// len 为每次读取的有效的字节个数
System.out.println(new String(data, 0, len));
}
// 输出结果
ab
cd
e
注意:使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了效率,建议使用
源码解析
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
private native int readBytes(byte b[], int off, int len) throws IOException;
上面列了read()和read(byte[])的源码,可见都是调用native的方法,涉及底层的系统调用。
FileOutputStream主要是向磁盘文件中写出数据,常用构造方法如下
构造方法名 | 方法说明 |
---|---|
FileOutputStream(File file) throws FileNotFoundException | 使用一个File对象来构建一个FileOutputStream |
FileInputStream(String name) throws FileNotFoundException | 使用一个文件名来构建一个FileOutputStream |
FileOutputStream(File file, boolean append) throws FileNotFoundException | append传true时,会对文件进行追加 |
FileOutputStream(String name, boolean append) throws FileNotFoundException | append传true时,会对文件进行追加 |
注意:
File file = new File("D:/三国/赵云.txt");
FileOutputStream fos = new FileOutputStream(file);
FileOutputStream fos1 = new FileOutputStream("D:/三国/司马懿.txt");
// 上述代码中执行完后,赵云.txt和司马懿.txt都会自动创建出来
向文件写数据
FileOutputStream fos = new FileOutputStream("D:/三国/司马懿.txt");
fos.write(96);
fos.write(97);
fos.write(98);
// 文件内容为 abc
FileOutputStream fos = new FileOutputStream("D:/三国/赵云.txt");
fos.write("三国赵云".getBytes());
// 文件内容为 三国赵云
上述代码每执行一次,文件里的内容就会被覆盖,有时候这不是我们想要的场景,我们一般是想追加文件
FileOutputStream fos = new FileOutputStream("D:/三国/赵云.txt", true);
fos.write("有万夫不当之勇".getBytes());
fos.close();
// 文件内容为 三国赵云有万夫不当之勇
应用场景
开发中涉及文件的上传、下载、传输都是用的这个节点流,会结合装饰后的处理流一起使用,在缓冲流部分有介绍。
扩展(由读者自己实现)
利用文件节点流实现文件的复制
ByteArrayInputStream是从内存的字节数组中读取数据
public ByteArrayInputStream(byte buf[]) {}
注意:不需要close数据源和抛出IOException,因为不涉及底层的系统调用
ByteArrayOutputStream是向内存字节数组中写数据,内部维护了一个数组
public ByteArrayOutputStream() {
// 内部维护了一个可变的字节数组
// protected byte buf[];
this(32);
}
内存节点流代码示例
ByteArrayInputStream bis = new ByteArrayInputStream("data".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
while ((len = bis.read()) != -1){
bos.write(len);
}
// 输出data
System.out.println(new String(bos.toByteArray()));
应用场景
字符流封装了更加适合操作文本字符的方法
Reader用于读取文本字符
public abstract class Reader implements Readable, Closeable {}
核心方法
方法名 | 方法说明 |
---|---|
int read() throws IOException | 从输入流中读取一个字符,读到文件末尾时返回-1 |
int read(char cbuf[]) throws IOException | 从输入流中读取字符到char数组中 |
Writer用于写出文本字符
public abstract class Writer implements Appendable, Closeable, Flushable {}
核心方法
方法名 | 方法说明 |
---|---|
void write(int c) throws IOException | 写入单个字符到输出流 |
void write(char[] cbuf) throws IOException | 写入字符数组到输出流中 |
void write(char[] cbuf, int off, int len) throws IOException | 写入字符数组的一部分,偏移量off开始,长度为len到输出流中 |
void write(String str) throws IOException | 直接写入字符串到输出流中(常用) |
void write(String str, int off, int len) throws IOException | 写入字符串的一部分,偏移量off开始,长度为len |
Writer append(char c) throws IOException | 追加字符到输出流中 |
字符流操作纯文本字符的文件是最合适的,主要有FileReader和FileWriter
FileReader主要是向磁盘文件中写出数据,常用构造方法如下
public FileReader(String fileName) throws FileNotFoundException{}
public FileReader(File file) throws FileNotFoundException {}
注意:当读取的文件不存在时,会抛出FileNotFoundException,这点和FileInputStream一致
FileReader fileReader = new FileReader("D:/三国/赵云.txt");
int b;
while ((b = fileReader.read()) != -1) {
System.out.println((char) b);
}
2 . read(char[]) 读取文件
FileReader fileReader = new FileReader("D:/三国/赵云.txt");
int len;
char[] data = new char[2];
while ((len = fileReader.read(data)) != -1) {
System.out.println(new String(data, 0, len));
}
// 两个字符两个字符依次读取
FileWriter构造方法如下,和FileOutStream构造方法类似,和FileOutputStream类似。
public FileWriter(String fileName) throws IOException {}
public FileWriter(String fileName, boolean append) throws IOException {}
public FileWriter(File file) throws IOException{}
public FileWriter(File file, boolean append) throws IOException {}
常用的写数据进文件的方法
FileWriter fileWriter = new FileWriter("D:/三国/孙权.txt");
fileWriter.write(97);
fileWriter.write('b');
fileWriter.write('C');
fileWriter.write("权");
fileWriter.append("力");
注意:
应用场景
纯文本文件的io操作,配合处理流一起实现。
字符流也有对应的内存节点流,常用的有StringWriter和CharArrayWriter
StringWriter是向内部的StringBuffer对象写数据。
// 定义
public class StringWriter extends Writer {
private StringBuffer buf;
public StringWriter() {
buf = new StringBuffer();
lock = buf;
}
}
// 应用
StringWriter sw = new StringWriter();
sw.write("hello");
StringBuffer buffer = sw.getBuffer();
// 输出hello
System.out.println(buffer.toString());
CharArrayWriter是向内部的char数组写数据
// 定义
public class CharArrayWriter extends Writer {
protected char buf[];
}
// 应用
CharArrayWriter caw = new CharArrayWriter();
caw.write("hello");
char[] chars = caw.toCharArray();
for (char c : chars) {
// 输出了h e l l o
System.out.println(c);
}
四种常用节点流的使用总结
注意到,OutputStream、Reader、Writer都实现了Flushable接口,Flushable接口有flush()方法
flush():强制刷新缓冲区的数据到目的地,刷新后流对象还可以继续使用
close(): 强制刷新缓冲区后关闭资源,关闭后流对象不可以继续使用
缓冲区:可以理解为内存区域,程序频繁操作资源(如文件)时,性能较低,因为读写内存较快,利用内存缓冲一部分数据,不要频繁的访问系统资源,是提高效率的一种方式
具体的流只要内部有维护了缓冲区,必须要close()或者flush(),不然不会真正的输出到文件中
上面的章节介绍了字节流和字符流的常用节点流,但是真正开发中都是使用更为强大的处理流
处理流是对节点流在功能上、性能上的增强
字节流的处理流的基类是FilterInputStream和FilterOutputStream
前面说了节点流,都是直接使用操作系统底层方法读取硬盘中的数据,缓冲流是处理流的一种实现,增强了节点流的性能,为了提高效率,缓冲流类在初始化对象的时候,内部有一个缓冲数组,一次性从底层流中读取数据到数组中,程序中执行read()或者read(byte[])的时候,就直接从内存数组中读取数据。
分类
字节缓冲流:BufferedInputStream , BufferedOutputStream
字符缓冲流:BufferedReader , BufferedWriter
可见构造方法传入的是节点流,是对节点流的装饰
// 内部默认8192 =8*1024 即8M的缓冲区
public BufferedInputStream(InputStream in) {
// 8192
// 内部维护了下面这样的字节数组
// protected volatile byte buf[];
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
这里使用复制一部1G的电影来感受缓冲流的强大
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:/三国/视频.mp4");
FileOutputStream fos = new FileOutputStream("D:/三国/拷贝.mp4");
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 五分钟还没拷好,关闭程序了...
2 . 使用基本的流读取数据(一次传输一个8M的字节数组)
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:/三国/视频.mp4");
FileOutputStream fos = new FileOutputStream("D:/三国/拷贝.mp4");
int len;
byte[] data = new byte[1024 * 1024 * 1024];
while ((len = fis.read(data)) != -1) {
fos.write(data, 0, len);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 拷贝电影耗时:4651ms
3 . 使用缓冲流读取数据(一次传输一个字节)
long start = System.currentTimeMillis();
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("D:/三国/视频.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("D:/三国/拷贝.mp4"));
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 拷贝电影耗时:39033ms
4 . 使用缓冲流读取数据(一次传输一个8M的字节数组)(最常使用)
long start = System.currentTimeMillis();
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("D:/三国/视频.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("D:/三国/拷贝.mp4"));
int len;
byte[] data = new byte[8 * 1024];
while ((len = fis.read(data)) != -1) {
fos.write(data, 0, len);
}
log.info("拷贝电影耗时:{}ms", System.currentTimeMillis() - start);
// 拷贝电影耗时:1946ms
由上述四个例子可以得出结论,缓冲流读取数据比普通流读取数据快很多!
注意:采用边读边写的方式,一次传输几兆的数据效率比较高,如果采用先把文件的数据都读入内存,在进行写出,这样读写的次数是较小,但是占用太大的内存空间,一次读太大的数据也严重影响效率!
对字符节点流的装饰,下面是字符缓冲流的构造方法
public BufferedReader(Reader in) {
// private static int defaultCharBufferSize = 8192;
// 内部维护了一个字符数组
// private char cb[];
this(in, defaultCharBufferSize);
}
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize);
}
字符缓冲流的特有方法
类 | 方法名 | 方法说明 |
---|---|---|
BufferedReader | String readLine() throws IOException | 一行行读取,读取到最后一行返回null |
BufferedWriter | void newLine() throws IOException | 写一个换行符到文件中,实现换行 |
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("D:/三国/赵云.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/三国/赵子龙.txt"));
String line = null;
while ((line = br.readLine())!=null) {
System.out.println(line);
bw.write(line);
bw.newLine();
}
// 结果
我乃常山赵子龙
于万军从中,取上将首级
缓冲流是IO流中最重要的知识点,下面通过代码实现正确用IO流的姿势
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(new File("D:/三国/视频.mp4")));
bos = new BufferedOutputStream(new FileOutputStream(new File("D:/三国/拷贝.mp4")));
int len;
// 一次传输8M的文件,实际测试这里传输的大小并不影响传输的速度
byte[] data = new byte[8 * 1024];
while ((len = bis.read(data)) != -1) {
bos.write(data, 0, len);
}
} catch (IOException e) {
log.error("error", e);
} finally {
// finally块中关闭流,确保资源一定被关闭
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
log.error("error", e);
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
log.error("error", e);
}
}
}
字符编码
计算机存储的数据都是二进制的,而我们在电脑上看到的数字、英文、汉字等都是二进制转换的结果
将字符转换成二进制,为编码
将二进制转换为字符,为解码
字符编码 就是 自然语言和二进制的对应规则
字符集
就是一个编码表,常见的字符集有ASCII字符集、GBK字符集、Unicode字符集等,具体各个编码的介绍在这里就不介绍了。
IDEA中,使用 FileReader 读取项目中的文本文件。IDEA可以设置为GBK 编码,当读取Windows系统中创建的默认的UTF8文本文件时,就会出现乱码 。
如下例
idea的字符集设置 默认是UTF-8,这里修改为GBK
运行的代码及结果
FileReader fileReader = new FileReader("D:/sanguo/utf8.txt");
int read;
while ((read = fileReader.read()) != -1) {
System.out.print((char)read);
}
// 浣犲ソ
Reader的子类,读取字节,并使用指定的字符集将其解码为字符。字符集可以自己指定,也可以使用平台的默认字符集。
构造方法如下
// 使用平台默认字符集
public InputStreamReader(InputStream in) {}
// 指定字符集
public InputStreamReader(InputStream in, String charsetName)
throws UnsupportedEncodingException{}
读取文件的“你好",文件默认的字符集是UTF8
// 创建流对象,默认UTF8编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:/三国/utf8.txt"));
// 创建流对象,指定GBK编码
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("D:/三国/utf8.txt"), "GBK");
int read;
while ((read = isr.read()) != -1) {
System.out.println((char) read);
}
while ((read = isr2.read()) != -1) {
System.out.println((char) read);
}
// 输出结果
你好
浣犲ソ
Writer的子类,使用指定的字符集将字符编码为字节。字符集可以自己指定,也可以使用平台的默认字符集。
构造方法如下
// 使用平台默认字符集
public OutputStreamWriter(OutputStream out) {}
// 使用平台默认字符集
public OutputStreamWriter(OutputStream out, String charsetName)
throws UnsupportedEncodingException{}
如下面的代码,将你好写入文件。写入后两个文件的字符集不一样,文件大小也不同
// 创建流对象,默认UTF8编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/三国/黄忠.txt"));
osw.write("你好"); // 保存为6个字节
// 创建流对象,指定GBK编码
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("D:/三国/马超.txt"),"GBK");
osw2.write("你好");// 保存为4个字节
jdk提供了对象序列化的方式,该序列化机制将对象转为二进制流,二进制流主要包括对象的数据、对象的类型、对象的属性。可以将java对象转为二进制流写入文件中。文件会持久保存了对象的信息。
同理,从文件中读出对象的信息为反序列化的过程
对象想序列化,满足的条件:
该类实现将对象序列化后写出到外部设备,如硬盘文件
public ObjectOutputStream(OutputStream out) throws IOException{}
常用方法
方法名 | 方法说明 |
---|---|
void writeObject(Object obj) throws IOException | 将指定的对象写出 |
如下代码,将User对象写入文件中
public class User implements Serializable {
private static final long serialVersionUID = 8289102797441171947L;
private String name;
private Integer age;
}
// 下面是将对象输出到文件的核心代码
User user = new User("马超",20);
// 创建序列化流对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/三国/马超.txt"));
// 写出对象
out.writeObject(user);
注意:
生成的文件内容如下
该类将ObjectOutputStream写出的对象反序列化成java对象
public ObjectInputStream(InputStream in) throws IOException
常用方法
方法名 | 方法说明 |
---|---|
Object readObject() throws IOException, ClassNotFoundException | 读取对象 |
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:/三国/马超.txt"));
// 强转为user
User user = (User) in.readObject();
System.out.println(user);
// 输出内容
User(name=马超, age=20)
利用对象流和字节数组流结合 ,可以实现java对象和byte[]之间的互转
// 将对象转为byte[]
public static <T> byte[] t1(T t) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(t);
return bos.toByteArray();
}
// 将byte[]转为对象
public static <T> T t2(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream bos = new ByteArrayInputStream(data);
ObjectInputStream oos = new ObjectInputStream(bos);
return (T) oos.readObject();
}
管道流主要用于两个线程间的通信,即一个线程通过管道流给另一个线程发数据
注意:线程的通信一般使用wait()/notify(),使用流也可以达到通信的效果,并且可以传递数据
使用的类是如下
这里使用字节流为例
class Sender implements Runnable {
private PipedOutputStream pos;
private String msg;
public Sender(String msg) {
this.pos = new PipedOutputStream();
this.msg = msg;
}
@Override
public void run() {
pos.write(msg.getBytes());
}
public PipedOutputStream getPos() {
return pos;
}
}
class Receiver implements Runnable {
private PipedInputStream pis;
public Receiver() {
this.pis = new PipedInputStream();
}
@Override
public void run() {
byte[] data = new byte[1024];
int len;
while ((len = pis.read(data)) != -1) {
System.out.println(new String(data, 0, len));
}
}
}
Sender sender = new Sender("hello");
Receiver receiver = new Receiver();
receiver.getPis().connect(sender.getPos());
new Thread(sender).start();
new Thread(receiver).start();
// 控制台输出 hello
System.in和System.out代表了系统标准的输入、输出设备
默认输入设备是键盘,默认输出设备是控制台
可以使用System类的setIn,setOut方法对默认设备进行改变
我们开发中经常使用的输出到控制台上的内容的方法。
System.out.println("a");
System.out.print("b");
class System{
public final static InputStream in = null;
public final static PrintStream out = null;
}
public PrintStream(String fileName) throws FileNotFoundException{}
主要方便读取Java基本类型以及String的数据,有DataInputStream 和 DataOutputStream两个实现类
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/三国/周瑜.txt"));
dos.writeUTF("周瑜");
dos.writeBoolean(false);
dos.writeLong(1234567890L);
DataInputStream dis = new DataInputStream(new FileInputStream("D:/三国/周瑜.txt"));
String s = dis.readUTF();
System.out.println(s);
boolean b = dis.readBoolean();
System.out.println(b);
// 输出
周瑜
false
以上各个章节详细介绍了各个流,可见流的种类比较多,记忆确实增加了困难。但是可以通过思维导图的方式整理出来,方便记忆。
字节流的导图
字符流的导图
按照功能划分
输入、输出对应关系
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/RVMYVZh4Mk5WE6IojTKNgA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。