IO流:用于处理设备之间的数据传输。
Java对数据的操作都是通过流的方式。
Java用于操作流的对象都在IO包中。
输入流:读入数据
输出流:写出数据
这里的输入和输出指的是内存的输入和输出。
字节流:可以读写任何类型的文件,比如音频,视频,文本文件,可执行文件等。
字符流:只能读写文本文件
通常情况下,如果文件可以用Windows自带的记事本打开,就可以选用字符流,如果对文件类型不了解的话,就用字节流。
A:字节流的抽象基类:InputStream OutputStream
B:字符流的抽象基类:Reader Writer
字节流
字节输入流 InputStream 读
字节输出流 OutputStream 写
字符流
字符输入流 Reader 读
字符输出流 Writer 写
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。比如InputStream的子类FileInputStream,Reader的子类FileReader。
OutputStream是一个抽象类,我们不能对其进行直接实例化,而我们需要使用子类对其进行实例化。
我们先来尝试在一个文件里写入文字。
我们现在操作的是文件所以我们选择的是FileOutputStream。
我们先来学习最简单的构造和使用吧。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
//FileOutputStream(File file)
//创建一个向指定 File 对象表示的文件中写入数据的文件输出流
FileOutputStream out = new FileOutputStream(file);
//FileOutputStream(String name)
//创建一个向具有指定名称的文件中写入数据的输出文件流。
//直接传入一个字符串的文件路径,如果这个文件不存在,会自动帮你创建
FileOutputStream out2 = new FileOutputStream("c.txt");
//通过以上两种方式我们就创建了两个FileOutputStream实例
//接下来我们就可以利用实例来往它所关联的文件里面写入数据
//一次写入一个字节
/*public void write(int b)*/
out.write(98);//a
out.write(98);//b
out.write(99);//c
//一次写入一个字节数组
/*public void write ( @NotNull byte[] b)*/
out2.write("你且迷着风浪永远二十赶朝暮".getBytes());
//写入指定长度的字节
/*public void write(@NotNull byte[] b,
int off,
int len)
将字节数组从off位置开始len长度字节数组数据写入到输出流
*/
//用Stringl类的转换方法getBytes()把字符串转化成字符数组
out2.write("声嘶力竭请你喜欢我".getBytes(), 0, 27);
//UTF - 8 不是固定字长编码的,而是一种变长的编码方式,一个汉字三个字节
//流使用完之后,必须释放资源
out.close();
out2.close();
}
}
–——上面的代码可以帮助我们在指定的文件中写入数据,那么,创建字节输出流对象做了几件事情呢?
–——为什么一定要close()?
A:案例演示: FileOutputStream写出数据如何实现数据的换行
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args) throws IOException {
FileOutputStream out = new FileOutputStream("d.txt");
//写入换行符
//windows下的换行符只用是 \r\n
// * Linux \n
//// * Mac \r
out.write("我和你呀存在一种危险关系".getBytes());
out.write("\r\n".getBytes());
out.write("彼此挟持这另一部分的自己".getBytes());
out.write("\r\n".getBytes());
out.write("本以为这完整了爱的定义".getBytes());
out.write("\r\n".getBytes());
out.close();
}
}
B:案例演示: FileOutputStream写出数据如何实现数据的追加写入
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo2_1{
public static void main(String[] args){
/*FileOutputStream(File file, boolean append)*/
/*FileOutputStream(String name, boolean append)*/
// 完成追加写入
FileOutputStream fos = new FileOutputStream("fos.txt" , true) ;
// 写数据
for(int x = 0 ; x < 10 ; x++){
fos.write(("hello" + x).getBytes()) ;
fos.write("\r\n".getBytes()) ;
}
// 释放资源
fos.close();
}
}
import java.io.FileInputStream;
import java.io.IOException;
public class Demo3 {
public static void main(String[] args) throws IOException {
// FileInputStream 从文件系统中的某个文件获得输入字节
// 构造方法和FileOutputStream类似
/*FileInputStream(String name)
* 通过打开一个到实际文件的连接来创建一个 FileInputStream
* 该文件通过文件系统中的路径名 name 指定。*/
/*FileInputStream(File file)
* 通过打开一个到实际文件的连接来创建一个 FileInputStream
* 该文件通过文件系统中的 File 对象 file 指定。*/
//输入流,如果所关联的文件不存在,那么就会报错
//我们之前不是创建了几个文件吗,现在就用他们来演示
FileInputStream in = new FileInputStream("d.txt");
//那么我们现在就来读取文件中的数据
//1、一次读取一个字节,如果读取不到字节数据返回 -1
//int len = in.read();
//System.out.println(len);
//2、一次读取一个字节数组
byte[] bytes = new byte[1024];//缓冲区
//返回值是你读取到有效字节个数
//int len1 = in.read(bytes);
//System.out.println(len1); //111
//可以把这个字节数组转成字符串来打印
//String s = new String(bytes, 0, len1);
//System.out.println(s);
/*我和你呀存在一种危险关系
彼此挟持这另一部分的自己
本以为这完整了爱的定义*/
//3.一次取字节数组的一部分
int len2 = in.read(bytes, 0, 6);
//off代表读取到的字节数据往缓存区bytes放的时候,从哪个位置开始,len表示一次读取几个字节
System.out.println(len2);//6
String s = new String(bytes, 0, len2);
System.out.println(s);//我和
//for (byte aByte : bytes) {
// System.out.println(aByte);
//}
// 释放资源
in.close();
}
}
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo4 {
public static void main(String[] args) {
FileOutputStream out = null;
try {
out = new FileOutputStream("e.txt");
out.write("怎么处理".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
//不管try里面有没有遇到异常,finally里面的代码都会执行
//一般我们在finally里面做一些善后工作,比如释放一些资源
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo5 {
public static void main(String[] args) throws IOException {
// 方式一:一次读写一个字节来复制文本文件
// 我们把前面写好的文本d.txt复制到D盘
FileOutputStream out = new FileOutputStream("D:\\d.txt");
FileInputStream in = new FileInputStream("d.txt");
int len = 0;
while ((len = in.read()) != -1) {
out.write(len);
}
//释放资源
in.close();
out.close();
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo5_1 {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("E:\\我的图片和音乐\\音乐\\许巍 - 曾经的你.mp3");
FileOutputStream out = new FileOutputStream("D:\\曾经的你.mp3");
int len = 0; //记录读取到的字节
while ((len = in.read()) != -1) {
out.write(len);
out.flush();
}
/*关闭(close) 输出流时,应先刷新(flush)缓冲的输出流,
换话句话说:“迫使所有缓冲的输出数据被写出到底层输出流中”*/
//记得释放资源
in.close();
out.close();
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*int read(byte[] b):一次读取一个字节数组
返回的int类型的值表示的意思是读取到的字节的个数,如果没有数据了就返回-1*/
public class Demo5_2 {
public static void main(String[] args) throws IOException {
//一次读写一个字节效率不高,一般不采用
//一般我们采用一次读写一个字节数组
FileInputStream in = new FileInputStream("E:\\我的图片和音乐\\疯狂动物城.mp4");
FileOutputStream out = new FileOutputStream("D:\\疯狂动物城.mp4");
//创建一个数组缓冲区
byte[] bytes = new byte[1024];
int len = 0;
while ((len = in.read(bytes)) != -1) {
out.write(bytes);
out.flush();
}
in.close();
out.close();
}
}
通过定义数组读取明显比每次读写一个字节来得快,有个数组来做缓冲区很管用, java想到了这个问题,就提供了 带缓冲区的字节类。
A:缓冲思想
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
这是加入了数组这样的缓冲区效果,java本身在设计的时候,
也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
B:BufferedOutputStream的构造方法
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size)
创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
从构造方法中我们可以知道BufferedInputStream没有无参构造方法,它必须传入一个InputStream(一般是FileInputStream),来一起使用,以提高读写效率。
它只是一个缓冲区,真正的操作还是要靠流来进行,只是用它做个容器。
import java.io.*;
public class Demo5_3 {
public static void main(String[] args) throws IOException {
//BufferedInputStream BufferedOutputStream
//更加高效的字节输入输出流
/*BufferedOutputStream(OutputStream out
*创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
*BufferedOutputStream(OutputStream out, int size)
*创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
* */
BufferedInputStream in = new BufferedInputStream(new FileInputStream("E:\\我的图片和音乐\\疯狂动物城.mp4"));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:\\疯狂动物城.mp4"));
byte[] bytes = new byte[1024 * 8];
int len = 0;
while ((len = in.read(bytes)) != -1) {
out.write(bytes);
out.flush();
}
out.close();
in.close();
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class Demo6 {
public static void main(String[] args) throws IOException {
//一次复制多个文件
FileInputStream in = new FileInputStream("D:\\宇多田ヒカル - Prisoner Of Love.mp3");
FileOutputStream out1 = new FileOutputStream("E:\\宇多田ヒカル - Prisoner Of Love1.mp3");
FileOutputStream out2 = new FileOutputStream("E:\\宇多田ヒカル - Prisoner Of Love2.mp3");
ArrayList<FileOutputStream> list = new ArrayList<>();
list.add(out1);
list.add(out2);
byte[] bytes = new byte[1024 * 8];
int len = 0;
while ((len = in.read(bytes)) != -1) {
for (FileOutputStream outputStream : list) {
outputStream.write(bytes);
outputStream.flush();
}
}
in.close();
out1.close();
out2.close();
}
}