1、概念
1.IO流用来处理设备与设备之间的数据传输
2.java对数据的操作是通过流的方式
3.java用于操作溜达类都在IO包中
流按流向分为两种:输入流(InputStream)输出流(OutputStream)
按照流的操作类型1分为两种:读和写两种形式
1.字节流:字节流可以分为任何数据,计算机数据都是以字节的形式存储。
2.字符流:字符流中能操作字符数据据,比较方便。
Io流常用父类
字节流的抽象父类
InputStream
OutputStream
字符流的抽象父类
Reader
Writer
IO程序书写
1.使用前:导入IO包中的类
2.使用时:进行IO的异常处理
3.使用后:释放资源
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileInputStream in=new FileInputStream("xxx.txt");
int b;
while((b=in.read())!=-1) {
System.out.println(b);
}
in.close();
}
用int储存流中信息而不是byte
因为字节输入流可以操作任意类型的文件,如图片,音频等等。处理的时候底层都会以二进制形式存储,如果每次读取返回byte,有可能在读到中间的时候遇到8个1在byte底层8个1代表-1,为了避免,用int来存储,int底层会补足到24位,就不会出现返回-1的情况。
练习:从一个文件读出数据在写到另一个文件中,要求让底层自动帮我们创建文件。
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//1.获取到源文件xxx.txt目的是得到他的内容
FileInputStream fis= new FileInputStream("xxx.txt");
//2.把要承载的内容文件相对路径给出,系统会自动帮我们生成yyy.txt(如果没肉)
FileOutputStream fos=new FileOutputStream("yyy.txt",true) ;
//3.定义一个int的容器存储数据
int b;
//4.循环获取xxx.txt里面的内容,现在xxx.txt的对象是fis
while((b=fis.read())!=-1) {
//5,通过循环获得内容直接写入yyy.txt的对象fos
fos.write(b);//补充,在写的过程中,底层会帮我们把补足的0去掉,直接存入的文件中
}
//6.关闭所有管道对象
fis.close();
fos.close();
}
字节数组拷贝之available()方法
int read(byte【】b);一次读一个字节
int write(byte【】b);一次写出一个字节数组
数组加快IO流传输(缓冲区底层)
FileInputStream fis= new FileInputStream("D:\\桌面\\千反田的笑_爱给网_aigei_com.mp4");
FileOutputStream fos=new FileOutputStream("yyy2.mp4") ;
int len=fis.available();
byte[] arr=new byte[2];
fos.write(arr);
while((len=fis.read())!=-1) {
fos.write(len);
}
fis.close();
fos.close();
}
BufferedInputStream和BufferedOutputStream(缓冲区)
1.缓冲思想
字节流一次读写一个数组的速度比一次读写一个字节的速度快很多。
这是加了数组这样缓冲区效果,java本身在设计的时候也考虑到了这样的设计思想,所以提供了字节缓冲区流。
BufferedInputStream
1.内置一个缓冲区(数组)
2.冲缓冲区中读取一个字节时缓冲区会一次性从文件中读取8192个字节,存在缓冲区中,返回给程序一个。
3,缓冲区再次读取的时候,就不需要找文件了,直接从缓冲区获取,直到最后缓冲区不足一个的时候,把剩下的字节放在一个里面。
BufferedOutputStream
1.内置了一个缓冲数组
2.从流中写出字节的时候,不会直接写到文件上,而把数据写到缓冲区中,然后缓冲区一次性把数据给文件。
案例演示:
public class Demo1 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("xxx.txt");
//将流放到缓冲区中
BufferedInputStream bis=new BufferedInputStream(fis);
// BufferedInputStream bis=new BufferedInputStream(new FileInputStream("xxx.txt"));
FileOutputStream fos=new FileOutputStream("yyy.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos);
int b;
while((b=bis.read())!=-1) {
bos.write(b);
}
//尽量不要传中文
bos.write("汪汪汪汪汪".getBytes());
bis.close();
bos.close();
}
}
close和flush区别
flush()方法:用来刷新缓冲区的,刷新后可以再次写出。
close()方法:用来关闭流释放资源,如果带缓冲区的流对象的close方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。
flush可以在不关闭软件,继续传输数据的情况下使用。
close内置flush功能,但是一旦启动就代表着流的关闭和资源的释放,
加密解密
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("yyy2.mp4"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("yyy.mp4"));
int b;
//解密,要写指示说明
while((b=bis.read())!=-1) {
//加密
bos.write(b^123);
}
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("yyy.mp4"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("xxx.mp4"));
int b;
//解密,要写指示说明
while((b=bis.read()^123)!=-1) {
//加密
bos.write(b);
}
}
FileReader字符流
字符类是可以直接写到字符的IO流(计算机存储数据会有转换)
字符流读取字符就要去读取字节数据,然后转换为字符,如果要写出字符,需要把字符转换为字节再输出。
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("xxx.txt");
FileWriter fw=new FileWriter("zzz.txt");
int b;
while((b=fr.read())!=-1) {
fw.write(b);
}
fr.close();
fw.close();
}
FileWriter字符流
FileWriter类的write方法
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("xxx.txt");
FileWriter fw=new FileWriter("zzz.txt");
BufferedReader bfr=new BufferedReader(fr);
BufferedWriter bfw=new BufferedWriter(fw);
int b;
while((b=bfr.read())!=-1) {
bfw.write(b);
}
bfr.close();
bfw.close();
}
什么情况下使用字符流
字符流可以拷贝文件,但是不推荐,因为读取的时候1,先把字节转换为字符 2,写出的时候还会把字符转为字节。
程序读取一段文本,或者需要写出一段文本,这个时候可以使用字符流
读取的时候按照字符的大小读取,不会出现半个中文,写到时候可以直接将字符串写出,不用转换为字节数组。
字符流不可以拷贝非文本的文件
readLine()和newLine()方法
BUfferedReader的readLine方法可以读取一行字符(不包含换行符)
BufferedWriter的newLine()可以输出一个跨平台的换行符号(“|\r\n”)
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr=new FileReader("xxx.txt");
FileWriter fw=new FileWriter("zzz.txt");
BufferedReader bfr=new BufferedReader(fr);
BufferedWriter bfw=new BufferedWriter(fw);
String b;
while((b=bfr.readLine())!=null) {
bfw.write(b);
bfw.newLine();//换行
//bfw.write("\r\n");//只针对windews系统
}
bfr.close();
bfw.close();
}
递归
方法调用方法
如果传入参数过多,内存会溢出。
递归的好处:不用知道循环多少次
弊端:不能调用次数过多,容易出现内存溢出。
构造方法不能调用递归。
练习:需求从键盘录入接收一个文件夹路径,打印出该文件夹下所有.java文件名称。
分析:
1,从键盘录入一个文件夹路径Scanner (获取)
2,判断这个路径是否存在,给个提示(判断)
3.获取文件夹下所有文件和文件夹,存储在FIle数组中。(打印)
4.遍历数组,每一个文件或文件夹(判断)
5.如果是文件,并且后缀是.java,就打印。
6.如果是文件夹,递归调用
public class Demo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File dir=getDir();
printJAVAFile(dir);
}
private static void printJAVAFile(File dir) {
// TODO Auto-generated method stub
//1.获取文件夹中所有文件文件夹存储在File数组中
File[] subFiles=dir.listFiles();
//2.遍历数组,对每一个文件或文件夹做判断
for (File subFile : subFiles) {
if(subFile.isFile()&&subFile.getName().endsWith(".java")) {
System.out.println(subFile);
}else if(subFile.isDirectory()) {
printJAVAFile(subFile);
}
}
}
private static File getDir() {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个绝对路径");
while(true) {
String line=sc.nextLine();
File dir=new File(line);
if(!dir.exists()) {
System.out.println("文件路径有误,请输入正确路径");
}else if(dir.isFile()) {
System.out.println("文件路径有误,请输入正确路径");
}else {
return dir;
}
}
}
}