首页 >> 大全

Java的 io流

2023-07-07 大全 36 作者:考证青年

目录 字节输入流的基本用法() 练习-文件拷贝 io流中不同JDK版本捕获异常的方式(了解)字符集详解 字符流 综合练习 高级流 转换流 序列化流 打印流 解压缩流/压缩流 常用工具包

io流的概述和分类

在使用IO流时,什么时候用就什么时候创建,什么时候不用就什么时候关闭

IO流:存储和读取数据的解决方案

就比如游戏的存档,需要两个知识点:文件的位置,信息的传输

注意,File类只能对文件本身进行操作,不能读写文件里的数据,所以需要学习io流,用于读写文件中的数据(可以读写文件,或网络中的数据)

io流可以把程序中的数据保存到文件中,也就是写出()数据,还可以把文件中的数据加载到程序中,就是读取(input)数据。

以程序为参照物看读写的方向,是程序在读取或写出数据

纯文本文件:用记事本能看懂的文件

io流的体系

基本流

字节流 字节输出流基本用法() 字节输出流写出数据的细节 字节输出流写出数据的三种方式 方法名说明

void write(int b)

一次写一个字节数据

void write(byte[ ] b)

一次写一个字节数组数据

void write(byte[ ] b,int off,int len)

一次写一个字节数组的部分数据

    public static void main(String[] args) throws IOException {FileOutputStream fos=new FileOutputStream("D:\\我的世界\\a1.txt");//一次写一个fos.write(97);//a//一次写多个byte[]arr={97,98,99,100,101};//aabcdefos.write(arr);//一次写一个数组的一部分// void write(byte[ ] b,int off,int len)//这里的三个参数分别表示为://参数1:代表数组//参数2:代表截取的起始索引,截取时包括起始索引//参数3:代表截取元素的个数fos.write(arr,2,2);//释放资源fos.close();}

字节输出流写出数据的两个问题

写之前先了解一个字符串的方法

,可以把字符串转化为一个byte类型的数组

使用这个方法可以很方便的把一些文字写入文件中

    public static void main(String[] args) throws IOException {FileOutputStream fos=new FileOutputStream("D:\\我的世界\\a1.txt");String s="laoyangzuihaokan";byte[] bytes = s.getBytes();fos.write(bytes);}

换行写和续写

在java中写单独的\r或\n也是可以的,java会自动补全,但是不推荐单独写

    public static void main(String[] args) throws IOException {FileOutputStream fos=new FileOutputStream("D:\\我的世界\\a1.txt");String s1="laoyangzuihaokan";byte[] bytes1 = s1.getBytes();fos.write(bytes1);String s2="\r\n";byte[] bytes2 = s2.getBytes();fos.write(bytes2);String s3="olhhg";byte[] bytes3 = s3.getBytes();fos.write(bytes3);fos.close();//laoyangzuihaokan//olhhg}

    public static void main(String[] args) throws IOException {FileOutputStream fos=new FileOutputStream("D:\\我的世界\\a1.txt",true);String s1="laoyangzuihaokan";byte[] bytes1 = s1.getBytes();fos.write(bytes1);String s2="\r\n";byte[] bytes2 = s2.getBytes();fos.write(bytes2);String s3="olhhg";byte[] bytes3 = s3.getBytes();fos.write(bytes3);fos.close();//运行两次后//laoyangzuihaokan//olhhglaoyangzuihaokan//olhhg}

字节输入流的基本用法() 字节输入流读取数据的细节 字节输入流循环读取

    public static void main(String[] args) throws IOException {//创建对象//a1.txt的数据abcdeaadsadhasdbajhvabdbaiyFileInputStream fis=new FileInputStream("D:\\我的世界\\a1.txt");//循环读取int b;// 赋值很重要,可以用它读取数据while ((b=fis.read())!=-1){//这一步判断数据是否读到末尾System.out.print((char) b);}//abcdeaadsadhasdbajhvabdbaiy}

练习-文件拷贝

注意,这次是小文件的拷贝

    public static void main(String[] args) throws IOException {//负责原文件的读取FileInputStream fis=new FileInputStream("D:\\我的世界\\a1.txt");//负责copy文件的写出FileOutputStream fos=new FileOutputStream("D:\\我的世界\\copy.txt");int b;//记录读取内容//边读边写while ((b=fis.read())!=-1){fos.write(b);}fos.close();fis.close();}

    public static void main(String[] args) throws IOException {//负责原文件的读取FileInputStream fis=new FileInputStream("D:\\我的世界\\页面返回顶部.mp4");//负责copy文件的写出FileOutputStream fos=new FileOutputStream("D:\\我的世界\\copy.mp4");int b;//记录读取内容//边读边写long l1 = System.currentTimeMillis();while ((b=fis.read())!=-1){fos.write(b);}fos.close();fis.close();long l2=System.currentTimeMillis();System.out.println(l2-l1);}

字节输入流一次读取多个字节 方法名说明

int read()

一次读取一个字节数据

int read(byte[ ] )

一次读取一个字节数组数据

注意:一次读取一个字节数组的数据,每次读取会尽可能把数组装满

所以,在创建字节数组时,一般会用1024的整数倍

1024 * 1024 * 5就是5M

    public static void main(String[] args) throws IOException {//a1.txt:abcdeFileInputStream fis=new FileInputStream("D:\\我的世界\\a1.txt");byte[] arr=new byte[2];//长度为2的数组,用read读取时一次可以读取两个//读取的返回值:本次读取到了多少个字节数据int read = fis.read(arr);System.out.println(read);//而且,read用数组读取会把本次读取到的数据放到数组中String str=new String(arr);System.out.println(str);//2//abfis.close();//第二次读取便会依次向后读取两个数据,跟read没有参数时一样//结果是//2//cd//第三次读取的结果是//1//ed,因为第三次读取的时候只剩一个数据未读取,//而read方法在读取时会把数据放到数组中,每次读取都会覆盖原本的数据//所以第三次读取时只读取一个,也就只覆盖一个数据,第二个没有覆盖//也就是 ed}

e覆盖掉c,后面没有数据,所以d没有被覆盖

解决方案:

使用new 时,传递三个参数,第一个表示数组,第二个表示起始索引,第三个表示结束索引,然后会起始索引截取到结束索引

new (arr,0,len)

    public static void main(String[] args) throws IOException {//a1.txt:abcdeFileInputStream fis=new FileInputStream("D:\\我的世界\\a1.txt");byte[] arr=new byte[2];//长度为2的数组,用read读取时一次可以读取两个//读取的返回值:本次读取到了多少个字节数据int read1 = fis.read(arr);System.out.println(read1);//而且,read用数组读取会把本次读取到的数据放到数组中String str1=new String(arr,0,read1);System.out.println(str1);//2//ab//第二次读取便会依次向后读取两个数据,跟read没有参数时一样int read2 = fis.read(arr);System.out.println(read2);String str2=new String(arr,0,read2);System.out.println(str2);//结果是//2//cd//第三次读取的结果是int read3 = fis.read(arr);System.out.println(read3);String str3=new String(arr,0,read3);System.out.println(str3);//1//ed,因为第三次读取的时候只剩一个数据未读取,//而read方法在读取时会把数据放到数组中,每次读取都会覆盖原本的数据//所以第三次读取时只读取一个,也就只覆盖一个数据,第二个没有覆盖//也就是 edfis.close();}

    public static void main(String[] args) throws IOException {//负责原文件的读取FileInputStream fis=new FileInputStream("D:\\我的世界\\页面返回顶部.mp4");//负责copy文件的写出FileOutputStream fos=new FileOutputStream("D:\\我的世界\\copy.mp4");int b;//记录读取长度//边读边写long l1 = System.currentTimeMillis();byte[]arr=new byte[1024*1024];while ((b=fis.read(arr))!=-1){//此时每一次读取的数据在数组中fos.write(arr,0,b);//这里最后一次读取可以装不满数组,// 所以要用三个参数,表示上面有多少,就写入多少}fos.close();fis.close();long l2=System.currentTimeMillis();System.out.println(l2-l1);}

io流中不同JDK版本捕获异常的方式(了解)

捕获异常的新格式:

try{语句..
}catch{语句..
}finally{语句..(这里的代码一定会执行,除非虚拟机停止)
}

的特点:的代码一定被执行,除非虚拟机停止

比如说:

try里的代码没有异常,那么try执行后就会执行的代码,但是try里出现了异常,try停止执行,catch执行后,里的代码执行

这样可以使io流一定能够释放资源

异常在以后的开发中都是抛出处理的

    public static void main(String[] args)  {FileInputStream fis=null;FileOutputStream fos=null;try {//负责原文件的读取fis=new FileInputStream("D:\\我的世界\\页面返回顶部.mp4");//负责copy文件的写出fos=new FileOutputStream("D:\\我的世界\\copy.mp4");int b;//记录读取内容//边读边写byte[]arr=new byte[1024*1024];while ((b=fis.read(arr))!=-1){//此时每一次读取的数据在数组中fos.write(arr,0,b);//这里最后一次读取可以装不满数组,// 所以要用三个参数,表示上面都多少,就写入多少}} catch (IOException e) {throw new RuntimeException(e);} finally {//由于fos和fis都是try大括号里的局部变量,//所以fos和fis的定义要放在try的外面if(fos!=null){try {fos.close();//这里的close还是有异常,用try catch包裹} catch (IOException e) {throw new RuntimeException(e);}}if (fis!=null) {try {fis.close();} catch (IOException e) {throw new RuntimeException(e);}}}}

try(创建流对象1;创建流对象2){//只有实现AutoCloseable接口的类才能这样写	可能出现的异常代码;
}catch(异常类名 变量名){异常的处理代码;
}catch执行完毕后,小括号里的流就会自动释放资源

创建流对象1;
创建流对象2;
try(1;2){可能出现的异常代码;
}catch(异常类名 变量名){异常的处理代码;
}

例子:

//jdk7public static void main(String[] args) {try (FileInputStream fis=new FileInputStream("D:\\我的世界\\页面返回顶部.mp4");FileOutputStream fos=new FileOutputStream("D:\\我的世界\\copy.mp4")){int b;//记录读取内容//边读边写byte[]arr=new byte[1024*1024];while ((b=fis.read(arr))!=-1){//此时每一次读取的数据在数组中fos.write(arr,0,b);//这里最后一次读取可以装不满数组,// 所以要用三个参数,表示上面都多少,就写入多少}} catch (IOException e) {e.printStackTrace();}}
//jdk9 public static void main(String[] args) throws FileNotFoundException {FileOutputStream fos=new FileOutputStream("D:\\我的世界\\copy.mp4");FileInputStream fis=new FileInputStream("D:\\我的世界\\页面返回顶部.mp4");try (fis;fos){int b;//记录读取内容//边读边写byte[]arr=new byte[1024*1024];while ((b=fis.read(arr))!=-1){//此时每一次读取的数据在数组中fos.write(arr,0,b);//这里最后一次读取可以装不满数组,// 所以要用三个参数,表示上面都多少,就写入多少}} catch (IOException e) {e.printStackTrace();}}  

字符集详解

字节流读取中文会出现乱码

ASCII字符集

0-127,一共128个字符

例如,存英文a时,先查询对应的ASCII表,得到对应值,然后转化为数字

a->97->110 0001,在前面加一个0就是八位二进制,就代表一个字节(这步是编码)

0110 0001,然后存这个二进制值存进电脑

ASCII的解码规则:

直接把二进制数转成10进制

GBK字符集

系统显示为ANSI

如果查询英文,可以直接按照ASCII来查,因为GBK完全兼容ASCII

:万国码

为什么会有乱码?

原因1:因为字节流一次只能读取一个字节,而一个中文由三个字节组成,所以读取时会产生乱码

原因2:比如说,在编码时用,但在解码时可能用的是GBK

Java中编码和解码的代码实现 方法名说明

byte[ ] ()

使用默认方式进行编码(ieda默认用UTF-8,默认使用gbk)

byte[ ] ( )

使用指定方式进行编码

方法名说明

(byte[ ] bytes)

使用默认方式进行解码

(byte[ ] bytes, )

使用指定方式进行解码

    public static void main(String[] args) throws UnsupportedEncodingException {//编码String str="ox欧肖";//默认方式byte[] bytes1 = str.getBytes();//指定方式byte[] bytes2 = str.getBytes("GBK");System.out.println(Arrays.toString(bytes1));System.out.println(Arrays.toString(bytes2));//[111, 120, -26, -84, -89, -24, -126, -106]//[111, 120, -59, -73, -48, -92]//解码//默认方式解码String str2=new String(bytes1);//使用指定方式解码,如果编码与解码不同,就会出现乱码String str3=new String(bytes1,"GBK");String str4=new String(bytes2,"GBK");System.out.println(str2);System.out.println(str3);System.out.println(str4);//ox欧肖//ox娆ц倴//ox欧肖}

字符流

字符流的底层就是字节流

字符流=字节流+字符集

字符流使用场景:对于纯文本文件进行读写操作

(字符输入流)

1.创建字符输入流对象(构造方法)

方法名说明

(File file)

创建字符输入流关联本地文件

( )

创建字符输入流关联本地文件

注意:读取的文件不存在会直接报错

2.读取数据(成员方法)

方法名说明

int read()

读取数据,读到末尾返回-1

int read(char[ ] )

读取多个数据,读到末尾返回-1

注意:

1.按字节进行读取,遇到中文,一次读多个字节,读取后编码,返回一个整数

2. 读到文件末尾了,read方法返回-1

3.释放资源

还是close方法

    public static void main(String[] args) throws IOException {//空参的read方法File file=new File("D:\\我的世界\\a1.txt");FileReader reader1=new FileReader(file);//file对象的形式传递FileReader reader2=new FileReader("D:\\我的世界\\a1.txt");//字符串的形式传递int ch ;//字符流的read方法也是一个一个的读取字节,遇到中文一次读取多个//在底层会进行解码把读取到的数据转成10进制并且返回//这个返回的数据就是字符集上对应的10进制数字//如果想看到中文就用(char)强转就行了while ((ch=reader1.read())!=-1){System.out.print((char)ch);}reader1.close();//殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》//带参的read方法 read(char[] buffer)//带参的read方法将读取数据,解码,强转数据进行合并//将强转得到的字符都放到数组中//带参的返回值还是读取的元素个数char[]arr=new char[2];//表示一次读取两个数据int len;//表示当前读到了第几个while((len=reader2.read(arr))!=-1){//这里的new String可以把数组里的元素转成字符串//第二个参数是要开始转化的起始索引,第三个参数就是终止索引System.out.print(new String(arr,0,len));}//殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》}

(字符输出流) 方法名说明

(File file)

创建字符输出流关联本地文件

( )

创建字符输出流关联本地文件

(File file, )

创建字符输出流关联本地文件,续写

( , )

创建字符输出流关联本地文件,续写

前两种方式是默认关闭续写的,即如果在创建对象时文件内存在数据,会先清空文件内的数据再写,

后面的方式可以打开续写开关,true就是打开续写开关

方法名说明

void write(int c)

写出一个字符

void

写出一个字符串

void write( str,int off,int len)

写出一个字符串的一部分

void write(char[ ] cbuf)

写出一个字符数组

void write(char[ ] cbuf,int off,int len)

写出字符数组的一部分

注意:

    public static void main(String[] args) throws IOException {//参数为true,表示打开续写,默认为false,即关闭续写//殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》是a1.txt文件的内容FileWriter f1=new FileWriter("D:\\我的世界\\a1.txt",true);FileWriter f2=new FileWriter(new File("D:\\我的世界\\a1.txt"),true);//write(int c)//注意字节输出流和字符输出流的区别//字节输出流一次只能写入一个字节//字符输出流一次可以写入多个字节//写入到文件里的是字符集上对应的整数f1.write(25105);//这里是汉字 我 ,在Unicode中三个字节,所以在字节输出流中写不了//write(String str)f1.write("\r\n何日功成名遂了,还乡,醉笑陪公三万场。");//write(String str,int off,int len)f1.write("\r\n何日功成名遂了,还乡,醉笑陪公三万场。",0,9);//write(char[ ] cbuf)char []chars={'\r','\n','1','2','3','4','5'};f1.write(chars);//write(char[ ] cbuf,int off,int len)f1.write(chars,0,5);f1.close();//殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》我////何日功成名遂了,还乡,醉笑陪公三万场。//何日功成名遂了//12345//123}

字符输入流原理解析

字符流读取数据时

数据源和内存先建立流通道,然后内存里会创建一个长度为8192的缓冲区

开始读取时,read方法会先从缓冲区寻找数据,会先判断缓冲区是否有数据,如果缓冲区没有数据,就从文件中读取数据,尽可能装满缓冲区,如果有数据,就直接从缓冲区读取数据,如果文件中也没有数据,就会返回-1

读取的数据存入缓冲区后,如果下面用清空文件,那么再次读取时只能读取到缓冲区的数据,未存入缓冲区的数据不能再读取

字符输出流底层原理

字符流写出数据时

数据源和内存先建立流通道,然后内存里会创建一个长度为8192的缓冲区

有两种方式可以让缓冲区的数据存储到目的地

1.缓冲区装满了

2.手动刷新(flush)

3.close方法

flush刷新完成后,还可以继续往文件中写入数据

字节流和字符流的使用场景

字节流:可以拷贝任意类型的文件

字符流:读取纯文本文件中的数据,往纯文本文件中写出数据

综合练习

    public static void main(String[] args) throws IOException {File fu=new File("D:\\我的世界\\three");File f1=new File("D:\\我的世界\\one");CopyFolder(fu,f1);}public static void CopyFolder(File copyFile,File file) throws IOException {if(file.isDirectory()){File[] files = file.listFiles();for (File file1 : files) {if(file1.isFile()){//文件的copyString name = file1.getName();File newFile=new File(copyFile,name);FileOutputStream fos=new FileOutputStream(newFile);FileInputStream fis=new FileInputStream(file1);byte[]bytes=new byte[1024*1024];int len;while ((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);}fis.close();fos.close();} else{String name = file1.getName();File newFile=new File(copyFile,name);newFile.mkdirs();//子文件夹的copyCopyFolder(newFile,file1);}}}}

异或^计算符,两边相同为false,两边不同为true

一个数异或另外一个数两次,这个数还会变为原来的数

例如:

sout(false^false);//false
sout(true^true);//false
sout(false^true);//true
sout(true^false);//true
sout(100^10)//110
sout(100^10)//100

在加密的时候可以拿着字节数据去异或一个数字,解密的时候再异或回来public static void main(String[] args) throws IOException {File file=new File("D:\\我的世界\\a1.txt");File file1=new File("D:\\我的世界\\a4.txt");decrypt(file,file1);}public static void encrypt(File file,File file1) throws IOException {if(file.isFile()){FileInputStream fis=new FileInputStream(file);FileOutputStream fos=new FileOutputStream(file1);int b;while ((b=fis.read())!=-1){fos.write(b^2);}fos.close();fis.close();}}public static void decrypt(File file,File file1) throws IOException {if(file.isFile()){FileInputStream fis=new FileInputStream(file1);FileOutputStream fos=new FileOutputStream(file);int b;while ((b=fis.read())!=-1){fos.write(b^2);}fos.close();fis.close();}}

第一种解法:

 public static void main(String[] args) throws IOException {//读取数据FileReader fdr=new FileReader("D:\\我的世界\\b1.txt");StringBuilder sb=new StringBuilder();int ch;while ((ch=fdr.read())!=-1){sb.append((char)ch);}fdr.close();System.out.println(sb);//排序String str=sb.toString();String[] split = str.split("-");ArrayList<Integer>list=new ArrayList<>();for (int i = 0; i < split.length; i++) {list.add(Integer.parseInt(split[i]));}Collections.sort(list);//写出FileWriter fw=new FileWriter("D:\\我的世界\\b1.txt");for (int i = 0; i < list.size(); i++) {if(i==list.size()-1){fw.write(list.get(i)+"");}else{fw.write(list.get(i)+"-");}}fw.close();}

第二种解法:

public static void main(String[] args) throws IOException {//读取数据FileReader fdr=new FileReader("D:\\我的世界\\b1.txt");StringBuilder sb=new StringBuilder();int ch;while ((ch=fdr.read())!=-1){sb.append((char)ch);}fdr.close();System.out.println(sb);//排序String[] arr = sb.toString().split("-");Integer[] array = Arrays.stream(arr).map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}}).sorted().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});//写出FileWriter fw=new FileWriter("D:\\我的世界\\b1.txt");String s=Arrays.toString(array).replace(",","-");String result=s.substring(1,s.length()-1);fw.write(result);fw.close();}

高级流

所谓高级流,就是把基本流做了一个封装,额外添加了一些功能

缓冲流

缓冲流可以提高读写的效率

缓冲流的体系结构

上面的就表示缓冲区

字节缓冲流

除了构造方法(创建对象的时候)有所不同其他的使用基本都类似

提高效率的原理:

底层自带了长度8192的缓冲区提高性能

方法名说明

( is)

把基本流包装成高级流,提高读取数据性能

( os)

把基本流包装成高级流,提高读取数据性能

在底层,真正读写数据的还是缓冲流包装的基本流

    public static void main(String[] args) throws IOException {//这里创建缓冲流对象后,使用的时候与基本流是一样的,BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\我的世界\\a1.txt"));BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\我的世界\\copy.txt"));int b;while((b=bis.read())!=-1){bos.write(b);}//这里释放资源时不用关闭基本流,直接关闭缓冲流就行//缓冲流关闭的时候会把基本流关上bos.close();bis.close();}

    public static void main(String[] args) throws IOException {//这里创建缓冲流对象后,使用的时候与基本流是一样的,BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\我的世界\\a1.txt"));BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\我的世界\\copy1.txt"));byte[]bytes=new byte[1024];int len;while((len=bis.read(bytes))!=-1){bos.write(bytes,0,len);}//这里释放资源时不用关闭基本流,直接关闭缓冲流就行//缓冲流关闭的时候会把基本流关上bos.close();bis.close();}

字节缓冲流的基本原理

创建缓冲流后,在实际写入与读取时还是用的基本流,只是数据在内存的的过程中用到了缓冲流

每一个缓冲流对象都会创建一个缓冲区

整体过程就是:

首先基本流读取数据,一次性读8192个数据,把读取到的数据放到缓冲区当中,而中间的变量就是一个中转站,把数据从缓冲输入流的缓冲区转移到缓冲输出流的缓冲区

,当右边的缓冲区填满了,就会利用基本流自动的写出数据,当变量在缓冲输入流的缓冲区读不到数据了,这时基本流又会读取8192个数据,然后循环,直到文件读取完毕。

由于数据从硬盘到硬盘转移到内存中去,所以效率提高

如果中间变量是数组,原理也类似,只不过中间变量变成了数组

字符缓冲流

提高效率的原理:

底层自带了长度8192的缓冲区提高性能

方法名说明

( r)

把基本流变成高级流

( w)

把基本流变成高级流

方法名说明

()

读取一行数据,如果没有数据可读了,会返回null

方法名说明

()

跨平台的换行

之前写换行是\r\n但是这不合理,因为只有在中是\r\n,在Mac中是\r,在Linux中是\n

所以| () | 跨平台的换行 |是一个很有用的方法,方法的底层会先判断程序运行的是什么操作系统,然后给出相应的值来换行

    public static void main(String[] args) throws IOException {BufferedReader br=new BufferedReader(new FileReader("D:\\我的世界\\a1.txt"));//一次读取一行,与read一样,再次读取会读取下一行//readLine遇到回车换行结束,但是不会把回车和换行读到内存中
//        String s1 = br.readLine();
//        System.out.println(s1);
//
//        String s2 = br.readLine();
//        System.out.println(s2);//殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》我//何日功成名遂了,还乡,醉笑陪公三万场。//一次读取所有数据String line;while((line=br.readLine())!=null){System.out.println(line);}//殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》我//何日功成名遂了,还乡,醉笑陪公三万场。//何日功成名遂了//12345//123br.close();}

    public static void main(String[] args) throws IOException {//这里write的续写要在基本流里打开BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\我的世界\\b2.txt",true));String s1="画堂人静雨蒙蒙,屏山半掩余香袅。";bw.write(s1);bw.newLine();String s2 = "——寇准《踏莎行·春暮》";bw.write(s2);bw.newLine();bw.close();//画堂人静雨蒙蒙,屏山半掩余香袅。//——寇准《踏莎行·春暮》}

小结

综合练习

    public static void main(String[] args) throws IOException {//基本流FileInputStream fis=new FileInputStream("D:\\我的世界\\UnitySetup64-2020.3.47f1c1.exe");FileOutputStream fos1=new FileOutputStream("D:\\我的世界\\copy1.txt");FileOutputStream fos2=new FileOutputStream("D:\\我的世界\\copy2.exe");long l1 = System.currentTimeMillis();int b1;while((b1=fis.read())!=-1){fos1.write(b1);}long l2 =System.currentTimeMillis();System.out.println(l2-l1);byte[]bytes1=new byte[1024];long l3 = System.currentTimeMillis();System.out.println(l3);int len1;while ((len1=fis.read(bytes1))!=-1){fos2.write(bytes1,0,len1);}long l4 = System.currentTimeMillis();System.out.println(l4);System.out.println(l4-l3);fos2.close();fos1.close();fis.close();//缓冲流BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\我的世界\\a1.txt"));BufferedOutputStream bos1=new BufferedOutputStream(new FileOutputStream("D:\\我的世界\\copy3.txt"));BufferedOutputStream bos2=new BufferedOutputStream(new FileOutputStream("D:\\我的世界\\copy4.txt"));long l5 = System.currentTimeMillis();int b2;while((b2=bis.read())!=-1){bos1.write(b2);}long l6 =System.currentTimeMillis();System.out.println(l6-l5);byte[]bytes2=new byte[1024];long l7 = System.currentTimeMillis();int len2;while ((len2=bis.read(bytes2))!=-1){bos2.write(bytes2,0,len2);}long l8 = System.currentTimeMillis();System.out.println(l8-l7);bos2.close();bos1.close();bis.close();}

这里好像不能一次运行太多流,要写成方法的形式

//由于字符流的基本流只能一个一个的读取数据,不方便,所以用字符流的缓冲流读取写入public static void main(String[] args) throws IOException {//读取BufferedReader br=new BufferedReader(new FileReader("D:\\我的世界\\csb.txt"));String s;ArrayList<String>list=new ArrayList<>();while ((s=br.readLine())!=null){list.add(s);}//排序Collections.sort(list, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {String s1 = o1.split("\\.")[0];int i1 = Integer.parseInt(s1);String s2=o2.split("\\.")[0];int i2=Integer.parseInt(s2);return i1-i2;}});//写入br.close();BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\我的世界\\copy.txt"));for (String s1 : list) {bw.write(s1);bw.newLine();}bw.close();}

//将第一种写法的Arraylist改成TreeMap,可以自动根据序号排序public static void main(String[] args) throws IOException {//读取BufferedReader br=new BufferedReader(new FileReader("D:\\我的世界\\csb.txt"));String s;TreeMap<Integer,String>list=new TreeMap<>();while ((s=br.readLine())!=null){String s1 = s.split("\\.")[0];String s2 = s.split("\\.")[1];int i = Integer.parseInt(s1);list.put(i,s2);}//写入br.close();BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\我的世界\\copy.txt"));Set<Map.Entry<Integer, String>> entries = list.entrySet();for (Map.Entry<Integer, String> entry : entries) {String value = entry.getValue();bw.write(value);bw.newLine();}bw.close();}

//这个练习的关键就是统计次数,
//所以统计次数的变量不能定义在程序中,而是定义在本地文件中//读取本地文件获得运行次数public static void main(String[] args) throws IOException {BufferedReader br=new BufferedReader(new FileReader("D:\\我的世界\\count.txt"));String s = br.readLine();int count = Integer.parseInt(s);count++;BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\我的世界\\count.txt"));bw.write(count+"");//注意,这里写字符串的原因是:// 如果直接写入数字,在写入时会变成数字在字符集中对应的字符,所以写入字符串if(count<=3){System.out.println("第"+count+"次使用免费");}else{System.out.println("开始收费喽!");}bw.close();br.close();}

使用IO流的原则:什么时候用就什么时候创建,什么时候不用就什么时候关闭

转换流

属于字符流的一种高级流

转换流是字符流和字节流之间的桥梁

通过转换输入流()把字节流转换成字符流,这样就可以在转换的过程中让字节流有字符流的特性

写出时,再通过转换输出流()把字符流转成字节流,存储到文件中

转换流的应用场景:

作用1:指定字符集读写数据(在jdk11后被淘汰)

作用2:字节流想要使用字符流的方法

练习:

方法名说明

( is)

把字节流转成字符流

( is, )

把字节流包装成字符流,第二个参数可以指定字符流的字符集

( os)

把字符流包装成字节流

( os, )

把字符流包装成字节流,第二个参数可以指定字符流的字符集,这个方法基本不用

    public static void main(String[] args) throws IOException {/*需求1*///了解,在jdk11被淘汰
//        InputStreamReader isr=new InputStreamReader(new FileInputStream("D:\\我的世界\\one.txt"),"GBK");
//        int b;
//        while ((b=isr.read())!=-1){
//            System.out.print((char)b);
//        }
//        isr.close();//掌握,FileReader的构造方法参数
//        FileReader fr=new FileReader("D:\\我的世界\\one.txt", Charset.forName("GBK"));
//        int b;
//        while ((b=fr.read())!=-1){
//            System.out.print((char)b);
//        }
//        fr.close();/*需求2*///了解,在jdk11被淘汰
//        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("D:\\我的世界\\one.txt"),"GBK");
//        String s="我好你不好";
//        osw.write(s);
//        osw.close();//掌握,FileWriter的构造方法参数
//        FileWriter fw=new FileWriter("D:\\我的世界\\one.txt",Charset.forName("GBK"));
//        fw.write("你好你好杨");
//        fw.close();/*需求3*/FileReader fr=new FileReader("D:\\我的世界\\one.txt", Charset.forName("GBK"));FileWriter fw=new FileWriter("D:\\我的世界\\two.txt");int b;while ((b=fr.read())!=-1){fw.write(b);}fw.close();fr.close();}

转换流练习

//先把字节流包装成字符流,再把字符流包装成高级字符流public static void main(String[] args) throws IOException {
//        //创建基本流
//        FileInputStream fis=new FileInputStream("D:\\我的世界\\copy.txt");
//        //把基本流转换成字符流
//        InputStreamReader fsr=new InputStreamReader(fis);
//        //再把刚才转换的字符流进行包装,变成缓冲流
//        BufferedReader br=new BufferedReader(fsr);
//        String str=br.readLine();
//        System.out.println(str);//上述代码可以写成以下形式BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("D:\\我的世界\\copy.txt")));String str=br.readLine();System.out.println(str);}

序列化流

属于字节流的一种,负责输出数据,与之对应的还有一个反序列化流,用来读取数据

序列化流(对象操作输出流)的解析

作用:可以把Java中的对象写到本地文件中

方法名说明

( out)

把基本流包装成高级流

方法名说明

final void ( obj)

把对象序列化(写出)到文件中去

反序列化流(对象操作输入流)的解析

可以把序列化到本地的对象读取到程序中来

方法名说明

( out)

把基本流包装成高级流

方法名说明

()

把序列化到本地的对象读取到程序中来

    public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\我的世界\\one.txt"));Object o = ois.readObject();System.out.println(o);ois.close();}

序列化流和反序列化流的细节 练习

规定:以后创建对象写到本地文件中时,要先把对象添加到集合中,再把集合写道本地文件中,读取时可以直接读取集合

//反序列化流public static void main(String[] args) throws IOException {student s1=new student("shangyang",13);student s2=new student("shangya",23);student s3=new student("shangy",43);ArrayList<student>list=new ArrayList<>();list.add(s1);list.add(s2);list.add(s3);ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("one.txt"));oos.writeObject(list);oos.close();}
//序列化流public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois=new ObjectInputStream(new FileInputStream("one.txt"));ArrayList<student>list = (ArrayList<student>) ois.readObject();//这里返回值是一个对象,要转成arraylistfor (student student : list) {System.out.println(student);}}

打印流

打印流不能读只能写,所以打印流只有输出流

打印流一般是指和两个类

字节打印流 方法名说明

( /File /)

关联字节输出流/文件/文件路径

( , )

指定字符编码

( out, auto )

自动刷新

( out, auto , )

指定字符编码且自动刷新

字节打印流底层没有缓冲区,开不开自动刷新都一样,所以下面两个构造方法意义不大

方法名说明

void write(int b)

常规方法,规则和之前的方法一样

void (Xxx xx)

特有方法:打印任意数据,自动刷新,自动换行

void print(Xxx xx)

特有方法:打印任意数据,不换行

void ( ,… args)

特有方法:带有占位符的打印语句,不换行

字节打印流底层没有缓冲区,开不开自动刷新都一样

    public static void main(String[] args) throws IOException, ClassNotFoundException {PrintStream ps=new PrintStream(new FileOutputStream("D:\\我的世界\\a2.txt"),true,"UTF-8");//这两个跟sout的输出是一样的ps.println(97);ps.print(true);ps.println();//这个是占位符的写法//这个占位符有很多,这里就不一一细说了ps.printf("%sone%s","two","three");ps.close();}

字符打印流

字符打印流有缓冲区,想要自动刷新需要开启

方法名说明

( /File /)

关联字符输出流/文件/文件路径

( , )

指定字符编码

(Write w, auto )

自动刷新

( out, auto , )

指定字符编码且自动刷新

方法名说明

void write(int b)

常规方法,规则和之前的方法一样

void (Xxx xx)

特有方法:打印任意数据,自动刷新,自动换行

void print(Xxx xx)

特有方法:打印任意数据,不换行

void ( ,… args)

特有方法:带有占位符的打印语句,不换行

在构造方法中,能开启自动刷新的参数是比较常用的

    public static void main(String[] args) throws IOException, ClassNotFoundException {//注意,要开启自动刷新PrintWriter pw=new PrintWriter(new FileWriter("D:\\我的世界\\a2.txt"),true);pw.println("one");pw.print(111);pw.printf("%sone%s","two","three");pw.close();}

.out创建一个指向控制台的打印流

sout就是调用打印流的方法

这个打印流是不能关闭的,在系统中唯一存在

解压缩流/压缩流

解压缩流就是读取压缩包中的文件

压缩流就是把文件中的数据写道压缩包中

解压缩流

压缩包里的每一个文件在java中都是一个对象

解压的本质就是:把每一个对象按照层级拷贝到本地另外一个文件夹中

:zip压缩包的解压缩流,也是一个高级流

方法名说明

( is)

把基本流包装成高级流

方法名说明

Entry ()

获得文件夹中的文件或子文件夹

    public static void main(String[] args) throws IOException{File src=new File("D:\\我的世界\\three.zip");File dest=new File("D:\\我的世界\\");unzip(src,dest);}public static void unzip(File src,File dest) throws IOException {//创建一个解压缩流用来读取压缩包中的数据ZipInputStream zip=new ZipInputStream(new FileInputStream(src));//中间值,用来记录获取的文件或文件夹对象ZipEntry entry;//getNextEntry会一个一个的遍历压缩包,直到全部遍历完成,返回nullwhile ((entry=zip.getNextEntry())!=null){System.out.println(entry);if(entry.isDirectory()){//entry为文件夹,在目的地创建一个新的文件夹File file=new File(dest,entry.toString());file.mkdirs();}else {//entry为文件,读取压缩包中的文件,放到目的地中File file = new File(dest, entry.toString());FileOutputStream fos=new FileOutputStream(file);int b;while ((b= zip.read())!=-1){fos.write(b);}fos.close();zip.closeEntry();}}zip.close();}

压缩流

    public static void main(String[] args) throws IOException {//创建File对象表示要压缩的文件File src=new File("D:\\我的世界\\a1.txt");//创建File对象表示压缩包的位置File dest=new File("D:\\我的世界\\");toZip(src,dest);}public static void toZip(File src,File dest) throws IOException {ZipOutputStream zos=new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));//创建zipEntry对象,表示压缩包中每一个文件和文件夹ZipEntry entry=new ZipEntry("a.txt");//把Zip对象放到压缩包中zos.putNextEntry(entry);FileInputStream fis=new FileInputStream(src);int b;while ((b=fis.read())!=-1){zos.write(b);}zos.closeEntry();zos.close();fis.close();}

    public static void main(String[] args) throws IOException {//创建File对象表示要压缩的文件File src=new File("D:\\我的世界\\aaa");//创建File对象表示压缩包放在哪里File fufile=src.getParentFile();//可以得到src的父级路径System.out.println(fufile);//创建File对象表示压缩包的位置File dest=new File(fufile,src.getName()+".zip");//创建压缩流关联压缩包ZipOutputStream zos=new ZipOutputStream(new FileOutputStream(dest));toZip(src,zos,src.getName());}/**   函数作用:获取src的每一个文件,变成ZipEntry对象,放到压缩包中*   参数1:数据源*   参数2:压缩流*   参数3:压缩包内部的路径* */public static void toZip(File src,ZipOutputStream zos,String name) throws IOException {File[] files = src.listFiles();for (File file : files) {if(file.isFile()){//文件,变成Entry对象,放到压缩包中ZipEntry entry=new ZipEntry(name+"\\"+file.getName());//这里不能直接传file,因为file是绝对路径,带盘符的//所以此时就要用到第三个参数,第三个参数代表压缩包内部的路径zos.putNextEntry(entry);//读取文件中的数据,写到压缩包中FileInputStream fis=new FileInputStream(file);int b;while ((b=fis.read())!=-1){zos.write(b);}fis.close();zos.closeEntry();}else {toZip(file,zos,name+"\\"+file.getName());}}}

常用工具包 -io

作用:提高io流的开发效率

方法名说明

void (File ,File )

复制文件

void (File ,File )

复制文件夹

void tory(File ,File )

复制文件夹

void (File )

删除文件夹

void (File )

清空文件夹

(File file, )

读取文件中的数据变成字符串

void write(File file, data, )

写出数据

外部包的导入:看这篇文章

    public static void main(String[] args) throws IOException {File src=new File("D:\\我的世界\\one");File dest=new File("D:\\我的世界\\a2.txt");//copyFile,拷贝文件,把参数一的文件拷贝到参数二去
//        FileUtils.copyFile(src,dest);
//
//        //copyDirectory, 复制文件夹,将参数1文件夹的内容复制到参数2
//        FileUtils.copyDirectory(src,dest);
//        //copyDirectoryToDirectory,复制文件夹,先在参数2的文件夹中创建一个以参数1为名的子文件夹
//        // ,再将参数1文件夹的内容复制到参数2
//        FileUtils.copyDirectoryToDirectory(src,dest);
//        //deleteDirectory,删除文件夹
//        FileUtils.deleteDirectory(dest);
//        //clearDirectory,清空文件夹
//        FileUtils.cleanDirectory(dest);
//        //readFileToString,读取文件夹中的数据变成字符串
//        FileUtils.readFileToString(src);//write,写出数据String s="殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天·林断山明竹隐墙》\n" +"何日功成名遂了,还乡,醉笑陪公三万场。\n" +"画堂人静雨蒙蒙,屏山半掩余香袅。——寇准《踏莎行·春暮》\n" +"\n";FileUtils.write(dest,s,"UTF-8");}

copy方法有多个重载方法,满足不同的输入输出流

.copy( input, )

.copy( input, , int )//可指定缓冲区大小

.copy( input, , )//可指定输入流的编码表

.copy( input, )

.copy( input, , )//可指定输出流的编码表

这个方法适合拷贝较大的数据流,比如2G以上

.( input, ) // 默认会用1024*4的来读取

.( input, , char[] )//可指定缓冲区大小

.( input)

.(byte[] input, )

.( input, )

.( input, )

.(URI uri, )

.(URL url, )

.( input)

.( input, int size)

.(URI uri)

.(URL url)

.( )

.( input, )

.( input)

.( input, )

.( input, )

.( lines, , )

.( lines, , , )

.( lines, , , )

.read( input, byte[] )

.read( input, byte[] , int , int ) .read( input, char[] )

.read( input, char[] , int , int )

.write(byte[] data, )

.write(byte[] data, , )

.write(byte[] data, , )

.write(char[] data, )

.write(char[] data, , )

.write(char[] data, , )

.write( data, )

.write( data, )

.( input, int )

.( input, byte[] )

.( input, byte[] , int , int ) .( input, char[] )

.( input, char[] , int , int )

.( , ) // 比较两个流是否相等

.( , )

.OL( , ) // 比较两个流,忽略换行符

.skip( input, long ) // 跳过指定长度的流

.skip( input, long )

.( input, long ) // 如果忽略的长度大于现有的长度,就会抛出异常

.( input, long )

.(File , File ) // 复制文件夹(文件夹里面的文件内容也会复制)

.(File , File , ) // 复制文件夹,带有文件过滤功能

.tory(File , File ) // 以子目录的形式将文件夹复制到到另一个文件夹下

.(File , File ) // 复制文件

.(File input, ) // 复制文件到输出流

.(File , File ) // 复制文件到一个指定的目录

.e( , File ) // 把输入流里面的内容复制到指定文件

.(URL , File ) // 把URL 里面内容复制到文件(可以下载文件)

.(URL , File , int , int )

.(File file, data, )

.(File file, data, , )

.(File file, byte[] data)

.(File file, byte[] data, ) .(File file, byte[] data, int off, int len) .(File file, byte[] data, int off, int len, )

// :文件编码,:每行以什么结尾

.(File file, lines)

.(File file, lines, )

.(File file, lines, )

.(File file, lines, , )

.(File file, , lines)

.(File file, , lines, )

.(File file, , lines, )

.(File file, , lines, , )

.write(File file, data, )

.write(File file, data, , )

.write(File file, data, )

.write(File file, data, , )

.(File , File ) // 文件夹在内的所有文件都将移动.tory(File src, File , ) // 以子文件夹的形式移动到另外一个文件下

.(File , File ) // 移动文件

.(File , File , ) // 以子文件的形式移动到另外一个文件夹下

.(File src, File , ) // 移动文件或者目录到指定的文件夹内

.(File ) // 删除文件夹,包括文件夹和文件夹里面所有的文件

.(File ) // 清空文件夹里面的所有的内容

.(File file) // 删除,会抛出异常

.(File file) // 删除,不会抛出异常

.(File ) // 创建文件夹(可创建多级)

.(File file) // 创建文件的父级目录

.(File file)

.(File file)

.(File file) // 把文件读取到字节数组

.(File file, ) // 把文件读取成字符串

.(File file, )

.(File file, ) // 把文件读取成字符串集合

.(File file, )

.(File file, Date date)

.(File file, File )

.(File file, long )

.(File file, Date date)

.(File file, File )

.(File file, long )

.(File , , )

.(File , [] , )

.(File , , )

.(File file)

.(File file, )

.(File , , )

.(File , [] , )

.(File , , )

.(File file) // 判断是否是符号链接

.(File , File child) // 判断文件夹内是否包含某个文件或者文件夹

.(File file) // 获取文件或者文件夹的大小

.()// 获取临时目录文件

.()// 获取临时目录路径

.()// 获取用户目录文件

.()// 获取用户目录路径

.touch(File file) // 创建文件

.(File file1, File file2) // 比较两个文件内容是否相同

.( , ) // 合并目录和文件名为文件全路径

.( ) // 去除目录和后缀后的文件名

.( ) // 获取文件的后缀

.( ) // 获取文件的目录

.( ) // 获取文件名

.( ) // 去除盘符后的路径

.( ) // 盘符

.( ) // 获取最后一个.的位置

.( ) // 获取最后一个/的位置

.( ) // 获取当前系统格式化路径

.( ) // 移除文件的扩展名

.( path) // 转换分隔符为当前系统分隔符

.( path) // 转换分隔符为linux系统分隔符

.( path) // 转换分隔符为系统分隔符

.( , ) // 判断文件路径是否相同,非格式化

.( , ) // 判断文件路径是否相同,格式化

.( , ) // 判断目录下是否包含指定文件或目录

.( , ) // 判断文件扩展名是否包含在指定集合(数组、字符串)中

.( , ) // 判断文件扩展名是否和指定规则匹配

工具包

胡涂包:

IO相关的工具类:

注意:封装文件读取()和封装文件写入()的类名和java的字符流类名重复了,所以要想使用工具类,一定要注意导包。

的中文使用文档:#/

的Api帮助文档:

方法的举例:

File ( list, File file, ) 将列表写入文件,追加模式,策略为: 当文件为空,从开头追加,尾部不加空行 当有内容,换行追加,尾部不加空行 当有内容,并末尾有空行,依旧换行追加

这里的列表就是单列集合,追加模式就是原有的不会清空

    public static void main(String[] args) {//常用的Hutool方法/**   FileUtil类:*       file:根据参数创建一个File对象*       touch:根据参数创建文件**       writeLines:把集合中的数据写出到文件中,覆盖模式*       appendLines:把集合中的数据写出到文件中,续写模式*       readLines:指定字符编码,把文件中的数据,读到集合中*       readUtf8Lines:按照UTF-8的形式,把文件中的数据读到集合中**       copy:拷贝文件或者文件夹** *///可以用多个参数进行拼接,创建File对象File file = FileUtil.file("D:\\", "我的世界", "noc", "a.txt");System.out.println(file);//touch,根据参数创建文件,如果父级路径不存在,可以连父级路径一起创建FileUtil.touch(file);//writeLines:把集合中的数据写出到文件中,覆盖模式ArrayList<String>list=new ArrayList<>();list.add("aaa");list.add("aaa");list.add("aaa");list.add("aaa");FileUtil.writeLines(list,file,"UTF-8");//appendLines:把集合中的数据写出到文件中,续写模式,与writeLines使用方法一样//readLines:指定字符编码,把文件中的数据,读到集合中List<String> stringList = FileUtil.readLines(file, "UTF-8");System.out.println(stringList);}

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了