IO流
IO流概述及其分类
1、概述
Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流),或者抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或者Writer(字符输出流)的子类。
(1)首先需要明白的是:流是为了永久性的保存数据
- 根据数据流向的不同分为输入流和输出流;
- 根据处理数据类型的不同分为字符流和字节流;
(2)然后需要明白的是输入模式和输出模式是谁流向谁
- InputStream(字节输入流)和Reader(字符输入流)通俗的理解都是读(read)的。
- OutputStream(字节输出流)和Writer(字符输出流)通俗的理解都是写(writer)的。
2、InputStream类
InputStream类是字节输入流的抽象类,是所有字节输入流的父类
3、Reader类
java中的字符是Unicode编码的,是双字节的。InputStream是用来处理字节的,在处理字符文本时很不方便。Java为字符文本的输入提供了专门的一套类Reader。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。
4、OutputStream类
输出流OutputStream类是字节输入流的抽象类,此抽象类表示输出字节流的所有类的超类。
5、Writer类
Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。
6、File类
File类是IO包中唯一代表磁盘文件本身的对象。通过File来创建,删除,重命名文件。File类对象的主要作用就是用来获取文本本身的一些信息。如文本的所在的目录,文件的长度,读写权限等等。
File类(File类的概述和构造方法)
(1)File类的概述
- File更应该叫做一个路径
- 文件路径或者文件夹路径
- 路径分为绝对路径和相对路径
- 绝对路径是一个固定的路径,从盘符开始
- 相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下
- 查看API指的是当前路径
- 文件和目录路径名的抽象表示形式
(2)构造方法
- File(String pathname):根据一个路径得到File对象
- File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
- File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
7、File类(File类的创建功能)
(1)创建功能
- public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
- public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
- public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
- (使用createNewFile()文件创建的时候不加.txt或者其他后缀也是文件,不是文件夹;使用mkdir()创建文件夹的时候,如果起的名字是比如aaa.txt也是文件夹不是文件;)
8、File类(File类的重命名和删除功能)
(1)重命名和删除功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径
- public boolean delete():删除文件或者文件夹
(2)重命名注意事项
- 如果路径名相同,就是改名。
- 如果路径名不同,就是改名并剪切。
(3)删除注意事项:
- Java中的删除不走回收站。
- 要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
9、File类(File类的判断功能)
- public boolean isDirectory():判断是否是目录
- public boolean isFile():判断是否是文件
- public boolean exists():判断是否存在
- public boolean canRead():判断是否可读
- public boolean canWrite():判断是否可写
- public boolean isHidden():判断是否隐藏
10、File类(File类的获取功能)
- public String getAbsolutePath():获取绝对路径
- public String getPath():获取路径
- public String getName():获取名称
- public long length():获取长度。字节数
- public long lastModified():获取最后一次的修改时间,毫秒值
- public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
- public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
11、File类(文件名称过滤器的概述及使用)
(1)文件名称过滤器的概述
- public String[ ] list(FilenameFilter filter)
- public File[ ] listFiles(FileFilter filter)
(2)使用
package com.lc; import java.io.File; public class Test { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub File file=new File("aa.txt");//文件默认就创建在你创建的项目下面,刷新即可看到 System.out.println(file.exists());//判断文件是否存在 file.createNewFile();//创建文件,不是文件夹 System.out.println(file.exists());//再次判断是否存在 System.out.println(file.getName());//获取文件的名字 System.out.println(file.getAbsolutePath());//获取文件的绝对路径 System.out.println(file.getPath());//获取文件的相对路径 System.out.println(file.getParent());//获取文件的父路径 System.out.println(file.canRead());//文件是否可读 System.out.println(file.canWrite());//文件是否可写 System.out.println(file.length());//文件的长度 System.out.println(file.lastModified());//文件最后一次修改的时间 System.out.println(file.isDirectory());//判断文件是否是一个目录 System.out.println(file.isHidden());//文件是否隐藏 System.out.println(file.isFile());//判断文件是否存在 } }
(3)list()
- public String[ ] list():获取指定目录下的所有文件或者文件夹的名称数组
- public File[ ] listFiles():获取指定目录下的所有文件或者文件夹的File数组
- list()获取某个目录下所有的文件或者文件夹
package com.lc; import java.io.File; public class FileTest { public static void main(String[] args){ File file=new File("D:/");//指定文件目录 String[] str=file.list();//获取指定目录下的所有文件或者文件夹的名称数组 for(String s : str){//加强for循环遍历输出 System.out.println(s); } } }
package com.lc; import java.io.File; public class FileTest { public static void main(String[] args){ File file=new File("D:/");//指定文件路径 File[] f=file.listFiles();//获取指定目录下的所有文件或者文件夹的File数组 for(File fi : f){//加强for循环遍历输出 System.out.println(fi); } } }
(4)获取某种格式的文件比如获取某种后缀的图片,并输出文件名
package com.lc; import java.io.File; public class FileTest { public static void main(String[] args){ File file=new File("C:\\Users\\biehongli\\Pictures\\xuniji"); String[] str=file.list(); for(String s : str){ if(s.endsWith(".jpg") || s.endsWith(".png")){//如果后缀是这种格式的就输出 System.out.println(s); } } } }
(5)下面演示获取文件夹下面子目录里面的文件获取(并没有完全获取子目录的子目录等等,仅仅获取了子一级目录)
package com.lc; import java.io.File; public class FileTest { public static void main(String[] args){ File file=new File("C:\\Users\\biehongli\\Pictures\\Camera Roll"); File[] f=file.listFiles(); for(File fi : f){ if(fi.isDirectory()){//判断如果是一个目录 String[] s=fi.list(); for(String str : s){ if(str.endsWith(".jpg")){ System.out.println(str); } } } } } }
(6)文件名称过滤器的概述
public String[] list(FilenameFilter filter)
public File[] listFiles(FileFilter filter)
package com.lc; import java.io.File; import java.io.FilenameFilter; public class FileTest { public static void main(String[] args){ File file=new File("C:\\Users\\biehongli\\Pictures\\Camera Roll"); String[] str=file.list(new FilenameFilter() {//过滤器,匿名内部类 public boolean accept(File dir, String name) { // TODO Auto-generated method stub //System.out.println(dir);//获取文件的路径 //System.out.println(name);//获取文件的名字 File f=new File(dir,name); return f.isFile() && f.getName().endsWith(".jpg"); } }); for(String s : str){ System.out.println(s); } } }
12、字节流
(1)字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111;那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上;24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型。
- FileInputStream的单个字节读取
- FileOutputStream的单个字节写入
package com.lc; import java.io.FileInputStream; import java.io.FileOutputStream; public class FileTest { public static void main(String[] args) throws Exception{ FileInputStream fis=new FileInputStream("aaa.txt"); FileOutputStream fos=new FileOutputStream("bbb.txt",true); //FileOutputStream()后面加true指文件后面可追加 int a=fis.read();//read()一次读取一个字节 System.out.println(a);//读取的一个字节输出 fos.write(101);//write()一次写一个字节 fis.close();//一定记得关闭流,养成好习惯 fos.close(); } }
(2)FileInputStream和FileOutputStream进行拷贝文本或者图片或者歌曲
package com.lc; import java.io.FileInputStream; import java.io.FileOutputStream; public class FileTest { public static void main(String[] args) throws Exception{ FileInputStream fis=new FileInputStream("aaa.txt"); FileOutputStream fos=new FileOutputStream("bbb.txt"); //如果没有bbb.txt,会创建出一个 int b; while((b=fis.read())!=-1){ fos.write(b); } fis.close(); fos.close(); } }
(3)FileInputStream和FileOutputStream定义小数组进行读写操作
package com.lc; import java.io.FileInputStream; import java.io.FileOutputStream; public class FileTest { public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("aaa.txt"); FileOutputStream fos = new FileOutputStream("bbb.txt"); int len; byte[] arr = new byte[1024 * 8];//自定义字节数组 while((len = fis.read(arr)) != -1) { //fos.write(arr); fos.write(arr, 0, len);//写出字节数组写出有效个字节个数 } //IO流(定义小数组) //write(byte[] b) //write(byte[] b, int off, int len)写出有效的字节个数 fis.close(); fos.close(); } }
13、BufferedInputStream和BufferOutputStream拷贝
(1)缓冲思想
- 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
- 这是加入了数组这样的缓冲区效果,java本身在设计的时候,
- 也考虑到了这样的设计思想,所以提供了字节缓冲区流
(2)BufferedInputStream
- BufferedInputStream内置了一个缓冲区(数组)
- 从BufferedInputStream中读取一个字节时
- BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
- 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
- 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
(3)BufferedOutputStream
- BufferedOutputStream也内置了一个缓冲区(数组)
- 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
- 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
package com.lc; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; public class FileTest { public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("aaa.txt"); FileOutputStream fos = new FileOutputStream("bbb.txt"); BufferedInputStream bis=new BufferedInputStream(fis); //使用装饰模式,把fis装饰进去bis中。使用缓冲读取速度变快 BufferedOutputStream bos=new BufferedOutputStream(fos); int b; while((b=bis.read())!=-1){ bos.write(b); } bis.close(); bos.close(); } }
(4)小数组的读写与Buffered的读取相比较
定义小数组如果是8192个字节大小和Buffered比较的话,定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组
14、fiush和close的区别
flush()方法:用来刷新缓冲区,刷新后可以再次写出(字节缓冲流内置缓冲区,荣国没有读取方法,可以使用flush()方法刷新出来)
close()方法:用来关闭流释放的资源的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出
15、字符流FileReader和FileWriter
(1)字符流概述
字符流是可以直接读写字符的IO流,字符流读取字符,就要先读取到字节数据,然后转为字符,如果要写出字符,需要把字符转为字节再写出。
(2)在何种情况下使用字符流
字符流也可以拷贝文件,但是读取时会把字节转成字符,写出时还要把字符转回字节。
程序需要读取一段文本,或者需要写出一段文本时可以使用字符流。读取的时候是按照字符的大小读取的,不会出现半个中文,写出的时候可以直接将字符串转出,不用转换为字节数组。
(3)字符流是否可以拷贝纯文本文件
不可以,引文在读取的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用 ?代替,写出的时候会将字符转换为字节写出去。
package lc; import java.io.FileReader; import java.io.FileWriter; public class FileTest { public static void main(String[] args) throws Exception{ //FileReader类的read()方法可以按照字符大小读取 FileReader fr=new FileReader("aaa.txt"); int b; while((b=fr.read())!=-1){ System.out.println((char)b);//int类型转为字符型 } fr.close(); //FileWriter类的write()方法可以自动把字符转为字节写出 FileWriter fw = new FileWriter("aaa.txt",true); fw.write("aaa"); fw.close(); //字符流的拷贝 FileReader fr2 = new FileReader("aaa.txt"); FileWriter fw2 = new FileWriter("bbb.txt"); int ch; while((ch = fr2.read()) != -1) { fw2.write(ch); } fr2.close(); fw2.close(); } }
package com.lc; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; public class FileTest { public static void main(String[] args) throws Exception{ BufferedReader br=new BufferedReader(new FileReader("aaa.txt")); BufferedWriter bw=newBufferedWriter(newFileWriter("bbb.txt")); //BufferedReader和BufferedWriter的使用: int b; while((b=br.read())!=-1){ bw.write((char)b); } br.close(); bw.close(); } }
16、压缩流ZipInputStream和ZipOutputStream
(1)读取压缩文件ZipInputStream
借助ZipFile类的getInputStream方法得到压缩文件的指定项的内容,然后传递给InputStreamReader类的构造方法,返回给BufferedReader类实例化,从而使得指定项的内容输出到内存中。
(2)压缩文件:ZipOutputStream
①zipOut.putNextEntry(entry); 此方法会清空zip文件原来存在的内容,然后写入文件,并将流定位到条目数据的开始处,直到关闭ZipOuputStream。
②必须关闭ZipOutputStream流,若不关闭ZipOutputStream流,则会压缩错误。
③压缩文件其实就是,创建一个新的压缩文件,然后把要压缩的文件内容写入到压缩文件项中。
package com.lc; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class ZipTest { public static void main(String[] args) { readZip(); writeZip(); } /** * 读取zip文件内容 */ private static void readZip() { File fil = new File("D:\\av\\zip\\zip.zip"); ZipInputStream zipIn = null; try { zipIn = new ZipInputStream(new FileInputStream(fil)); } catch (FileNotFoundException e) { e.printStackTrace(); } ZipEntry zipEn = null; /** * 需要读取zip文件项的内容时,需要ZipFile类的对象的getInputStream方法取得该项的内容, * 然后传递给InputStreamReader的构造方法创建InputStreamReader对象, * 最后使用此InputStreamReader对象创建BufferedReader实例 * 至此已把zip文件项的内容读出到缓存中,可以遍历其内容 */ ZipFile zfil = null; try { zfil = new ZipFile("D:\\av\\zip\\zip.zip"); } catch (IOException e1) { e1.printStackTrace(); } try { while ((zipEn = zipIn.getNextEntry()) != null) { if (!zipEn.isDirectory()) { // 判断此zip项是否为目录 System.out.println(zipEn.getName() + ":\t"); /** * 把是文件的zip项读出缓存, * zfil.getInputStream(zipEn):返回输入流读取指定zip文件条目的内容 zfil:new * ZipFile();供阅读的zip文件 zipEn:zip文件中的某一项 */ BufferedReader buff = new BufferedReader( new InputStreamReader(zfil.getInputStream(zipEn))); String str; while ((str = buff.readLine()) != null) { System.out.println("\t" + str); } buff.close(); } zipIn.closeEntry();// 关闭当前打开的项 } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { zfil.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 压缩文件 * 创建压缩文件 * 若该文件本来就存在文件则清空,然后写入,直到关闭ZipOutputStream * 即从ZipOutputStream实例化到关闭期间写入的文件不会清空 * 若不关闭ZipOutputStream流,则会压缩错误:不可预料的压缩文件末端 * * 压缩文件夹可以循环其内文件再读取其数据,再压缩文件 * */ private static void writeZip() { ZipOutputStream zipOut = null; try { zipOut = new ZipOutputStream(new FileOutputStream("D:\\av\\zip\\zip1.zip"));//若文件不存在则创建 } catch (FileNotFoundException e) { e.printStackTrace(); } int i=0; while (i<3) { ZipEntry entry = new ZipEntry(i+".txt"); try { zipOut.putNextEntry(entry);// 此方法会清空zip文件原来存在的内容,然后创建新的文件1.txt,并将流定位到条目数据的开始处 zipOut.write(98); } catch (IOException e1) { e1.printStackTrace(); } i++; } try { zipOut.close();//必须关闭,否则压缩文件错误:不可预料的压缩文件末端 } catch (IOException e) { e.printStackTrace(); } } }