IO 流
IO流的概念
• I/O 即输入Input/ 输出Output的缩写,其实就是计算机调度把各个存储中(包括内存和外部存储)的数据写入写出的过程;
• java中用“流(stream)”来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在java.io这个包里面。
什么是流?
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
IO流的分类
- 从流的方向分类(相较于内存的方向)
- 输入流:只能从中读取数据。把数据从其他设备读取到内存中的流。
- 输出流:只能向其写入数据。把数据从内存中写到其他设备上的流。
- 从流的数据类型分类
- 字节流:以字节为单位,读写数据的流,可以操作任何数据(主要由InputStream和outPutStream作为基类)
- 字符流:以字符为单位,读写数据的流,只能操作纯字符数据,比较方便(主要由Reader和Writer作为基类)
- 按照流的角色划分
- 节点流(低级流):可以从/向一个特定的IO设备(如磁盘,网络)读/写数据的流
- 处理流(高级流):用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能。
- Java语言中的所有字节流都以Stream结尾。所有的字符流都含有Reader或Writer。
- 字节流适合读取:视频,声音,图片等二进制文件
- 字符流适合读取:纯文本文件。
- Java中一个字符占两个字节,即字符流一次读取两个字节,字节流一次读取一个字节。
字节流
字节输出流
OutPutStream
OutPutStream 是一个抽象类,并且是所有字节输出流类的父类,它定义了一些字节输出流的基本共性功能方法。
方法名称 | 功能描述 |
---|---|
public abstract void write(int b) | 将指定的字节输出流 |
public void write(byte b[]) | 将b.length个字节从指定的字节数组写入此输出流 |
public void write(byte b[], int off, int len) | 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。 |
public void flush() | 刷新此输出流并强制任何缓冲的输出字节被写出。 |
public void close() | 关闭并释放与当前输出流相关联的任何系统资源 |
FileOutputStream
构造方法
FileOutputStream(String name) | |
---|---|
FileOutputStream(String name,boolean append) | |
FileOutputStream(File file) | |
FileOutputStream(File file,boolean append) | |
FileOutputStream(FileDescriptor fdObj) |
文件输出流,将数据写出到文件。
- write(int b)
// 1.创建FileOutputStream对象
String fptFilePath = "D:\\fpt.txt";
FileOutputStream fpt = new FileOutputStream(fptFilePath);
// 2. 写入数据
fpt.write(65);
fpt.write(66);
fpt.write(67);
// 3.关闭释放流
fpt.close();
- write(byte b[])
String fptFilePath = "D:\\fpt.txt";
FileOutputStream fpt = new FileOutputStream(fptFilePath);
byte[] bytes = "中文输出".getBytes(Charset.defaultCharset());
fpt.write(bytes);
fpt.close();
- write(byte b[],int offset,int len)
String fptFilePath = "D:\\fpt.txt";
FileOutputStream fpt = new FileOutputStream(fptFilePath);
byte[] bytes = "abcdefg".getBytes();
fpt.write(bytes,1,3);
fpt.close();
追加模式,使用 FileOutputStream(String name,boolean append) 或 FileOutputStream(File file,boolean append)
创建文件输出流对象即可。
String fptFilePath = "D:\\fpt.txt";
FileOutputStream fpt = new FileOutputStream(fptFilePath,true);
fpt.write("追加内容".getBytes());
fpt.close();
字节输入流
InputStream
InputStream 是一个抽象类,并且是字节输入流类的父类,可以读取字节信息到内存中,它定义了字节输入流的基本共性功能方法。
方法名称 | 功能描述 |
---|---|
public abstract int read() | 从输入流中读取数据的下一个字节 |
public int read() | 从输入流中读取一个字节返回int型变量,若到达文件末尾,则返回-1 |
public int read(byte b[]) | 从输入流中读取b.length个字节到字节数组中,返回读入缓冲区的总数,若到达文件末尾,则返回-1 |
public int read(byte b[], int off, int len) | 从输入流中读取最多len个字节到字节数组中(从数组的off位置开始存储字节),当len为0时则返回0,如果len不为0,则该方法将阻塞,直到某些输入可用为止。 |
public void close() | 关闭并释放与此输入流关联的系统资源 |
FileInputStream
FileInputStream 类是文件输入流,从文件中读取字节。
构造方法:
- read() 单个字节读取
String filePath = "D:\\fis.txt";
FileInputStream fis = new FileInputStream(filePath);
int readOne = fis.read();
System.out.println(readOne);
System.out.println((char)readOne);
fis.close();
- read(byte b[]) 字节数组读取
String filePath = "D:\\fis.txt";
FileInputStream fis = new FileInputStream(filePath);
// 1. 定义len
int len;
byte b = new byte[10]; // 字节数组长度为10,每次读取10个字节
// 2.循环读取
while((len=fis.read(b))!=-1){
// 每次读取后,把数组的有效字节部分,变成字符串打印
System.out.println(new String(b,0,len)); //读取有效值,防止重复读取
}
fis.close();
- read(byte b[],int off,int len) 字节数组读取(指定读取起始点)
String filePath = "D:\\fis.txt";
FileInputStream fis = new FileInputStream(filePath);
byte[] b = new byte[10];
int len;
while ((len = fis.read(b,0,10))!=-1){
System.out.println(new String(b,0,len));
}
文件拷贝,图片音视频复制
public static void copyVideoImage(String targetFilePath,String optFilePath) throws IOException {
// 1.创建FileInputStream对象和FileOutputStream对象
FileInputStream fis = new FileInputStream(targetFilePath);
FileOutputStream fos = new FileOutputStream(optFilePath);
// 2.读取设置
int len; // 长度
byte b[] = new byte[1024]; // 每次读取1024字节
// 3.循环读取和写入
while ((len=fis.read(b))!=-1){
// 每次读取1024个字节到数组中,并且返回此次读入的长度
fos.write(b,0,len); // 写出从索引0开始的len个字节
}
// 4.关闭输入流和输出流
fis.close();
fos.close();
// 5.
System.out.println("copy完毕");
}
public static void main(String[] args) throws IOException {
// 文件源目录
String filePath = "C:\\Users\\robin\\Desktop\\项目资源文件\\音视频文件\\steamin使用教程.mp4";
//文件拷贝目录
String optFilePath = "C:\\Users\\robin\\Desktop\\项目资源文件\\音视频文件\\steamin拷贝.mp4";
copyVideoImage(filePath,optFilePath);
}
字符流
字符流本质就是基于字节流读取时,去查了指定的码表,而字节流之间读取数据会有乱码问题(常见的中文乱码)。
FileInputStream 读取文本文件,会出现中文乱码
public static void main(String[] args) throws IOException {
String filePath = "D:\\1.txt";
FileInputStream fis = new FileInputStream(filePath);
int len;
byte b[] = new byte[4];
while((len=fis.read(b))!=-1){
System.out.println(new String(b));
}
}
字符输入流
Reader
Reader是一个抽象类,是字符输入流类的父类,可以读取字符信息到内存中,它定义了字符输入流的基本共性功能方法。
public void close() | 关闭此流并释放资源 |
---|---|
public void read() | 从输入流读取一个字符 |
public int read(char[] cbuf) | 从输入流中读取一些字符,并将它们存储到字符数组 cbuf 中 |
FileReader
FileRead类是读取字符文件的一个类。构造时使用系统默认的字符编码和默认字节缓冲区。
String filePath = "D:\\1.txt";
FileReader fileReader = new FileReader(filePath);
int len ; // 用来记录每次读取的字符,并且用于判断文件是否读到了文件末尾
while ((len= fileReader.read())!=-1){
System.out.println((char)len);
}
fileReader.close()
字符输出流
Writer
Writer是一个抽象类,并且是所有字符输出流类的父类,将指定的字符信息写到目的文件中。同样的,定义了字符输出流的基本共性功能方法。
void write(int c) | 写入单个字符 |
---|---|
void write(char[] cbuf) | 写入字符数组 |
abstract void write(char[] cbuf,int off,int len) | 写入字符数组的某一部分,off数组的开始索引,len写的字符个数 |
void write(String str) | 写入字符串 |
void write(String str,int off,int len) | 写入字符串的某一部分,off表示字符串的开始索引,len表示写的字符个数 |
void flush() | 刷新该流的缓冲 |
void close() | 先刷新,再关闭此流 |
FileWriter
write(int b),每次写出一个字符数据
// 字符输出流
String filePath = "D:\\writer.txt";
FileWriter fw =null;
try{
fw = new FileWriter(filePath);
fw.write('c');
fw.write("知更鸟");
fw.write("robin");
}catch (IOException e){
System.out.println(e.getMessage());
}finally {
try {
if(fw!=null){
fw.close();
}
}catch (IOException e){
System.out.println(e.getMessage());
}
}
注意,使用FileWriter时,一定要记得流的关闭或者是刷新,因为如果不关闭的话,数据只是保存到缓冲区,而不是文件,这一点与FileOutputStream不同。
关闭close和刷新flush
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。
flush :刷新缓冲区,流对象可以继续使用。
close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
文本文件复制
public static void main(String[] args) {
// 文件源目录和目的目录
String filePath = "D:\\reader.txt";
String optFilePath = "D:\\writer.txt";
copyTxt(filePath,optFilePath);
}
public static void copyTxt(String sourceFilePath,String targetFilePath){
// 1.创建FileReader对象和FileWriter对象
FileReader reader = null;
FileWriter writer = null;
// 2.规范一点try catch
try {
reader = new FileReader(sourceFilePath);
writer = new FileWriter(targetFilePath);
// 3. 开始循环读取写入数据
char cbuf[] = new char[1024];
int len;
while ((len = reader.read(cbuf))!=-1){
writer.write(cbuf,0,len); // 将cbuf写入到wirter中,每次从cbuf数组的0索引开始写入,并且写入Len个字符(len刚好是每次读取的字符数)
}
}catch (IOException e){
System.out.println(e.getMessage());
}finally {
try {
// 4.判断字符流对象是否为空,然后释放资源
if(reader!=null){
reader.close();
}
if(writer!=null){
writer.close();
}
}catch (IOException e){
System.out.println(e.getMessage());
}
}
}
小结
- Java语言中的所有字节流都以Stream结尾。所有的字符流都含有Reader或Writer。
- 字节流适合读取:视频,声音,图片等二进制文件
- 字符流适合读取:纯文本文件。
- Java中一个字符占两个字节,即字符流一次读取两个字节,字节流一次读取一个字节。