在javaIO中,流是一个核心概念。可以将流理解为一个连续的数据串。
你可以从流中读数据,也可以向流中写数据。但是对于同一个流,只能来读数据或者写数据,不能既用来读,又用来写。从而可以将流按照读或者写,分为输入流与输出流两种。输入与输出都是相对于内存(程序)来说的,磁盘或网络等向内存中传输数据用到的就是输入流,内存向磁盘或是网络传输数据就是用输出流。
流既可以以字节为单位进行读写,也可以以字符为单位。从而流按照读写的单位不同,分为字节流与字符流。
JavaIO中,字节流通常以“stream”命名,例如InputStream与OutputStream。除了DataInputSteam和DataOutputStream可以读写int、double、float等基本类型的数据外,其他的字节流都只能一个个字节的读取或写入。
字符流通常以“Reader”或“Writer”命名,字符流以字符为单位进行读取或写入。
InputStream与OutputStream
java.io.InputStream是所有字节输入流的基类。它的子类包括有FileInputStream、BufferedInputStream、DataInputStream等。
简单示例:
InputStream input = new FileInputStream("D:\\test.txt");
// read():返回一个整数,代表读取到的字节的内容(范围:0~255)
// 返回-1,代表文件读取完毕
int data = input.read();
while (data != -1) {
//do something
data = input.read();
}
input.close();
上述示例中,创建了一个FileInputStream对象,用于读取磁盘中的文件。FileInputStream是InputStream的子类,所以FileInputStream对象可以赋值给InputStream。
流在使用完毕后需要正确的关闭它,close()可以做到这一点。
但是上述代码在while循环中的doSomething中可能发生异常,导致后续的close()未被调用,流不能被关闭,所以需要增加try{}catch{}finally{},将input.close()放在finally中,确保最终会被执行到。
因为close()方法本身也可能会抛出异常,所以还需要一层try{}catch。
最终代码如下所示:
InputStream input = null;
try {
input = new FileInputStream("D:\\test.txt");
int data = input.read();
while (data != -1) {
// 此处可能发生异常
// do something
data = input.read();
}
} catch (IOException e) {
// do something
} finally {
try {
if (input != null) {
// close()本身可能会抛出异常
input.close();
}
} catch (IOException e) {
// do something
}
}
除了上述方法外,还可以使用从Java7开始,被称为“try-with-resource”的异常处理机制。具体可见此篇文章:AutoCloseable作用
后续代码为了简洁考虑,只会写输入输出的主体代码,不再写冗长的异常处理。
java.io.OutputStream是所有字节输出流的父类。它的子类包括有FileOutputStream、BufferedOutputStream、DataOutputStream等。
简单示例如下:
OutputStream output = new FileOutputStream("D:\\out.txt");
byte[] bytes = "Hello World".getBytes();
int i = 0;
while (i < bytes.length) {
int b = bytes[i];
// 将单个字节写入到输出流中
output.write(b);
i++;
}
output.close();
OutputStream的write(byte)方法将一个包含待写入数据信息的int变量作为参数写入输出流。只有int类型的第一个字节会被写入,其他为会被忽略。即写入低8位,忽略高24位。
flush():OutputStream的flush()方法会将输出流中的数据冲刷到对应的目标媒介中。比如,输出流是FileOutputStream,那么写入到文件输出流中的数据可能暂存在内存的缓冲区中,并没有及时的写入到磁盘中。通过调用flush()方法,可以强制将缓冲区中的数据刷新到磁盘(或是其他目标媒介)中。
Reader与Writer
java.io.Reader是字符输入流的基类。Reader与InputStream类似,不同之处在于,Reader基于字符,而InputStream基于字节。它的子类包括有FileReader、BufferedReader、PipedReader等。
简单示例如下:
// 文件内容为:test测试文本
Reader reader = new FileReader("D:\\test.txt");
StringBuilder stringBuilder = new StringBuilder();
int data = reader.read();
while(data != -1){
char dataChar = (char) data;
stringBuilder = stringBuilder.append(dataChar);
data = reader.read();
}
reader.close();
System.out.println(stringBuilder.toString());
运行结果:
test测试文本
注意,文件与程序的编码格式要保持一致,此处都设置为UTF-8。txt文件的编码格式可以通过:“文件”->“另存为”->“编码”设置。Java程序的编码格式通过-Dfile.encoding=UTF-8设置。
Reader的read()方法返回一个字符,可能是一个字节,也可能两个字节,意味着返回值的范围为0~65535.当读到文件结尾处,返回值为-1.
java.io.Writer是字符输入流的基类。Writer与OutputStream的区别在于,前者基于字符进行操作,后者对字节操作。Writer的子类包括有FileWriter、BufferedWriter、PipedWriter等。
简单示例如下:
Writer writer = new FileWriter("D:\\output.txt");
writer.write("HelloWorld你好世界");
writer.close();
运行后,D盘多出一个output.txt文件,内容为:HelloWorld你好世界。
InputStreamReader与OutputStreamWriter
之前介绍的输入输出流,要么是以字节为单位进行读写,要么以字符为单位进行操作,那么能不能先用字节读写到流中,再转换为字符流呢?InputStreamReader与OutputStreamWriter就是这个作用,它可以将字节流转化为字符流。
InputStreamReader简单示例如下:
// 文件内容为:test测试文本
InputStream inputStream = new FileInputStream("D:\\test.txt");
// 将字节流转换为字符流
Reader reader = new InputStreamReader(inputStream);
// 可以在转换过程中限定编码格式
// Reader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
StringBuilder stringBuilder = new StringBuilder();
int data = reader.read();
while(data != -1){
char dataChar = (char) data;
stringBuilder = stringBuilder.append(dataChar);
data = reader.read();
}
reader.close();
System.out.println(stringBuilder.toString());
运行结果:
test测试文本
OutputStreamWriter简单示例如下:
OutputStream outputStream = new FileOutputStream("D:\\output01.txt");
Writer writer = new OutputStreamWriter(outputStream);
// 可以在转换过程中限定编码格式
// Writer outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");
writer.write("HelloWorld你好世界");
writer.close();
运行后,D盘多出一个output01.txt文件,内容为:HelloWorld你好世界。
参考链接:
本文详细介绍了Java IO中的流概念,包括输入流与输出流、字节流与字符流的区别。以FileInputStream和FileOutputStream为例展示了读写文件的基本操作,并强调了异常处理和资源关闭的重要性。同时,提到了Reader和Writer类在字符流操作中的应用,以及InputStreamReader和OutputStreamWriter在字节流与字符流转换中的作用。最后,文章提醒注意文件与程序的编码一致性问题。
2028

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



