1.输出流OutputStream
OutputStream是抽象类,如果要使用OutputStream对象,只能使用其子类FileOutputStream的对象,完成写数据到硬盘功能。
FileOutputStream的构造方法
a. FileOutputStream(File file)
创建一个向指定文件写入字节数组的输出流对象(目标文件以File对象的形式表示)
b. FileOutputStream(String name)
创建一个向指定文件写入字节数组的输出流对象(目标文件以路径名字符串的形式表示)
public class Demo1 {
public static void main(String[] args) throws FileNotFoundException {
// FileOutputStream(File file)
File file = new File("a.txt");
OutputStream os1 = new FileOutputStream(file);
//FileOutputStream(String name)
OutputStream os2 = new FileOutputStream("b.txt");
}
}
OutputStream的write方法
void write(int b)
将指定的字节写入此输出流。
write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
参数:
b - 数据。
off - 数据中的初始偏移量。
len - 要写入的字节数。
public class Demo2 {
public static void main(String[] args) throws IOException {
//void write(int b)
writeSingleByte();
//void write(byte[] b)
writeAllBytes();
//void write(byte[] b, int off, int len)
writePartialBytes();
}
private static void writePartialBytes() throws IOException {
// 1. 创建流对象
OutputStream out = new FileOutputStream("a.txt");
// 2. 通过写方法向输出流写入数据
byte[] bytes = "hello world".getBytes();
// void write(byte[] b, int off, int len)
//out.write(bytes, 0, bytes.length);
// 再比如,写入world这个字符串,到目标文件
out.write(bytes, 6, 5);
//3. 关闭流,并释放系统资源
out.close();
}
private static void writeAllBytes() throws IOException {
// 1. 创建流对象
OutputStream out = new FileOutputStream("a.txt");
// 2. 通过写方法向输出流写入数据
byte[] bytes = "hello world".getBytes();
// void write(byte[] b)
out.write(bytes);
//3. 关闭流,并释放系统资源
out.close();
}
private static void writeSingleByte() throws IOException {
// 1. 创建流对象
OutputStream out = new FileOutputStream("a.txt");
// 2. 通过写方法向输出流写入数据
//int a = 97; // 'a'
char c = 'a';
out.write(c);
// 向 文本文件中写入 "hello world"
byte[] bytes = "hello world".getBytes();
for (int i = 0; i < bytes.length; i++) {
out.write(bytes[i]);
}
//3. 关闭流,并释放系统资源
out.close();
}
}
字节流写数据常见问题:
1.创建文件字节输出流到底做了哪些事情?
1). 创建FileOutputStream对象的时候,jvm首先到操作系统,查找目标文件
a. 当发现目标文件不存在的时候, jvm会首先创建该目标文件(内容为空, 前提是该目标文件的父目录存在)
b. 当发现目标文件存在的时候, jvm默认会首先清空目标文件内容,做好准备
让FileOutputStream,从文件头开始写入数据
2). 在内存中,创建FileOutputStream对象
3). 在FileOutputStream对象和目标文件之间建立数据传输通道
2.数据写成功后,为什么要close()?
通过流的close方法:
a. 关闭流
b. 释放系统资源、
3.如何实现数据的换行?
在要换行的地方,向文件中写入换行符即可 ‘\n’
换行符,在不同的操作系统中表示方式不一样:
a. 类unix操作系统中:’\n’
b. windows默认的换行表示: ‘\r’+’\n’ 用windows自带的文本编辑器对于\n是否有换行效果,还和操作系统版本有关
4.如何实现数据的追加写入?
a. 对于同一输出流对象,多次写入的数据,会依次写入目标文件,先写入的数据在前,后写入的数据在后(非追加写入)
b. 所谓追加写入,针对的是不同的输出流对象,向文件写入数据的情况,所谓追加写入,是指当使用不同的输出流对象向文件中写入数据的时候,从文件已有内容之后开始写入
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处
public class Demo3 {
public static void main(String[] args) {
//加上异常处理的输出流代码
// 1.创建文件字节输出流对象
OutputStream out = null;
try {
out = new FileOutputStream("a.txt", true);
// 2. 向目标文件写入数据
byte[] bytes = "lee million".getBytes();
out.write(bytes, 0, bytes.length);
// 向文件中写入换行符
String lineSeparator = System.lineSeparator();
out.write(lineSeparator.getBytes());
bytes = "zhangsan".getBytes();
out.write(bytes, 0, bytes.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3. 关闭流并释放资源
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void question1To4() throws IOException {
// 1.创建文件字节输出流对象
OutputStream out = new FileOutputStream("a.txt", true);
// 2. 向目标文件写入数据
byte[] bytes = "lee million".getBytes();
out.write(bytes, 0, bytes.length);
// 向文件中写入换行符
String lineSeparator = System.lineSeparator();
out.write(lineSeparator.getBytes());
bytes = "zhangsan".getBytes();
out.write(bytes, 0, bytes.length);
// 3. 关闭流并释放资源
out.close();
// 返回和操作系统相关的换行符字符串
//String s = System.lineSeparator();
//System.out.println("\r\n".equals(s));
}
}
2.输入流InputStream
InputStream是抽象类,不能直接实例化,需要使用其子类对象来实现功能.
FileInputStream的构造方法
// 创建一个读取指定文件(目标文件)数据的,文件字节输入流对象(目标文件以File对象的形式表示)
FileInputStream(File file)
// 创建一个读取指定文件(目标文件)数据的,文件字节输入流对象(目标文件以name字符串的形式表示)
FileInputStream(String name)
创建一个文件字节输入流对象,做了哪些工作?
1. FileInputStream对象在被创建之前,jvm会首先到操作系统中,找目标文件
a. 找到,就不做任何额外工作
b. 找不到,则直接抛出异常FileNotFoundException
2. 在jvm内存中,创建FileInputStream对象
3. 在FileInputStream对象和目标文件之间,建立数据传输通道
public class Demo1 {
public static void main(String[] args) throws FileNotFoundException {
// 测试FileInputStream的构造方法
constructor();
}
private static void constructor() throws FileNotFoundException {
//FileInputStream(File file)
File file = new File("c.txt");
InputStream in1 = new FileInputStream(file);
//FileInputStream(String name)
InputStream in2 = new FileInputStream("d.txt");
}
}
InputStream的read方法
int read()
从输入流中读取数据的下一个 字节。
返回值:
1.下一个数据字节;
2.如果到达流的末尾(没有数据可读),则返回 -1。
int read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
返回值:
1. 读入缓冲区的总字节数;
2. 如果因为已经到达流末尾而不再有数据可用,则返回 -1。
int read(byte[] b, int off, int len)
开发中基本不会使用。
将输入流中最多 len 个数据字节读入 byte 数组(从第offset个位置开始填充)。
public class Demo2 {
public static void main(String[] args) throws IOException {
// 读取单个字节数据
readSingleByte();
// int read(byte[] b)
readAllBytes();
//int read(byte[] b, int off, int len)
readParialBytes();
}
private static void readParialBytes() throws IOException {
// 1. 创建流对象
InputStream input = new FileInputStream("a.txt");
//2. 从目标文件读取数据
// int read(byte[] b)
// 实际开发中,通常给1024的整数倍 2^10
byte[] buffer = new byte[1024];
// len 就告诉我们实际向字节数组中填充了多少个字节数据(实际读取到的字节个数)
int offset = 5;
int len = input.read(buffer, offset, buffer.length - offset);
System.out.println(len);
// 3. 关闭流并释放资源
input.close();
}
private static void readAllBytes() throws IOException {
// 1. 创建流对象
InputStream input = new FileInputStream("a.txt");
//2. 从目标文件读取数据
// int read(byte[] b)
// 实际开发中,通常给1024的整数倍 2^10
byte[] buffer = new byte[1024];
// len 就告诉我们实际向字节数组中填充了多少个字节数据(实际读取到的字节个数)
int len = input.read(buffer);
String s = new String(buffer,0, len);
System.out.println(s);
System.out.println("lee million".equals(s));
System.out.println(Arrays.toString(buffer));
// 3. 关闭流并释放资源
input.close();
}
private static void readSingleByte() throws IOException {
// 1. 创建流对象
InputStream input = new FileInputStream("a.txt");
//2. 从目标文件读取数据
//int read()
// int readByte = input.read();
// char c = (char) readByte;
// System.out.println(c);
int readByte;
while ((readByte = input.read()) != -1) {
// 读取目标文件中,一个字节数据(代表一个字符)
char c = (char) readByte;
System.out.print(c);
}
// 3. 关闭流并释放资源
input.close();
}
}
3.字节缓冲流
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果, java本身在设计的时候,也考虑到了这样的情况,所以提供了字节缓冲区流。
字节缓冲输出流 BufferedOutputStream
构造方法
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
字节缓冲输入流 BufferedInputStream
构造方法
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
需要以其他流,作为初始化参数,从而创建出的流对象,这种流我们称为包装流对象,其类我们称为包装流。
如果过要关闭包装流对象,只需要关闭包装流对象即可(不需要关心包装流所包装的底层流)。
因为包装流会自己负责关闭,它所包装的底层流。
public class Demo1 {
public static void main(String[] args) throws IOException {
//basicUse();
// 利用缓冲流复制文件
InputStream in = new BufferedInputStream(
new FileInputStream("d:\\a.txt"));
OutputStream out = new BufferedOutputStream(
new FileOutputStream("e:\\b.txt"));
byte[] buf = new byte[4096];
int len;
while ((len = in.read(buf)) != -1) {
// 将读取到的多个字节数据,写入输出流
out.write(buf, 0, len);
}
//关闭流并释放资源
in.close();
out.close();
}
private static void basicUse() throws IOException {
// 创建缓冲输出流对象
FileOutputStream fos = new FileOutputStream("d.txt");
OutputStream out = new BufferedOutputStream(fos);
byte[] bytes = "hello buffer".getBytes();
out.write(bytes);
close包装流即可
//关闭流释放资源
out.close();
//创建缓冲输入流对象
FileInputStream fis = new FileInputStream("d.txt");
InputStream in = new BufferedInputStream(fis);
byte[] buffer = new byte[1024];
int len = in.read(buffer);
// close包装流即可
in.close();
System.out.println(new String(buffer, 0, len));
}
}
public void flush()
刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。
public void close()
关闭此输出流并释放与此流有关的所有系统资源。
close 方法先调用其 flush 方法,然后调用其基础输出流的 close 方法
public class Demo2 {
public static void main(String[] args) throws IOException {
// 缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("f.txt"));
byte[] bytes = "hello zs".getBytes();
bos.write(bytes);
// bos.flush();
bos.close();//直接调用close就可以
//close 方法先调用其 flush 方法,
//然后调用其基础输出流的 close 方法
}
}