Java学习的第七天:
第五章 输入输出 / io:
5.1 io 流概述:
I/O 流分为很多种,按照操作数据的不同,可以分为字节流和字符流,按照数据传输方 向的不同又可以分为输入流和输出流,程序从输入流中读取数据,向输出流中写入数据。在 I/O 包中,字节流的输入/输出流分别用java.io.InputStream 和javai.o.OutputStream 表示, 字符流的输入/输出流分别用java.io.Reader和java.io.Writer表示,具体分类如图所示。
5.2字节流:
5.2.1字节流的概念:
字节流是指针对字节输入/输出提供的一系列流。在计算机中,无论是文本、图片还是音频和视频,都是以字节的形式存在的,因此要对这些内容进行传输就需要使用字节流。字节流是程序中最常用的流,根据数据传输方向的不同可将其分为字节输入流和字节输出流。 在JDK 中,提供了两个抽象类InputStream 和OutputStream 表示字节输入流和字节输出 流,它们是字节流的两个顶级父类,字节输入流都是InputStream 的子类,字节输出流都是 OutputStream 的子类。
InputStream常用方法
方法声明 | 功能描述 |
---|---|
int read() | 从输入流中读取数据的下一个字节 |
void close() | 关闭此输入流并释放与该流关联的所有系统资源 |
int read(byte[ ] b, int off, int len) | 从输入流中读取若干字节,把它们保存到参数 b指定的字数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节数目。 |
int read(byte[ ] b ) | 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中 |
OutputStream常用方法
方法声明 | 功能描述 |
---|---|
void write() | 将指定字节写入此输出流 |
void write(byte[]b) | 将bl.ength个字节从指定的byte数组写入此输出流 |
void write(byte[]b,int off,int len) | 将指定byte数组中从偏移量off开始的len个字节写入此输出流 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节 |
void close() | 关闭此输出流并释放与此流有关的所有系统资源 |
5.2.2 字节流的读 / 写操作
针对文件的读/写,JDK专门提供了两个类,分别是FileInputStream 和FileOutputStream,它们分别包含了一套所有输入与输出需要使用的方法,可以完成最基本的读取与写出功能。
package com.itheima.example12;
import java.io.*;
public class example12 {
public static void main(String[] args) {
FileInputStream input = null;
try {
input = new FileInputStream("D:/JAVA/java 学习/src/itheima.txt");//使用绝对路径
//使用了try....catch来捕获异常不然会报错,还不懂为什么会这样。
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int i=0;
while(true){
try {
i=input.read();//变量i记住读取的一个字节
} catch (IOException e) {
e.printStackTrace();
}
if(i==-1) break;//结束退出
System.out.println(i);
}
try {
input.close ();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
比较迷惑的是输出应该是到111停止的 不知道为什么又多出了13和10
package com.itheima.examaple13;
import java.io.*;
public class example13 {
public static void main(String[] args) {
FileOutputStream Out= null;
try {
Out = new FileOutputStream("D:/JAVA/java 学习/src/text.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String s="www.itheima.com";
byte [] arr=s.getBytes(); //将字符串s变为字节数组
for(int i=0;i<arr.length;i++){
try {
Out.write(arr[i]);//将将数组中的数据写入文件中
} catch (IOException e) {
e.printStackTrace();
}
}
try {
Out.close();//关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
出现text且在其中出现写入的数组
从运行结果中可以看出,通过 FileOutputStream 写数 据时,自动创建了文件test.txt,并将数据写入文件。需要注 意的是,如果是通过 FileOutputStream 向一个已经存在的 文件中写入数据,那么该文件中的数据首先会被清空,再写 入新的数据。若希望在已存在的文件内容之后增加新内容, 只需要在字节输出流的末尾追加一个参数值true即可。
5.2.3文件的复制:
在应用程序中,通常情况下输入流和输出流都是同时使用的。例如,文件的复制就需要通过输入流读取文件中的数据,通过输出流将数据写入文件。下面通过案例演示如何进行 文件的复制操作
package com.itheima.example14;
import java.io.*;
public class example14 {
public static void main(String[] args) throws Exception{
FileInputStream input=new FileInputStream("source/妹纸.jpg");
FileOutputStream output=new FileOutputStream("target/嘿嘿嘿.jpg");
int length;
long startTime=System.currentTimeMillis();
while((length= input.read())!=-1){
output.write(length);
}
long endTime=System.currentTimeMillis();
System.out.println("复制图片的时间是"+(endTime-startTime)+"毫秒");
input.close();
output.close();
}
}
5.2.4字节流的缓冲区:
5.2.3节中实现了对图片的复制,但是单个字节的读/写效率非常低。为了提高效率,可以定义一个字节数组作为缓冲区。在复制文件时,可以将读取的单个字节保存到字节数组中,然后将字节数组中的数据一次性写入文件。下面通过修改文件5-3学习如何使用字节数组复制文件
package com.itheima.example14;
import java.io.*;
public class example14 {
public static void main(String[] args) throws Exception{
FileInputStream input=new FileInputStream("source/妹纸.jpg");
FileOutputStream output=new FileOutputStream("target/嘿嘿嘿2.jpg");
byte[] buffer=new byte[1024];//定义一个字节数组作为缓冲区
int length; //定义变量length记住读取缓冲区的字节
long startTime=System.currentTimeMillis();
while((length= input.read(buffer))!=-1){//从第一个字节开始向文件写入length个字节
output.write(buffer,0,length);
}
long endTime=System.currentTimeMillis();
System.out.println("复制图片的时间是"+(endTime-startTime)+"毫秒");
input.close();
output.close();
}
}
这次用了20毫秒!(我感觉我电脑不行了。。。。。)
5.2.5字节缓冲流:
在进行文件复制时,使用字节流缓冲区可以提高程序的效率,与此同时,还可以使用 java.io 包中自带缓冲功能的字节缓冲流,它们分别是 BufferedInputStream 和 BufferedOutputStream,这两个流在实例化时需要接收InputStream 和 OutputStream 类型 的对象作为参数。
package com.itheima.example14;
import java.io.*;
public class example14 {
public static void main(String[] args) throws Exception{
BufferedInputStream input=new BufferedInputStream(new FileInputStream("source/妹纸.jpg"));//创建了一个带缓冲区的输入流
BufferedOutputStream output=new BufferedOutputStream(new FileOutputStream("target/嘿嘿嘿3.jpg"));//创建了一个带缓冲区的输出流。
int length;
long startTime=System.currentTimeMillis();
while((length= input.read())!=-1){
output.write(length);
}
long endTime=System.currentTimeMillis();
System.out.println("复制图片的时间是"+(endTime-startTime)+"毫秒");
input.close();
output.close();
}
}
用了50毫秒。
5.3 字符流:
字符流的目标通常是文本文件。Reader和 Writer是 java.io包中所有字符流的抽象父 类,定义了在I/O 流中读/写字符数据的通用 API。在Java中,字符采用的是 Unicode字符 编码,常见的字符输入/输出流是由 Reader和 Writer抽象类派生出来的,处理数据时以字 符为基本单位。
5.3.1 字符流的概念:
前面已经讲解过InputStream 类和 OutputStream 类在读/写文件时操作的都是字节, 如果希望在程序中操作字符,使用这两个类就不太方便,为此,JDK 提供了字符流。同字节 流一样,字符流也有两个抽象的顶级父类,分别是 Reader和 Writer。其中 Reader是字符输 入流,用于从某个源设备读取字符;Writer是字符输出流,用于向某个目标设备写入字符。
代码示例:
package com.itheima.example15;
import java.io.*;
public class example15 {
public static void main(String[] args) throws Exception {
FileReader read=new FileReader("text.txt");
int i;
while((i= read.read())!=-1){
System.out.print((char) i);
}
read.close();
}
}
输出结果:
package com.itheima.example15;
import java.io.*;
public class example15 {
public static void main(String[] args) throws Exception {
FileWriter write=new FileWriter("itheima1.txt");
String s="你好! www.itheima.com";
write.write(s);
write.close();
}
}
结果:
FileWriter同 FileOutputStream 一样,如果指定的 文件不存在,则会先创建文件,再写入数据,如果文件存 在,则会先清空文件中的内容,再进行写入。若希望在 已存在的文件内容之后增加新内容,只需要在字符输出 流的末尾追加一个参数值true即可。
5.3.3 缓冲流:
BufferedReader用于对字符输入流提供缓冲区,BufferedWriter用于对字符输出流提供缓 冲区,需要注意的是,在 BufferedReader中有一个重要的方法readLine(),该方法用于一次 读取一行文本。
使用字符缓冲流实现文本文件的复制
package com.itheima.example16;
import java.io.*;
public class example16 {
public static void main(String[] args) throws Exception {
BufferedReader read=new BufferedReader(new FileReader("itheima1.txt"));
BufferedWriter write=new BufferedWriter(new FileWriter("dest.txt"));
String s=null;
//每次读取一行文本,判断是否到文件末尾
while((s=read.readLine())!=null){
write.write(s);
write.newLine();//写入一个换行符,该方法会根据不同的操作系统生成相应的换行符
}
read.close();
write.close();
}
}
5.3.4 转换流
OutputStreamWriter是Writer的子类,能够将一个字节输出流转换成字符输出流,方便直接写入字符,而InputStreamReader是Reader的子类,能够将一个字节输入流转换成字符输入流,方便直接读取字符。下面通过案例学习如何将字节流转换为字符流,为了提高读/写效率,通过字符缓冲流实现转换的操作
package com.itheima.example16;
import java.io.*;
public class example16 {
public static void main(String[] args) throws Exception {
FileInputStream input= new FileInputStream("itheima1.txt");//创建字节输入流
InputStreamReader streamReader= new InputStreamReader(input);//将字节输入流转换成字符输入流
BufferedReader bufferReader=new BufferedReader(streamReader);//赋予字符输入流对象缓冲区
FileOutputStream outPut= new FileOutputStream("dext2.txt");//创建字节输出流
OutputStreamWriter streamWriter = new OutputStreamWriter(outPut);//将字节输出流转换成字符输出流
BufferedWriter bufferWriter=new BufferedWriter(streamWriter);//赋予字符输出流对象缓冲区
String line= null;
while((line=bufferReader.readLine())!=null){//判断是否读到末尾
//输出读取到的文件
bufferWriter.write(line);
}
bufferReader.close();
bufferWriter.close();
}
}
5.4 File类:
File类用于封装一个路径,这个路径可以指向一个文件,也可以指向一个目录,File类提供了针对这些文件或目录的一些常规操作。
5.4.2遍历目录下的文件:
在程序开发中,经常需要遍历某个指定目录下的所有文件的名称,下面通过案例演示如何利用 File类进行遍历
package com.itheima.example17;
import java.io.*;
public class example17 {
public static void main(String[] args) throws Exception {
File f=new File("E:/迅雷下载/Genshin Impact");
if(f.isDirectory()){ //判断File对象对应的目录是否存在
String [] ss=f.list(); //获得目录下的所有文件的文件名
for(String s: ss){
System.out.println(s); //循环遍历依次输出文件名
}
}
}
}
输出结果:
5.4.3删除文件及目录:
在程序开发中,可能会遇到需要删除指定目录下的某个文件或者删除整个目录的情况, 此时可以通过 File对象的删除方法实现。首先在 C盘的根目录下创建一个名称为hello文 件夹,然后在该文件夹中创建任意数量的Java文件。
运行成功后,观察hello目录下的所有文件,可以发现该目录下的所有Java文件都已经被成功删除。需要注意的是,在使用File对象删除目录时,是从JVM 直接删除而不经过回 收站,因此文件一旦删除则无法恢复。