Java IO流
常见IO流归纳
字节流
OutputStream:字节输出流
public abstract class OutputStream implements Closeable, Flushable{}
OutputStream是一个抽象类,是表示字节输出流的所有类的超类。操作的数据都是字节,定义了输出字节流的基本共性功能方法。
常见的方法:
close():关闭字节输出流,释放资源,类似python中操作文件,最后需要close一样。
write():该方法为重载方法,将相应的内容写入文件中。
flush():是将缓存的数据刷入永久存储(文件)中。
FileOutputStream
public class FileOutputStream extends OutputStream{}
FileOutputStream流是指文件字节输出流,专用于输出原始字节流如图像数据等,其继承OutputStream类,拥有输出流的基本特性
构造方法:
/**
* 读取文件中的数据
*/
public static void main(String[] args) {
try(OutputStream ops = new FileOutputStream("测试",true)) {
ops.write(48);// 写入对应的ASCLL码(48-->0)
ops.write("qwer".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
InputStream:字节输入流
public abstract class InputStream implements Closeable{}
InputSteam是一个抽象类,是表示字节输入流的所有类的超类。操作的数据都是字节,定义了字节输入流的基本共性功能方法。
常见的方法:
close() :关闭此输入流并释放与流相关联的任何系统资源。
read() :从输入流读取数据的下一个字节。
reset() :将此流重新定位到上次在此输入流上调用 mark方法时的位置。
FileInputStream
public class FileInputStream extends InputStream{}
FileInputStream流是指文件字节输入流,用于从文件系统中的某个文件中获得输入字节,获取的文件可用性取决于主机环境。继承InputStream类,拥有输入流的基本特性。
构造方法:
/**
* 读取文件中的数据
*/
public static void main(String[] args) {
try (InputStream ips = new FileInputStream("文件路径");) {
int length = 0;
while ((length = ips.read())!=-1) {
System.out.print((char)length);
}
} catch (Exception e) {
e.printStackTrace();
}
}
字符流
Writer
public abstract class Writer implements Appendable, Closeable, Flushable{}
Writer写入字符流的抽象类,操作数据的最下单位为1个字符。操作的数据都是字符,定义了写入字符流的基本共性功能方法。
常见的方法:
write(char[] cbuf) :往输出流写入一个字符数组。
write(int c) :往输出流写入一个字符。
write(String str) :往输出流写入一串字符串。
write(String str, int off, int len) :往输出流写入字符串的一部分。
close() :关闭流,释放资源。 【这个还是抽象的,写出来是说明有这个关闭功能】
flush():刷新输出流,把数据马上写到输出流中。 【这个还是抽象的,写出来是说明有这个关闭功能】
FileWiter
public class FileWriter extends OutputStreamWriter{}
FileWriter类从OutputStreamWriter类继承而来,FileWriter类用于存储文件,用来读取字符文件的便捷类。
构造方法:
/**
* 将数据写到文件中
*/
public static void main(String[] args) {
try(
// 创建字符输出流,明确需要操作的文件
Writer fw = new FileWriter("文件路径");) {
// 写入字符文件
fw.write("hello world!");
// 强制刷新保存数据
fw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
Reader
public abstract class Reader implements Readable, Closeable {}
Reader用于读取字符流的抽象类,数据单位为字符。操作的数据都是字符,定义了输出字符流的基本共性功能方法。
常见的方法:
read() :读取单个字符,返回结果是一个int,需要转成char;到达流的末尾时,返回-1
read(char[] cbuf):读取cbuf的长度个字符到cbuf这种,返回结果是读取的字符数,到达流的末尾时,返回-1
close() :关闭流,释放占用的系统资源。
FileReader
public class FileReader extends InputStreamReader{}
FileReader类从InputStreamReader类继承而来,FileReader类用于读取文件,用来读取字符文件的便捷类。
/**
* 读取数据
*/
public static void main(String[] args) {
try (
// 创建一个读取流对象,一定要明确读取的文件,并且保证文件路径正确
FileReader fr = new FileReader("文件路径");) {
StringBuffer sb = new StringBuffer();
int len = 0;
// 一次读取一个字符,当返回值为-1,则数据读取完毕
while ((len = fr.read()) != -1) {
sb.append((char) len);
}
System.out.println("文件内容:" + sb);
} catch (Exception e) {
e.printStackTrace();
}
}
字节缓冲流
BufferedOutputStream
public class BufferedOutputStream extends FilterOutputStream{}
BufferedOutputStream没有无参构造方法,它必须传入一个OutputStream (一般是FileOutputStream)来一起使用。另外,我们还可以指定缓冲区的大小,一般情况下,使用默认的缓冲区大小就足够了(默认大小为8192)。
构造方法
/**
* 向文件中写出数据
*/
public static void main(String[] args) {
// 指定目的地
FileOutputStream fops;
try {
fops = new FileOutputStream("文件路径");
BufferedOutputStream bos = new BufferedOutputStream(fops);
// 写入数据
bos.write("whsxt".getBytes());
// 刷新数据
bos.flush();
// 关闭流
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
BufferedInputStream
public class BufferedInputStream extends FilterInputStream{}
BufferedInputStream类从FilterInputStream类继承而来,FilterInputStream类继承于InputStream类。
构造方法
例:
/**
* 从文件中读入数据
*/
public static void main(String[] args) {
try (
// 指定目的地
InputStream ips = new FileInputStream("文件路径");
BufferedInputStream bips = new BufferedInputStream(ips);) {
int len = 0;
byte[] data = new byte[1024];
StringBuilder sb = new StringBuilder();
// 取数据
while ((len = bips.read(data)) != -1) {
sb.append(new String(data, 0, len));
}
System.out.println(sb);
} catch (IOException e) {
e.printStackTrace();
}
}
字符缓冲流
BufferedWriter
newLine():方法会根据当前的操作系统,写入一个换行符(不同操作系统换行符不一样,例如:windows操作系统的换行符为“\r\n”,Linux操作系统的换行符为“\n”)。
BufferedReader
readLine():方法从输入流中读取一行文本,如果已到达流末尾,则返回null。
例:
/**
* 字符缓冲流拷贝文件
*/
public static void main(String[] args) throws IOException {
try (
// 把基本输出流进行包装
BufferedReader br = new BufferedReader(new FileReader("原文件路径"));
// 把基本输出流进行包装
BufferedWriter bw = new BufferedWriter(new FileWriter("新文件路径+文件名"));) {
// 读取数据
String line = null;
while ((line = br.readLine()) != null) {
// 存数据
bw.write(line);
// 刷新数据
bw.flush();
// 添加换行
bw.newLine();
}
} catch (Exception e) {
e.printStackTrace();
}
}
转换流
InputStreamReader
是Reader的子类,将输入的字节流变为字符流,即:将一个字节流的输入对象变为字符流的输入对象。
构造方法
例:
/**
* 采用utf-8编码读取文件
*/
public static void main(String[] args) {
try (
// 创建与文件关联的字节输入流对象
InputStream fips = new FileInputStream("文件路径");
// 创建转换流对象,编码格式指定为utf-8
InputStreamReader ipsr = new InputStreamReader(fips, "utf-8");) {
// 读取数据
char[] buf = new char[1024];
int len = 0;
while ((len = ipsr.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
}
OutputStreamWriter
是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变为字节流的输出对象。
构造方法
例:
public static void main(String[] args) {
try (
// 创建与文件关联的字节输出流对象
FileOutputStream fos = new FileOutputStream("文件路径");
// 创建可以把字符转成字节的转换流对象,并指定编码
OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");) {
// 写入数据
osw.write("LYANG");
} catch (Exception e) {
e.printStackTrace();
}
}
数据流
DataOutputStream
DataOutputStream数据输出流允许应用程序以适当方式将基本数据类型和字符串类型数据写入文件中,常见的方法有:writeByte()、writeShort()、writeInt()、writeLong()、writeFloat()、writeDouble()、writeChar()、writeBoolean()、writeUTF()等。
DataOutputStream
使用DataOutputStream写入文件的二进制数据,必须通过DataInputStream来读取,并且读取的顺序必须和写入的顺序相同。
/**
* 使用数据流拷贝文件,并打印输出
*/
public static void main(String args[]) throws IOException {
try (
DataInputStream dips = new DataInputStream(new FileInputStream("文件路径"));
DataOutputStream dops = new DataOutputStream(new FileOutputStream("文件路径_copy"));
BufferedReader dr = new BufferedReader(new InputStreamReader(dips));) {
String len;
while ((len = dr.readLine()) != null) {
System.out.println(len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
序列化和反序列化
ObjectOutputStream:序列化
ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
当一个对象要能被序列化,这个对象所属的类必须实现 java.io.Serializable ,否则会发生NotSerializableException 异常。
import java.io.Serializable;
class Student implements Serializable { // 实现Serializable接口
private String name;
private int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
try (
// 明确存储对象的文件
FileOutputStream fops = new FileOutputStream("学生信息文件地址");
// 给操作文件对象加入写入对象功能
ObjectOutputStream oops = new ObjectOutputStream(fops);) {
// 把需要持久化的Student对象添加进入List中
List<Student> list = new ArrayList<Student>();
for (int i = 0; i < 5; i++) {
list.add(new Student("张三" + i, 20 + i));
}
// 调用了写入对象的方法,进行持久化操作
oops.writeObject(list);
} catch (Exception e) {
e.printStackTrace();
}
}
ObjectInputStream:反序列化
ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
public static void main(String[] args) {
try (
// 定义流对象关联存储了对象文件。
FileInputStream fips = new FileInputStream("学生信息文件地址");
// 建立用于读取对象的功能对象。
ObjectInputStream ois = new ObjectInputStream(fips);) {
// 读取list集合
List<Student> list = (ArrayList<Student>) ois.readObject();
for (int i = 0; i < list.size(); i++) {
Student p = list.get(i);
System.out.println(p.getName() + " " + p.getAge());
}
} catch (Exception e) {
e.printStackTrace();
}
}
字节数组流
ByteArrayOutputStream
ByteArrayOutputStream字节数组输出流在内存中创建一个byte数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。缓冲区初始化时默认32个字节,会随着数据的不断写入而自动增长,但是缓冲区最大容量是2G,只要数据不超过2G,都可以往里写。
常用方法
close():关闭 ByteArrayOutputStream没有任何效果。
reset():将此字节数组输出流的 count字段重置为零,以便丢弃输出流中当前累积的所有输出。
size():返回缓冲区的当前大小。
toByteArray():创建一个新分配的字节数组。
write(int b):将指定的字节写入此字节数组输出流。
write(byte[] b, int off, int len):从指定的字节数组写入 len字节,从偏移量为 off开始,输出到这个字节数组输出流。
构造方法
public static void main(String[] args) {
try {
// 字节数组输出流(节点流),可将任意数据类型转换为字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 缓冲流(包装类),用于提高效率
BufferedOutputStream bos = new BufferedOutputStream(baos);
// 对象流(包装流),实现写出任意数据类型
ObjectOutputStream oos = new ObjectOutputStream(bos);
// 使用对象流来写数据
oos.writeInt(123);
oos.writeDouble(123.45);
oos.writeChar('A');
oos.writeBoolean(false);
oos.writeUTF("whsxt");
oos.writeObject(new Date());
// 刷新流,在获取数据之前一定要先刷新流,因为使用了包装流
oos.flush();
// 获取数据
byte[] bs = baos.toByteArray();
System.out.println(Arrays.toString(bs));
} catch (IOException e) {
e.printStackTrace();
}
}
ByteArrayInputStream
字节数组输入流就是把一个字节数组 byte[] 包装了一下,使其具有流的属性,可顺序读下去,还可标记跳回来继续读,主要的作用就是用来读取字节数组中的数据。
常用方法
available():返回可从此输入流读取(或跳过)的剩余字节数。
close():关闭 ByteArrayInputStream没有任何效果。
mark(int readAheadLimit):设置流中当前标记的位置。
read():从该输入流读取下一个数据字节。
reset():将缓冲区重置为标记位置。
skip(long n):从此输入流跳过 n个字节的输入。
构造方法
public static void main(String[] args) {
try {
// 获取字节数组,返回上个案例中通过字节数组输出流写出的字节数组
byte[] bs = outputStreamMethod();
// 字节数组输入流(节点流),用于读取字节数组中的数据
ByteArrayInputStream bios = new ByteArrayInputStream(bs);
// 缓冲流(包装类),用于提高效率
BufferedInputStream bis = new BufferedInputStream(bios);
// 对象流(包装流),实现读取指定类型的数据
ObjectInputStream ois = new ObjectInputStream(bis);
// 读取数据
System.out.println(ois.readInt());
System.out.println(ois.readDouble());
System.out.println(ois.readChar());
System.out.println(ois.readBoolean());
System.out.println(ois.readUTF());
System.out.println(ois.readObject());
} catch (Exception e) {
e.printStackTrace();
}
}
网络下载资源
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import org.junit.Test;
public class TestDownLoad {
/**
* 从网络下载资源到内存中
* @param urlPath 文件路径
* @throws Exception
*/
public byte[] fromNetworkDown(String urlPath) throws Exception {
URL path = new URL(urlPath);
try(
InputStream ips = new BufferedInputStream(path.openStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
) {
byte[] data = new byte[1024];
int length = 0;
while ((length = ips.read(data)) != -1) {
baos.write(data, 0, length);
}
baos.flush();
return baos.toByteArray();
}
}
/**
* 把内存中的数据下载到磁盘
* @param data 获取内存中的数据
* @param newPath 下载到磁盘的路径
* @throws Exception
*/
public void saveDisk(byte[] data, String newPath) throws Exception {
try(
OutputStream ops = new BufferedOutputStream(new FileOutputStream(newPath));
) {
ops.write(data);
ops.flush();
}
}
/**
* 资源下载
* @param path 下载到磁盘的路径
* @throws Exception
*/
public void downResource(String urlPath) throws Exception {
byte[] data = fromNetworkDown(urlPath);
// 获取文件后缀
int lastIndexOf = urlPath.lastIndexOf(".");
// 获取当前系统时间
long TimeMillis = System.currentTimeMillis();
// 定义文件名(当前系统时间 + 文件后缀)
String newFileName = TimeMillis + urlPath.substring(lastIndexOf);
saveDisk(data, newFileName);
}
@Test
public void TestDownLoadFile() {
try {
downResource("https://gss0.bdstatic.com/5bVWsj_p_tVS5dKfpU_Y_D3/res/r/image/2017-09-27/297f5edb1e984613083a2d3cc0c5bb36.png");
System.out.println("下载成功!");
} catch (Exception e) {
e.printStackTrace();
System.err.println("下载失败!");
}
}
}