1 IO介绍
1.1 什么是IO
- input 内存从外界持久化设备中读取数据称为输入;
- output 内存的数据写入到持久化设备中称为输出;
1.2 IO的分类
- 字节流 以字节为单位读取数据,几乎可以读取所有的文件例如:文件,图片,照片…(inputSteam/outputStream);
- 字符流 以字符为单位读取数据,只能读取字符文件;
- 有四个主要的抽象类;
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8b4c081f3eeb8dfe175d20e0c8663f72.png)
2 字节流
2.1 InputSream
- InputSream是字节输入流的父类,是一个抽象类
- 常用方法
方法 | 描述 |
---|
int read() | 读取原始流数据的一个字节,并返回这个字节数,如果已经读取到末端则返回-1 |
int read(byte[ ] byte ) | 读取原始流数据并存储在字节数组中,并返回字节数组的的长度,如果已经读取到末端则返回-1 |
int avaliable( ) | 源文件数据字节的总长度 |
long skip(long a ) | 跳过几个字节读取 |
void close( ) | 关闭流 |
2.2 FileInputStream
- FileInputStream是InputStream子类,文件数据输入流
- 常用的构造方法
方法 | 描述 |
---|
FileInputStream(String path) | 传入文件的地址 |
FileInputStream(File file) | 传入一个文件对象 |
实例 | |
package FileDemo;
import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException {
File file =new File("C:\\Users\\Administrator\\Desktop\\test\\字母.txt");
InputStream inputStream=new FileInputStream(file);
readByte(inputStream);
File file1 =new File("C:\\Users\\Administrator\\Desktop\\test\\背影-朱自清.txt");
InputStream inputStream1=new FileInputStream(file1);
readBytes(inputStream1);
}
//编写一个方法按照一个字节读取文件,不能读取字符因为字符有2-3字节组成,会导致乱码
public static void readByte(InputStream inputStream ) throws IOException {
int a=0;
while((a=(inputStream.read()))!=-1){
System.out.print((char)a);
}
}
//编写一个方法按照一个字节读取文件,不能读取字符因为字符有2-3字节组成,会导致乱码
public static void readBytes(InputStream inputStream ) throws IOException {
int available = inputStream.available();
byte[] a= new byte[available];
while((inputStream.read(a,0,a.length))!=-1){
System.out.print(new String(a,"UTF-8") );
}
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/35a07cca143cd6e3a345154cf0633c19.png)
2.3 OutputStream
- OutputStream字节输出流的父类,是一个抽象方法
- 常用方法
方法 | 描述 |
---|
void write(int b)) | 将指定一个字节写入文件中 |
void write(byte [] byte ) | 将指定的字节数组写入文件中 |
void flush( ) | 当写入数据时,是先把数据放在缓冲区,缓冲区满后写入文件中,就会出现数据已经读取完毕但是 缓冲区的数据还没有满,则需要使用flush强制刷新把数据flush出来 |
void close( ) | 关闭流,释放系统资源 |
2.4 FileoutputStream
- FileoutputStream是outputStream的子类
- 常见的构造方法
方法 | 描述 |
---|
FileoutputStream(String path) | 传入文件的地址 |
FileoutputStream(String path,boolean append) | 传入文件的地址 传入true为追加,反之则为覆盖 |
FileoutputStream(File file) | 传入一个文件对象 |
FileoutputStream(File file,boolean append) | 传入一个文件对象, 传入true为追加,反之则为覆盖 |
示例
package FileDemo;
import java.io.*;
//将朱自清-背影txt文档复制一份
public class FileDemo {
public static void main(String[] args) throws IOException {
//建立文件输入流
InputStream inputStream=new FileInputStream("C:\\Users\\Administrator\\Desktop\\test\\背影-朱自清.txt");
//建立文件输出流
OutputStream outputStream=new FileOutputStream("C:\\Users\\Administrator\\Desktop\\test\\背影-朱自清-复制.tx");
//获取文件的最大字节数
int available = inputStream.available();
//建立存储字节的数组
byte[] bytes=new byte[available];
//读取数据
inputStream.read(bytes,0,bytes.length);
//将数据写入文件
outputStream.write(bytes,0,bytes.length);
//关闭流
inputStream.close();
outputStream.close();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/75477141a7151f2c7cd5ab2e0035423e.png)
2.5 Buffer缓冲字节输入/输出流
2.5.1 什么是buffer缓冲
- buffer 缓冲是内存的一块空间,是内存处理器预留缓冲输入、输出数据的,这块区域就叫做缓冲区
2.5.2 为什么要使用buffer缓冲
- 缓解内存和磁盘的交互,操作磁盘要比内存慢很多,
- 数据处理和数据传输不一致导致的,例如要操作一段数据,每1秒钟要读取磁盘100次,就会浪费大量的时间在读取操作上,如果存入缓冲区内,直接对内存操作,减少了内存和磁盘的操作
2.5.3 缓冲的实现过程
- 当读取/写入数据时,就会把源文件流数据预先存入缓冲区,直接对缓冲区进行操作,如果需要操作的数据超出了取值范围之外就会读取下一段数据继续进行操作;
- 缓冲流默认空间是8k,也可以自己设置
2.5.4 BufferInputStream
常用构造方法
方法 | 描述 |
---|
BufferInputStream(InputStream inputStream ) | 传入一个输入流,缓冲区默认大小是8k |
BufferInputStream(InputStream inputStream ,int size) | 传入一个输入流,以及缓冲区的大小 |
常用方法
方法 | 描述 |
---|
int read() | 读取原始流数据的一个字节,并返回这个字节数,如果已经读取到末端则返回-1 |
int read(byte[] buf,int off,int len); | 读取原始流数据并存储在字节数组中,并返回字节数组的的长度,如果已经读取到末端则返回-1 |
void close( ) | 关闭流,释放资源 |
2.5.5 BufferOutputStream
常用构造方法
方法 | 描述 |
---|
BufferOutputStream(OutputStream outputStream ) | 传入一个输出流,缓冲区默认大小是8k |
BufferOutputStream(OutputStream outputStream ,int size) | 传入一个输出流,以及缓冲区的大小 |
2.5.6 示例
package FileDemo;
import com.sun.istack.internal.localization.NullLocalizable;
import java.io.*;
//使用缓冲流把某个⽬录下的全部文件,全部拷⻉到另外⼀个文件
public class FileDemo {
public static void main(String[] args) throws IOException {
copy("C:\\Users\\Administrator\\Desktop\\test","C:\\Users\\Administrator\\Desktop\\test\\test2");
}
public static void copy(String source ,String goal) throws IOException {
//源文件
File sourceFile=new File(source);
//目标文件
File goalFile=null;
//建立输入流 输入流 缓冲流
InputStream sourceFileinputStream= null;
OutputStream outputStreamgoalFile= null;
BufferedInputStream bufferedInputStream= null;
BufferedOutputStream bufferedOutputStream= null;
File[] files = sourceFile.listFiles();
for (File file:files){
if (file.isFile()){
int a=0;
sourceFileinputStream=new FileInputStream(file);
bufferedInputStream=new BufferedInputStream(sourceFileinputStream);
goalFile=new File(goal,file.getName());
outputStreamgoalFile=new FileOutputStream(goalFile);
bufferedOutputStream =new BufferedOutputStream(outputStreamgoalFile);
byte [] bytes=new byte[1024];
while ((a=bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,bytes.length);
bufferedOutputStream.flush();
}
}
}
sourceFileinputStream.close();
outputStreamgoalFile.close();
bufferedInputStream.close();
bufferedOutputStream.close();
}
}
3 字符流
3.1 Reader
- Reader是字符输入流的父类,字符流只能读取文本
常用方法
方法 | 描述 |
---|
public int read() | 一个字符的一个字符的读取,只能操作文本文件,不能操作图片,视频等 |
public int read(char [] charu ) | 从输入流中读取一段数据,存储到char 数组中,并返回的char数字的长度 |
public int read(char [] charu,int off int lent) | 从输入流中读取一段数据,存储到char 数组中,长度为off 开端,int lent结束,不能超过数组的总长度 |
public void close () | 关闭流,释放系统资源 |
3.2 Writer
Writer是字节输出流的父类
常用的方法
方法 | 描述 |
---|
public void write(int a) | 将整形数字a写入到文件,但不会直接写入文件而是通过asii转换,然后再写入 |
public void write( String a) | 可以字符a直接写入到文件中,不会转化。 |
public abstract void write(char cbuf[], int off, int len) | 将字符数组写入到文件中,长度取决于off和len的值 |
public void flush() | 把缓存区的数据刷到文件中去 |
public void close() | 关闭流,释放系统资源 |
3.3 BufferedReader
- 为了提高单个字符的读写效率,进行批量字符读写,提高字符的读写效率;
- BufferedReader在读取字符数据时,会提前读取字符数据把缓冲区充满,BufferedReader在读取数据在缓冲区读取数据,如果读取的数据超过了范围则从文件中读取下一段数据
构造方法
描述 | 方法 |
---|
BufferedReader(Reader in) | 传入一个字符串 |
BufferedReader(Reader in,int size) | 传入一个文件对象 ,并传入缓冲区的大小值 |
普通方法
方法 | 描述 |
---|
public int read() | 一个字符的一个字符的读取,只能操作文本文件,不能操作图片,视频等 |
public int read(char [] charu ) | 从输入流中读取一段数据,存储到char 数组中,并返回的char数字的长度 |
public int read(char [] charu,int off int lent) | 从输入流中读取一段数据,存储到char 数组中,长度为off 开端,int lent结束,不能超过数组的总长度 |
public int readline() | 读取一行数据,返回字符串,以回车或者换行符为终止,读取完毕返回null |
public void mark(int marks) | 标记一个书签以及限制标记往后最大读取位数 |
public booleanl markSupport( ) | 判断这个流是否支持标记 |
public booleanl reset( ) | 重置流,回到被mark的地方 |
public booleanl ready( ) | 判断这个流是否能被读取,是否以来其他流 |
public void close( ) | 关闭流,释放系统资源 |
long skip(long a ) | 跳过几个字符读取 |
示例1
package FileDemo;
import java.io.*;
public class StreamDemo {
public static void main(String[] args) throws IOException {
//读取整篇文章
Reader reader=new FileReader("C:\\Users\\Administrator\\Desktop\\test\\字母.txt");
BufferedReader bufferedReader=new BufferedReader(reader);
java.lang.String a=null;
while((a=(bufferedReader.readLine()))!=null){
System.out.println(a);
}
reader.close():
bufferedReader.close():
System.out.println("===================================");
}
}
示例2
package FileDemo;
import java.io.*;
public class StreamDemo {
public static void main(String[] args) throws IOException {
//读取整篇文章
Reader reader=new FileReader("C:\\Users\\Administrator\\Desktop\\test\\字母.txt");
BufferedReader bufferedReader=new BufferedReader(reader);
//读取标记2位2次
bufferedReader.mark(2);
char [] charu=new char[10];
bufferedReader.read(charu,0,charu.length);
System.out.println(String.valueOf(charu));
//重置回到原处
bufferedReader.reset();
System.out.println(String.valueOf(charu));
}
}
3.4 BufferedWriter
- BufferedWriter 向文件写入数据,先向缓冲区写入数据,超出缓冲区范围后,再写入到文件种
构造方法
构造方法 | 描述 |
---|
BufferedWriter(Writer writer) | 传入一个字符输入流,使用默认的缓冲区的大小 |
BufferedWriter(Writer writer,int size) | 传入一个字符输入流,并设置缓冲区的大小 |
普通方法
方法 | 描述 |
---|
void writer(int a) | 传入一个整形的参数,写入文件不会直接写入数据,而是进行 asii转换,然后再写入文件 |
void writer(char charu,int off, int len ) | 传入一个字符数组,写入的长度为off到len |
void writer(String a ,int off, int len ) | 传入一个字符串,写入的长度为off到len |
void newline() | 写入到换行符号 |
void flush() | 将缓存区的数据,写入到文件(因为只有超出缓冲区的范围才会写入文件,就会出现文件已经读取完毕了,缓冲区却没有满的情况) |
void close() | 关闭流,释放资源 |
示例
将文件下”朱自清-背影.txt” 复制进入另外一个文件夹
import java.io.*;
public class FileTest {
public static void main(String[] args) throws IOException {
Reader reader =new FileReader("C:\\Users\\14408\\Desktop\\card\\test\\test1\\朱自清-背影.txt");
BufferedReader bufferedReader=new BufferedReader(reader);
Writer writer =new FileWriter("C:\\Users\\14408\\Desktop\\card\\test\\test1\\Directory\\朱自清-背影.txt",false);
BufferedWriter bufferedWriter=new BufferedWriter(writer);
String a=null;
while ((a=(bufferedReader.readLine()))!=null){
bufferedWriter.write(a);
bufferedWriter.newLine();
}
bufferedWriter.flush();
reader.close();
bufferedReader.close();
writer.close();
bufferedWriter.close();
}
}
3.5 InputStreamReader
- 背景:计算机存储的单位是字节,程序内存读取外部持久设备的数据叫做解码,程序内存读取外部持久化设备称为编码
- inputStreamReader是字节输入流转化为字符输出流的桥梁,在解码方式要和编码的方式相同
构造方法
方法 | 描述 |
---|
InputStreamReader(InputStream InputStream ) | 传入一个字节输入流对象,使用默认的编码格式 |
InputStreamReader(InputStream InputStream,String charsetname ) | 传入一个字节输入流对象,使用默认的编码格式 |
普通方法
方法 | 描述 |
---|
public int read() | 读取一个字符 |
public int read( char[] int off,int len ) | 读取一个字符 |
public boolean ready( ) | 判断是否可读 |
public void close( ) | 关闭流,释放资源 |
public String getEncode( ) | 获取流的编码格式 |
示例
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FileTest {
public static void main(String[] args) throws IOException {
InputStream inputStream=new FileInputStream("C:\\Users\\14408\\Desktop\\card\\test\\test1\\Directory\\朱自清-背影.txt");
InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"utf-8");
String encoding = inputStreamReader.getEncoding();
System.out.println(encoding);
System.out.println("====================================");
int size=0;
char[] charu=new char[1024];
while ((size=(inputStreamReader.read(charu)))!=-1){
System.out.println(String.valueOf(charu));
}
inputStream.close();
inputStreamReader.close();
}
}
3.6 OutputStreamWriter
- OutputStreamWriter是字节输出流转化为字符输出流的桥梁,在解码方式要和编码的方式相同
构造方法
方法 | 描述 |
---|
OutputStreamWriter(OutputStream outputStream ) | 传入一个字节输出流对象,使用默认的编码格式 |
OutputStreamWriter(OutputStream outputStream,String charsetname ) | 传入一个字节输出流对象,使用默认的编码格式 |
普通方法
方法 | 描述 |
---|
void write() | 写入单个字符 |
void write(char charu , int off,int len) | 写入一个字符数组 长度为以off为开头,len为结束 |
void write(String a ,int off,int len) | 写入一个字符数组 长度为以off为开头,len为结束 |
void newline() | 写入一个换行符 |
void flush() | 将缓存区的数据,写入到文件(因为只有超出缓冲区的范围才会写入文件,就会出现文件已经读取完毕了,缓冲区却没有满的情况) |
void close() | 关闭流,释放系统资源 |
String getEncode( ) | 获取流的编码格式 |
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Scanner;
public class FileTest {
public static void main(String[] args) throws IOException {
OutputStream outputStream=new FileOutputStream("C:\\Users\\14408\\Desktop\\card\\test\\test1\\Directory\\123.txt");
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(outputStream);
Scanner scanner=new Scanner(System.in);
String next = scanner.next();
outputStreamWriter.write(next);
outputStreamWriter.close();
outputStream.close();
}
}
4 如何处理IO异常
4.1 JDK7以前
import java.io.*;
public class FileTest {
public static void main(String[] args) throws IOException {
BufferedInputStream bufferedInputStream=null;
BufferedOutputStream bufferedOutputStream=null;
try {
FileInputStream fileInputStream=new FileInputStream("");
bufferedInputStream=new BufferedInputStream(fileInputStream);
FileOutputStream fileOutputStream=new FileOutputStream("");
bufferedOutputStream=new BufferedOutputStream(fileOutputStream);
int size=0;
byte[] bytes=new byte[1024];
while((size=bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,size);
}
}catch(Exception e){
e.printStackTrace();
}finally {
if (bufferedOutputStream!=null){
try {
bufferedOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
bufferedInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
};
}
}
}
4.2 JDK7以后
- try with resources处理IO异常;
- 关闭的资源必须实现,Java.lang.autocloseable接口才能被关闭;
- try with resources关闭的顺序是最后一个被定义的资源先关闭;
*** 示例**
package FileDemo;
import com.sun.org.apache.xpath.internal.operations.String;
import java.io.*;
public class FileDemo {
public static void main(String[] args) {
try (
//`定义资源
InputStream inputStream =new FileInputStream("");
BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream);
OutputStream outputStream=new FileOutputStream("");
BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(outputStream);
) {
//定义代码
int size=0;
//定义缓存的数组
byte [] bytes=new byte[1024];
//读取源文件
while((size=bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,size);
}
bufferedOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}