📓 本文已归档到:「javacore」
关键词:
InputStream
、OutputStream
、Reader
、Writer
- 字符流和字节流
- FileReader 和 FileWriter
- InputStreamReader 和 OutputStreamWriter
- BufferedReader
- PrintStream
- FileInputStream 和 FileOutputStream
- ByteArrayInputStream 和 ByteArrayOutputStream
- PipedInputStream 和 PipedOutputStream
- DataInputStream 和 DataOutputStream
- ZipInputStream 和 ZipOutputStream
- ObjectInputStream 和 ObjectOutputStream
JAVA IO 中的流操作分为两类:
- 字节流主要操作字节类型数据(byte)。主要类是
InputStream
(输入) 和OutputStream
(输出)。 - 字符流主要操作字符类型数据,一个字符占两个字节。主要类是
Reader
(输入) 和Writer
(输出)。
JAVA IO 中的流操作类,常常是以输入、输出两种形式成对提供。
在 JAVA IO 中,流操作的一般流程如下:
- 使用 File 类绑定一个文件。
- 把 File 对象绑定到流对象上。
- 进行读或写操作。
- 关闭流
- 字节流主要操作字节类型数据(byte);字符流主要操作字符类型数据,一个字符占两个字节。
- 字节流在操作时本身不会用到缓冲区(内存),而是对文件本身直接操作的;字符流在操作时使用了缓冲区,通过缓冲区再操作文件。
FileReader 和 FileWriter 用于输入输出文本文件。
import java.io.*;
public class ReaderAndWriterDemo {
public static void output(String filepath) throws IOException {
// 1.使用 File 类绑定一个文件
File f = new File(filepath);
// 2.把 File 对象绑定到流对象上
Writer out = new FileWriter(f);
// Writer out = new FileWriter(f, true); // 追加内容方式
// 3.进行读或写操作
String str = "Hello World!!!\r\n";
out.write(str);
// 4.关闭流
// 字符流操作时使用了缓冲区,并在关闭字符流时会强制将缓冲区内容输出
// 如果不关闭流,则缓冲区的内容是无法输出的
// 如果想在不关闭流时,将缓冲区内容输出,可以使用 flush 强制清空缓冲区
out.flush();
out.close();
}
public static char[] input(String filepath) throws IOException {
// 1.使用 File 类绑定一个文件
File f = new File(filepath);
// 2.把 File 对象绑定到流对象上
Reader input = new FileReader(f);
// 3.进行读或写操作
int temp = 0; // 接收每一个内容
int len = 0; // 读取内容
char[] c = new char[1024];
while ((temp = input.read()) != -1) {
// 如果不是-1就表示还有内容,可以继续读取
c[len] = (char) temp;
len++;
}
System.out.println("文件字符数为:" + len);
// 4.关闭流
input.close();
return c;
}
public static void main(String[] args) throws IOException {
String filepath = "d:\\test.txt";
output(filepath);
System.out.println("内容为:" + new String(input(filepath)));
}
}
InputStreamReader 和 OutputStreamWriter 可以将 InputStream 和 OutputStream 分别转换为 Reader 和 Writer。
示例:
import java.io.*;
public class OutputStreamWriterDemo {
public static void main(String args[]) throws IOException {
File f = new File("d:" + File.separator + "test.txt");
Writer out = new OutputStreamWriter(new FileOutputStream(f));
out.write("hello world!!");
out.close();
}
}
public class InputStreamReaderDemo {
public static void main(String args[]) throws IOException {
File f = new File("d:" + File.separator + "test.txt");
Reader reader = new InputStreamReader(new FileInputStream(f));
char c[] = new char[1024];
int len = reader.read(c);
reader.close();
System.out.println(new String(c, 0, len));
}
}
BufferedReader 类用于从缓冲区中读取内容,所有的输入字节数据都放在缓冲区中。
示例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class BufferedReaderDemo {
public static void main(String args[]) throws IOException {
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.print("请输入内容:");
String str = buf.readLine();
if (str.equalsIgnoreCase("exit")) {
System.out.print("退出");
break;
}
System.out.println("输入的内容为:" + str);
}
}
}
PrintStream 提供了非常方便的打印功能。
事实上,我们常用的 System 中提供的静态成员 System.out 和 System.err 就是 PrintStream 对象。
示例:
import java.io.*;
public class PrintStreamDemo {
public static void main(String arg[]) throws Exception {
final String filepath = "d:\\test.txt";
// 如果现在是使用 FileOuputStream 实例化,意味着所有的数据都会输出到文件中
OutputStream os = new FileOutputStream(new File(filepath));
PrintStream ps = new PrintStream(os);
ps.print("Hello ");
ps.println("World!!!");
ps.printf("姓名:%s;年龄:%d", "张三", 18);
ps.close();
}
}
FileInputStream 和 FileOutputStream 用于输入、输出文件。
示例:
import java.io.*;
public class FileStreamDemo {
private static final String FILEPATH = "d:\\test.txt";
public static void output(String filepath) throws IOException {
// 第1步、使用File类找到一个文件
File f = new File(filepath);
// 第2步、通过子类实例化父类对象
OutputStream out = new FileOutputStream(f);
// 实例化时,默认为覆盖原文件内容方式;如果添加true参数,则变为对原文件追加内容的方式。
// OutputStream out = new FileOutputStream(f, true);
// 第3步、进行写操作
String str = "Hello World\r\n";
byte[] bytes = str.getBytes();
out.write(bytes);
// 第4步、关闭输出流
out.close();
}
public static void input(String filepath) throws IOException {
// 第1步、使用File类找到一个文件
File f = new File(filepath);
// 第2步、通过子类实例化父类对象
InputStream input = new FileInputStream(f);
// 第3步、进行读操作
// 有三种读取方式,体会其差异
byte[] bytes = new byte[(int) f.length()];
int len = input.read(bytes); // 读取内容
System.out.println("读入数据的长度:" + len);
// 第4步、关闭输入流
input.close();
System.out.println("内容为:\n" + new String(bytes));
}
public static void main(String args[]) throws Exception {
output(FILEPATH);
input(FILEPATH);
}
}
ByteArrayInputStream 和 ByteArrayOutputStream 用于在内存中输入、输出数据。
示例:
import java.io.*;
public class ByteArrayStreamDemo {
public static void main(String args[]) {
String str = "HELLOWORLD"; // 定义一个字符串,全部由大写字母组成
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 准备从内存ByteArrayInputStream中读取内容
int temp = 0;
while ((temp = bis.read()) != -1) {
char c = (char) temp; // 读取的数字变为字符
bos.write(Character.toLowerCase(c)); // 将字符变为小写
}
// 所有的数据就全部都在ByteArrayOutputStream中
String newStr = bos.toString(); // 取出内容
try {
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(newStr);
}
}
PipedInputStream 和 PipedOutputStream 可以在两个线程间进行通信。
示例:
import java.io.*;
public class PipedStreamDemo {
static class Send implements Runnable {
private PipedOutputStream pos = null;
Send() {
pos = new PipedOutputStream(); // 实例化输出流
}
@Override
public void run() {
String str = "Hello World!!!";
try {
pos.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
try {
pos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 得到此线程的管道输出流
*/
PipedOutputStream getPos() {
return pos;
}
}
static class Receive implements Runnable {
private PipedInputStream pis = null;
Receive() {
pis = new PipedInputStream();
}
@Override
public void run() {
byte b[] = new byte[1024];
int len = 0;
try {
len = pis.read(b);
} catch (IOException e) {
e.printStackTrace();
}
try {
pis.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("接收的内容为:" + new String(b, 0, len));
}
/**
* 得到此线程的管道输入流
*/
PipedInputStream getPis() {
return pis;
}
}
public static void main(String args[]) {
Send s = new Send();
Receive r = new Receive();
try {
s.getPos().connect(r.getPis()); // 连接管道
} catch (IOException e) {
e.printStackTrace();
}
new Thread(s).start(); // 启动线程
new Thread(r).start(); // 启动线程
}
}
DataInputStream 和 DataOutputStream 会一定格式将数据输入、输出。
示例:
import java.io.*;
public class DataStreamDemo {
public static final String FILEPATH = "d:\\order.txt";
private static void output(String filepath) throws IOException {
// 1.使用 File 类绑定一个文件
File f = new File(filepath);
// 2.把 File 对象绑定到流对象上
DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));
// 3.进行读或写操作
String names[] = {"衬衣", "手套", "围巾"};
float prices[] = {98.3f, 30.3f, 50.5f};
int nums[] = {3, 2, 1};
for (int i = 0; i < names.length; i++) {
dos.writeChars(names[i]);
dos.writeChar('\t');
dos.writeFloat(prices[i]);
dos.writeChar('\t');
dos.writeInt(nums[i]);
dos.writeChar('\n');
}
// 4.关闭流
dos.close();
}
private static void input(String filepath) throws IOException {
// 1.使用 File 类绑定一个文件
File f = new File(filepath);
// 2.把 File 对象绑定到流对象上
DataInputStream dis = new DataInputStream(new FileInputStream(f));
// 3.进行读或写操作
String name = null; // 接收名称
float price = 0.0f; // 接收价格
int num = 0; // 接收数量
char temp[] = null; // 接收商品名称
int len = 0; // 保存读取数据的个数
char c = 0; // '\u0000'
try {
while (true) {
temp = new char[200]; // 开辟空间
len = 0;
while ((c = dis.readChar()) != '\t') { // 接收内容
temp[len] = c;
len++; // 读取长度加1
}
name = new String(temp, 0, len); // 将字符数组变为String
price = dis.readFloat(); // 读取价格
dis.readChar(); // 读取\t
num = dis.readInt(); // 读取int
dis.readChar(); // 读取\n
System.out.printf("名称:%s;价格:%5.2f;数量:%d\n", name, price, num);
}
} catch (EOFException e) {
System.out.println("结束");
} catch (IOException e) {
e.printStackTrace();
}
// 4.关闭流
dis.close();
}
public static void main(String args[]) throws IOException {
output(FILEPATH);
input(FILEPATH);
}
}
示例:
import java.io.*;
import java.util.zip.*;
public class ZipStreamDemo {
public static final String ZIP_FILE_PATH = "d:\\zipdemo.zip";
public static void demo01(String zipfilepath) throws IOException {
File file = new File(zipfilepath);
ZipFile zipFile = new ZipFile(file);
ZipEntry entry = zipFile.getEntry("mldn.txt");
System.out.println("压缩文件的名称:" + zipFile.getName());
File outputFile = new File("d:" + File.separator + "mldn_unzip.txt");
OutputStream out = new FileOutputStream(outputFile); // 实例化输出流
InputStream input = zipFile.getInputStream(entry); // 得到一个压缩实体的输入流
int temp = 0;
while ((temp = input.read()) != -1) {
out.write(temp);
}
input.close(); // 关闭输入流
out.close(); // 关闭输出流
}
/**
* 压缩一个文件
*/
public static void output1(String filepath, String zipfilepath) throws Exception {
// 1.使用 File 类绑定一个文件
// 定义要压缩的文件
File file = new File(filepath);
// 定义压缩文件名称
File zipFile = new File(zipfilepath);
// 2.把 File 对象绑定到流对象上
InputStream input = new FileInputStream(file);
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
// 3.进行读或写操作
zipOut.putNextEntry(new ZipEntry(file.getName()));
zipOut.setComment("This is a zip file.");
int temp = 0;
while ((temp = input.read()) != -1) { // 读取内容
zipOut.write(temp); // 压缩输出
}
// 4.关闭流
input.close();
zipOut.close();
}
/**
* 读取实体为一个文件的压缩包
*/
public static void input1(String zipfilepath, String filepath) throws Exception {
// 1.使用 File 类绑定一个文件
File zipFile = new File(zipfilepath);
// 2.把 File 对象绑定到流对象上
ZipInputStream input = new ZipInputStream(new FileInputStream(zipFile));
// 3.进行读或写操作
ZipEntry entry = input.getNextEntry(); // 得到一个压缩实体
System.out.println("压缩实体名称:" + entry.getName());
// 4.关闭流
input.close();
}
/**
* 压缩一个目录
*/
public static void output2(String dirpath, String zipfilepath) throws Exception {
// 1.使用 File 类绑定一个文件
// 定义要压缩的文件夹
File file = new File(dirpath);
// 定义压缩文件名称
File zipFile = new File(zipfilepath);
// 2.把 File 对象绑定到流对象上
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
zipOut.setComment("This is zip folder.");
// 3.进行读或写操作
int temp = 0;
if (file.isDirectory()) { // 判断是否是文件夹
File lists[] = file.listFiles(); // 列出全部文件
for (int i = 0; i < lists.length; i++) {
InputStream input = new FileInputStream(lists[i]);
// 设置ZipEntry对象
zipOut.putNextEntry(new ZipEntry(file.getName() + File.separator + lists[i].getName()));
while ((temp = input.read()) != -1) {
zipOut.write(temp);
}
input.close();
}
}
// 4.关闭流
zipOut.close();
}
/**
* 解压实体为一个目录的压缩包
*/
public static void input2(String zipfilepath, String dirpath) throws Exception {
// 1.使用 File 类绑定一个文件
File file = new File(zipfilepath);
ZipFile zipFile = new ZipFile(file);
// 2.把 File 对象绑定到流对象上
ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
// 3.进行读或写操作
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) { // 得到一个压缩实体
System.out.println("解压缩" + entry.getName() + "文件。");
// 定义输出的文件路径
File outFile = new File(dirpath + File.separator + entry.getName());
if (!outFile.getParentFile().exists()) { // 如果输出文件夹不存在
outFile.getParentFile().mkdirs(); // 创建文件夹
}
if (!outFile.exists()) { // 判断输出文件是否存在
outFile.createNewFile(); // 创建文件
}
InputStream input = zipFile.getInputStream(entry); // 得到每一个实体的输入流
OutputStream out = new FileOutputStream(outFile); // 实例化文件输出流
int temp = 0;
while ((temp = input.read()) != -1) {
out.write(temp);
}
input.close(); // 关闭输入流
out.close(); // 关闭输出流
}
// 4.关闭流
zis.close();
}
public static void main(String[] args) throws Exception {
final String filepath = "d:\\demo.txt";
final String zipfilepath = "d:\\demo.zip";
final String dirpath = "d:\\demo2";
final String dirpath2 = "d:\\new";
final String zipfilepath2 = "d:\\demo2.zip";
// demo01(ZIP_FILE_PATH);
output1(filepath, zipfilepath);
input1(zipfilepath, filepath);
output2(dirpath, zipfilepath2);
input2(zipfilepath2, dirpath2);
}
}
ObjectInputStream 和 ObjectOutputStream 是对象输入输出流,一般用于对象序列化。
示例:
import java.io.*;
public class ObjectStream {
public static class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "姓名:" + this.name + ";年龄:" + this.age;
}
}
public static void writeObject(String filepath, Object obj[]) throws Exception {
// 1.使用 File 类绑定一个文件
File f = new File(filepath);
// 2.把 File 对象绑定到流对象上
OutputStream out = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(out);
// 3.进行读或写操作
oos.writeObject(obj);
// 4.关闭流
oos.close();
}
public static Object[] readObject(String filepath) throws Exception {
// 1.使用 File 类绑定一个文件
File f = new File(filepath);
// 2.把 File 对象绑定到流对象上
InputStream input = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(input);
// 3.进行读或写操作
Object[] objects = (Object[]) ois.readObject();
// 4.关闭流
ois.close();
return objects;
}
public static void main(String args[]) throws Exception {
final String filepath = "d:\\object.txt";
Person per[] = {new Person("张三", 30), new Person("李四", 31), new Person("王五", 32)};
writeObject(filepath, per);
Object o[] = readObject(filepath);
for (int i = 0; i < o.length; i++) {
Person p = (Person) o[i];
System.out.println(p);
}
}
}