IO简介
输入(Input):可以让程序从外部系统获得数据(核心含义是"读",读取外部数据)。
输出(Output):程序输出数据给外部系统从而可以操作外部系统(核心含义是“写”,将数据写出到外部系统)。
数据源
数据源Data Source,提供数据的原始媒介。
常见的数据源有:数据库、文件、其他程序、内存、网络连接、IO设备。
数据源分为:源设备、目标设备。
【源设备】为程序提供数据,一般对应输入流。
【目标设备】程序数据的目的地,一般对应输出流。
流
流是一个抽象、动态的概念,是一连串连续动态的数据集合。
输入/输出流的划分是相对【程序】而言的,并不是相对数据源。
JAVA中的四大抽象类
InputStream/OutputStream和Reader/Writer类是所有IO流类的抽象父类。
【lnputStream】
- 此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。数据的读取需要由它的子类来实现。
- 根据节点的不同,它派生了不同的节点流子类。继承自InputSteam的流都是用于向程序中输入数据,数据的单位为字节(8 bit)。
常用方法:
int read():读取一个字节的数据,并将字节的值作为int类型返回(0-255)。如果未读出字节则返回-1(返回值为-1表示读取结束)。
void close():关闭输入流对象,释放相关系统资源。
【OutputStream】
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
常用方法:
void write(int n):向目的地中写入一个字节。
void close():关闭输出流对象,释放相关系统资源。
【Reader】
Reader用于读取的字符流抽象类,数据单位为字符。
int read(): 读取一个字符的数据,并将字符的值作为int类型返回(0-65535,即Unicode值)。如果未读出字符则返回-1(返回值
为-1表示读取结束)。
void close() :关闭流对象,释放相关系统资源。
【Writer】
Writer用于输出的字符流抽象类,数据单位为字符。
void write(int n):向输出流中写入一个字符。
void close() :关闭输出流对象,释放相关系统资源。
JAVA中流的概念细分
按流的方向分类:输入流、输出流
输入流:数据流从数据源到程序(以InputStream、Reader结尾的流)。
输出流:数据流从程序到目的地(以OutputStream、Writer结尾的流)。
按处理的数据单元分类:字节流、字符流
字节流:以字节为单位获取数据,命名上以stream结尾的流一般是字节流,如FilelnputStream、FileOutputStream。
字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。
按处理的对象分类:节点流、处理流
节点流:可以直接从数据源或目的地读写数据,如 FilelnputStream、FileReader.DatalnputStream等。
处理流:不直接连接到数据源或目的地,是”处理流的流"。通过对其他流的处理提高程序的性能,如 BufferedInputStream、
BufferedReader等。处理流也叫包装流。
节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。
详细说明
-
InputStream/OutputStream
字节流的抽象类。 -
Reader/Writer
字符流的抽象类。 -
FilelnputStream/FileOutputStream
节点流:以字节为单位直接操作“文件”。 -
ByteArraylnputStream/ByteArrayOutputStream
节点流:以字节为单位直接操作“字节数组对象”。 -
ObjectlnputStream/ObjectOutputStream
处理流:以字节为单位直接操作“对象”。 -
DatalnputStream/DataOutputStream
处理流:以字节为单位直接操作“基本数据类型与字符串类型”。
-
FileReader/FileWriter
节点流:以字符为单位直接操作“文本文件”(注意:只能读写文本文件)。
-
BufferedReader/BufferedWriter
处理流:将Reader/Writer对象进行包装,增加缓存功能,提高读写效率。 -
BufferedInputStream/BufferedOutputStream
-
处理流:将InputStream/OutputStream对象进行包装,增加缓存功能,提高读写效率。
-
InputStreamReader/OutputStreamWriter
处理流:将字节流对象转化成字符流对象。 -
PrintStream
处理流:将OutputStream进行包装,可以方便地输出字符,更加灵活。
IO流入门案例
public static void main(String[] args) {
FileInputStream file = null;
try{
//创建字节输入流对象
file = new FileInputStream("E:/a.txt");
int s1 = file.read();//打印输入字符a对应的ascci码值97(不跳过空格)
int s2 = file.read();//打印输入字符b对应的ascci码值98
int s3 = file.read();//打印输入字符c对应的ascci码值99
int s4 = file.read();//由于文件内容已读取完毕,返回-1
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
}catch(Exception e){
e.printStackTrace();
}finally{
if (file != null){
try{
file.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
优化
public static void main(String[] args) {
FileInputStream file = null;
try{
//创建字节流输入对象
file = new FileInputStream("E:/a.txt");
StringBuilder strb = new StringBuilder();
int temp = 0;
while((temp = file.read())!= -1){
System.out.println(temp);
strb.append((char) temp);
}
System.out.println(strb.toString());
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (file != null){
file.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
File类简介
File类是Java提供的针对磁盘中的文件或目录转换对象的包装类。一个File对象而可以代表一个文件或目录,File对象可以实现获取文件和
目录属性等功能,可以实现对文件和目录的创建,删除等功能。
【针对文件操作的方法】
- createNewFile() 创建新文件
- delete() 直接从磁盘上删除
- exists() 查询磁盘中的文件是否存在
- getAbsolutePath() 获取绝对路径
- isFile() 判断是否是文件
- length() 查看文件中的字节数
- isHidden() 测试文件是否被这个抽象路径名是一个隐藏文件
【针对目录操作的方法】
- exists() 查询目录是否存在
- isDirectory() 判断当前路径是否为目录
- mkdir() 创建目录
- getParentFile() 获取当前目录的父级目录
- list() 返回一个字符串数组,包含目录中的文件和目录的路径名
- listFiles() 返回一个File 数组,表示用此抽象路径名表示的目录中的文件
#### File类的基本使用
操作文件
public static void main(String[] args) throws Exception{
//创建file对象
File file = new File("E:/aa.txt");
//返回true表示创建成功,如第二次运行由于已存在会创建失败,返回false
System.out.println(file.createNewFile());
//返回true表示删除文件成功
System.out.println(file.delete());
//返回true表示存在该文件
System.out.println(file.exists());
System.out.println(file.getName());
System.out.println(file.isFile());
System.out.println(file.isHidden());
}
操作目录
System.out.println("-------------------操作目录-------------------");
File file1 = new File("E:/123/456/789");
/*//创建一级目录
System.out.println(file1.mkdir());
//创建多级目录
System.out.println(file1.mkdirs());
System.out.println(file1.exists());
System.out.println(file1.isFile());
System.out.println(file1.isDirectory());
System.out.println(file1.getParent());
System.out.println(file1.getParentFile());
System.out.println(file1.getParentFile().getName());
System.out.println(file1.list());*/
System.out.println("-----------------查看所有子目录---------------");
File file2 = new File("E:/");
String[] files = file2.list();
for (String fil:files){
System.out.println(fil);
}
System.out.println("---查看所有子目录(带绝对路径)--");
File[] files1 = file2.listFiles();
for (File fil1:files1){
System.out.println(fil1);
}
常用流对象
文件字节流
FilelnputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。Java也提供了FileReader专门读取文
本文件。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。Java也提供了FileWriter专门写入文本文件。
文件字节输入流
public static void main(String[] args) {
FileInputStream fis = null;
try{//定义文件字节输入流对象
fis = new FileInputStream("E:/tiger.jpg");
int temp = 0;
while((temp = fis.read()) != -1){
System.out.println(temp);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (fis != null){
fis.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
文件字节输入流
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try{//创建文件字节输入流对象
fis = new FileInputStream("E:/tiger.jpg");
//创建文件字节输出流对象
fos = new FileOutputStream("E:/aa.jpg");
int temp = 0;
while((temp = fis.read()) != -1){
fos.write(temp);
}
//将数据从内存中写入到磁盘中(读一个字节写一个字节)
fos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (fis != null){
fis.close();
}
if (fos != null){
fos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
通过缓冲区提高读写效率
【用袋子背大米】
方式一
通过创建一个指定长度的字节数组作为缓冲区,以此来提高IO流的读写效率。该方式适用于读取较大图片时的缓冲区定义。
【注意】缓冲区的长度一定是2的整数幂。一般情况下1024长度较为合适。
public static void main(String[] args) {
long nowNum = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try{//创建文件字节输入流对象
fis = new FileInputStream("E:/tiger.jpg");
//创建文件字节输出流对象
fos = new FileOutputStream("E:/aa.jpg");
//创建缓冲区,提高读写效率
byte[] buff = new byte[1024];
int temp = 0;
while((temp = fis.read(buff)) != -1){
fos.write(buff,0,temp);
}
//将数据从内存中写入到磁盘中(读一个字节写一个字节)
fos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (fis != null){
fis.close();
}
if (fos != null){
fos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
long nowNum1 = System.currentTimeMillis();
System.out.println((nowNum1-nowNum)/1000);//0s,优化前耗时约9s
}
方式二
通过创建一个字节数组作为缓冲区,数组长度是通过输入流对象的available()返回当前文件的预估长度来定义的。在读写文件时,是在一
次读写操作中完成文件读写操作的。
【注意】如果文件过大,那么对内存的占用也是比较大的。所以大文件不建议使用该方法。
public static void main(String[] args) {
long nowNum = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try{//创建文件字节输入流对象
fis = new FileInputStream("E:/tiger.jpg");
//创建文件字节输出流对象
fos = new FileOutputStream("E:/cc.jpg");
//创建缓冲区,提高读写效率
byte[] buff = new byte[fis.available()];
fis.read(buff);
//将数据从内存中写入到磁盘中(读一个字节写一个字节)
fos.write(buff);
fos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (fis != null){
fis.close();
}
if (fos != null){
fos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
long nowNum1 = System.currentTimeMillis();
System.out.println((nowNum1-nowNum)/1000);//0s
}
通过字节缓冲流提高读写效率
- Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。
- 当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。
- BufferedInputStream和BufferedOutputStream这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。
public static void main(String[] args) {
long nowNum = System.currentTimeMillis();
FileInputStream fis =null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
fis = new FileInputStream("E:/tiger.jpg");
bis = new BufferedInputStream(fis);
fos = new FileOutputStream("E:/dd.jpg");
bos = new BufferedOutputStream(fos);
//缓冲流中的byte数组【长度默认是8192】
int temp = 0;
while((temp = bis.read()) != -1){
bos.write(temp);
}
bos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
//注意:关闭流的顺序:“后开先关”
if(bis != null){
fis.close();
}
if(fis != null){
fis.close();
}
if(bos != null){
bos.close();
}
if(fos != null){
fos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
long nowNum1 = System.currentTimeMillis();
System.out.println((nowNum1-nowNum)/1000);//0s
}
定义文件拷贝工具类
public static void copyFile(String source,String destination){
FileInputStream fis = null;
BufferedInputStream bis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try{
// fis = new FileInputStream(source);
bis = new BufferedInputStream(new FileInputStream(source));
// fos = new FileOutputStream(destination);
bos = new BufferedOutputStream(new FileOutputStream(destination));
int temp = 0;
while((temp = bis.read()) != -1){
bos.write(temp);
}
bos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(bis != null){
bis.close();
}
if(fis != null){
fis.close();
}
if(bos != null){
bos.close();
}
if(fos != null){
fos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}