I/O的学习之字节流
今天的主要内容
-
File类的使用
File类概述和构造方法
File类的创建功能
File类的重命名和删除功能
File类的判断功能
File类的获取功能
案例:输出指定目录下指定后缀的文件名
文件名称过滤器的概述及使用
-
IO流
IO流概述
FileInputStream
FileOutputStream
IO流拷贝图片
BufferedInputStream和BufferOutputStream拷贝
flush和close的区别
流的标准异常处理代码
IO流图片加密
-
IO流(拷贝文件)
- 在控制台录入文件的路径,将文件拷贝到当前项目下
-
IO流(录入数据拷贝到文件)
- 获取键盘输入,并将输入的信息写入到text.txt中
File
一、File类(File类的概述和构造方法)
-
File类的概述
-
File更应该叫做一个路径
文件路径或者文件夹路径
路径分为绝对路径和相对路径
绝对路径是一个固定的路径,从盘符开始
相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下指的当前路径
查看API
文件和目录路径名的抽象表示形式
-
-
构造方法
File(String pathname):根据一个路径得到File对象
File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象(重点)
-
构造方法的使用
public class TestFile_1 { public static void main(String[] args) { //File(String pathname):根据一个路径得到File对象 File file1 = new File("E:" + File.separator + "mytest" + File.separator + "testMy.txt"); //File(String parent, String child) String child = "testMy.txt"; File file2 = new File("E:" + File.separator + "mytest",child); //File(File parent, String child) //这种方法更好,因为可以对父路径进行一些操作 File parent = new File("E:" + File.separator + "mytest"); File file3 = new File(parent,child); System.out.println(file3.exists()); System.out.println(parent.exists()); } }
二、File类(File类的创建功能)
-
A:创建功能
- public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
- public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
- public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
三、File类(File类的重命名和删除功能)
-
A:重命名和删除功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径
- public boolean delete():删除文件或者空的文件夹
-
B:重命名注意事项
- 如果路径名相同,就是改名。
- 如果路径名不同,就是改名并剪切。
-
C:删除注意事项:
- Java中的删除不走回收站。
- 要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
-
程序
public class TestFileMethod { public static void main(String[] args) { File file = new File("E:" + File.separator + "myTest"); //重命名myTest为myTest2 System.out.println(file.renameTo(new File("E:" + File.separator + "myTest2"))); //此时renameTo相当于剪切并重命名 System.out.println(file.renameTo(new File("E:" + File.separator + "test" + File.separator + "myTest3"))); } }
四、File类(File类的判断功能)
- A:判断功能
- public boolean isDirectory():判断是否是目录
- public boolean isFile():判断是否是文件
- public boolean exists():判断是否存在
- public boolean canRead():判断是否可读
- setReadable(false)在Windows系统中不生效
- 只在Windows中生效
- public boolean canWrite():判断是否可写
- setWritable(false)在Windows中也生效
- public boolean isHidden():判断是否隐藏
五、File类(File类的获取功能)
- A:获取功能
- public String getAbsolutePath():获取绝对路径
- public String getPath():获取路径
- public String getName():获取名称
- public long length():获取长度。字节数
- public long lastModified():获取最后一次的修改时间,毫秒值
- 可格式化为正常日期
- SimpleDateFormat sdf = new SimpleDateFormat();
- sdf.format(new Date(file.lastModified));
- public String[] list():获取指定目录下的所有文件和文件夹的名称数组
- public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
六、File类(输出指定目录下指定后缀的文件名)
-
需求:判断E盘目录及子目录下是否有后缀名为.txt的文件,如果有,就输出该文件名称
- 需要递归
-
程序
public class TestFile_2 { public static void main(String[] args) { File file = new File("E:/"); findFile(file); } private static void findFile(File file) { // TODO Auto-generated method stub if(file.isDirectory()) { File[] files = file.listFiles(); if(files != null) { for(int i = 0; i < files.length;i++) { findFile(files[i]); } } }else { String fileName = null; if(file.getName().contains(".txt")) { System.out.println(file); } } } }
七、File类(文件名称过滤器的概述及使用)
-
A:文件名称过滤器的概述
-
@FunctionalInterface(函数式接口)
public interface FileFilter- 只有一个accept方法
public String[] list(FilenameFilter filter)
public File[] listFiles(FileFilter filter)
-
过滤器作用就是筛选我们需要的文件和文件夹信息
-
常用方法
public String[] list(FilenameFilter filter)
public File[] listFiles(FileFilter filter)
-
程序
需求:返回E盘目录及子目录下是否有后缀名为.txt的文件
-
Code:
public class TestFileFilter { public static void main(String[] args) { File file = new File("E:/"); //返回E盘目录及子目录下是否有后缀名为.txt的文件 file.listFiles(new FileFilter() { @Override public boolean accept(File file) { // TODO Auto-generated method stub if(file.isDirectory()) { File[] files = file.listFiles(); if(files != null) { for(int i = 0;i < files.length;i++) { accept(files[i]); } } }else { if(file.getName().contains(".txt")) { System.out.println(file); return true; } } return false; } }); } }
I/O
一、IO流(IO流概述及其分类)
-
概念
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的类都在IO包中
流按流向分为两种:输入流,输出流。
-
流按操作类型分为两种:
字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
字符流 : 字符流只能操作纯字符数据,比较方便。
-
IO流常用父类
-
字节流的抽象父类:
InputStream
OutputStream
-
字符流的抽象父类:
Reader
Writer
-
-
IO程序书写
使用前,导入IO包中的类
使用时,进行IO异常处理
使用后,释放资源
二、IO流(FileInputStream)
read()一次读取一个字节
-
程序
public class TestFileInputStream { public static void main(String[] args) { File file = new File("E:" + File.separator + "test" + File.separator + "test.txt"); //创建输入流 FileInputStream fileInputStream = null; int b = 0; try { fileInputStream = new FileInputStream(file); //read()一次读取一个字节 while((b = fileInputStream.read()) != -1) { System.out.print((char)b); } fileInputStream.close(); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /* * 在JDK1.8中输出结果为: * -------------- * hahahahaha * -------------- * */
三、IO流(read()方法返回值为什么是int)
* 因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
四、IO流(FileOutputStream)
- write()一次写出一个字节
-
虽然write的参数是int,但是在写入文件的时候仍旧是一个字节一个字节去写入
public class TestFileOutputStream { public static void main(String[] args) { OutputStream osOutputStream = null; try { osOutputStream = new FileOutputStream(new File("E:/test/test2.txt")); osOutputStream.write(97); //在test2.txt中写入a; osOutputStream.close(); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
五、IO流(FileOutputStream追加)
public FileOutputStream(File file,
boolean append)
throws FileNotFoundExceptionFileOutputStream fos = new FileOutputStream("bbb.txt",true); //如果没有bbb.txt,会创建出一个bbb.txt
六、IO流(拷贝图片)
利用字节流完成图片的拷贝
-
程序
public class TestCopyPic { public static void main(String[] args) { InputStream iStream = null; OutputStream oStream = null; try { iStream = new FileInputStream(new File("E:/test/1.jpg")); oStream = new FileOutputStream(new File("E:/test/2.jpg")); //进行图片的拷贝 int b = 0; //单个字节进行拷贝 while((b = iStream.read()) != -1) { oStream.write(b); } //关流 iStream.close(); oStream.close(); } catch (IOException e) { // TODO: handle exception e.printStackTrace(); } } }
七、IO流(拷贝音频文件画原理图)
八、IO流(字节数组拷贝之available()方法)
-
public int available()
throws IOException- Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream(返回)
available()获取读的文件所有的字节个数
int read(byte[] b):一次读取一个字节数组
write(byte[] b):一次写出一个字节数组
-
程序
public class TestCopyPic_2 { public static void main(String[] args) { FileInputStream fiStream = null; FileOutputStream foStream = null; try { fiStream = new FileInputStream(new File("E:/test/1.jpg")); foStream = new FileOutputStream(new File("E:/test/3.jpg")); /*int b = fiStream.available(); //获取文件的字节个数 System.out.println(b);*/ //根据文件大小做一个字节数组 byte[] arr = new byte[fiStream.available()]; //将文件上的所有字节读取到数组中 fiStream.read(arr); //将数组中的所有字节一次写到了文件上 foStream.write(arr); fiStream.close(); foStream.close(); }catch (IOException e) { // TODO: handle exception e.printStackTrace(); } } } /* 此时拷贝成功 */
弊端:有可能会内存溢出
九、IO流(定义小数组)
write(byte[] b)
write(byte[] b, int off, int len)写出有效的字节个数
注意理解:read(byte[] b)方法的工作实质
* 返回的是有效字节的个数
* 因此不能直接输出字节数组内容
* 而是只输出到有效字节位数即可-
read(byte[] b)的理解
public class TestCopyPic_3 {
public static void main(String[] args) {
FileInputStream fiStream = null;
FileOutputStream foStream = null;try { //此时test.txt的大小为三个字节,内容为abc fiStream = new FileInputStream(new File("E:/test/test.txt")); foStream = new FileOutputStream(new File("E:/test/test1.txt")); byte[] arr = new byte[2]; //定义两个字节大小的数组 System.out.println("======第一次读取时:======"); int a = fiStream.read(arr); System.out.println("第一次读取时的有效字节个数;" + a); //a为读到的有效字节个数 System.out.print("第一次读取时的字节数组中内容;"); for(byte b : arr) { //遍历当前数组 System.out.print(b + " "); } System.out.println("\n======第二次读取时:======"); int a2 = fiStream.read(arr); System.out.println("第二次读取时的有效字节个数;" +a2); System.out.print("第二次读取时的字节数组中内容;"); for(byte b : arr) { System.out.print(b + " "); } fiStream.close(); foStream.close(); }catch (IOException e) { // TODO: handle exception e.printStackTrace(); } } } /* * ======第一次读取时:====== 第一次读取时的有效字节个数;2 第一次读取时的字节数组中内容;97 98 ======第二次读取时:====== 第二次读取时的有效字节个数;1 //由于字节数组大小为3,而第二次读取时,文件中只有一个c 第二次读取时的字节数组中内容;99 98 //原98的位置没有被覆盖,照常输出 * */
-
小数组实图片的拷贝
public static void main(String[] args) { FileInputStream fiStream = null; FileOutputStream foStream = null; try { //此时test.txt的大小为三个字节,内容为abc fiStream = new FileInputStream(new File("E:/test/1.jpg")); foStream = new FileOutputStream(new File("E:/test/copy.jpg")); int len = 0; byte[] arr = new byte[1024]; //1kb while((len = fiStream.read(arr)) != -1) { foStream.write(arr, 0, len); //将有效字节写入 } fiStream.close(); foStream.close(); } catch(IOException e) { e.printStackTrace(); } }
十、IO流(BufferedInputStream和BufferOutputStream拷贝)
-
A:缓冲思想
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
BufferedInputStream和BufferedOutputStream减少了内存到硬盘的读和写的次数,提高了效率。
-
原理图
-
B.BufferedInputStream
BufferedInputStream内置了一个缓冲区(数组)
从BufferedInputStream中读取一个字节时,BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
-
C.BufferedOutputStream
BufferedOutputStream也内置了一个缓冲区(数组)
程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
注意BufferedInoutStream和BufferedOutputStream在new时不抛出异常
-
程序
public static void main(String[] args) { FileInputStream fiStream = null; FileOutputStream foStream = null; BufferedInputStream biStream = null; BufferedOutputStream boStream = null; try{ fiStream = new FileInputStream(new File("E:/test/1.jpg")); foStream = new FileOutputStream(new File("E:/test/copy.jpg")); //创建BufferedInputStream和BufferedOutputStram biStream = new BufferedInputStream(fiStream); boStream = new BufferedOutputStream(foStream); //复制 int b = 0; while((b = biStream.read())!= -1) { boStream.write(b); } biStream.close(); //只关闭包装后的流即可 boStream.close(); }catch(IOException e) { e.printStackTrace(); } }
-
E.小数组的读写和带Buffered的读取哪个更快?
定义小数组如果是8192个字节大小和Buffered比较的话
定义小数组会略胜一筹,因为读和写操作的是同一个数组
而Buffered操作的是两个数组
BufferedOutputStream的源码中显示的是:在BufferedOutputStream类中自己定义了一个DEFAULT_BUFFER_SIZE = 8192的字节数组,作为缓存
十一、IO流(flush和close方法的区别)
-
public void flush() throws IOException(针对缓冲流而言的)
Flushes this output stream and forces any buffered output bytes to be written out.
The flush method of OutputStream does nothing.
-
flush()方法
- 用来刷新缓冲区的,刷新后可以再次写出
-
close()方法
- 用来关闭流释放资源的的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出
十二、IO流(字节流读写中文)
-
字节流读取中文的问题
- 字节流在读中文的时候有可能会读到半个中文,造成乱码
-
字节流写出中文的问题
字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组
* String中的getBytes方法
* oStream.write("I love you".getBytes());写出回车换行 write("\r\n".getBytes());
-
注意:string和byte之间的转化
* String->byte[]
* String中的getBytes方法
* oStream.write("I love you".getBytes());* byte[]->String * String中的构造方法 String(byte[] bytes, int offset, int length) * System.out.println(new String(bArr,0,len));
十三、IO流(流的标准处理异常代码一)
finally的嵌套使用
-
程序
public static void main(String[] args) throws IOException{ FileInputStream fiStream = null; FileOutputStream foStream = null; try { fiStream = new FileInputStream(new File("E:/test/1.jpg")); foStream = new FileOutputStream("E:/test/copy.jpg"); //doWork byte[] bArr = new byte[1024 * 3]; int len = 0; while((len = fiStream.read(bArr)) != -1) { foStream.write(bArr,0,len); } } finally { try { if(fiStream != null) fiStream.close(); }finally { //确保至少有一个流可关闭 if(foStream != null) { foStream.close(); } } } }
十四、IO流(流的标准处理异常代码二)1.7版本
- 不需要写关闭流的代码
- InputStream和OutputStream实现了Closable接口,Closable实现了AutoClosable接口
- 只要实现了AutoClosable接口就会被自动调用从而自动关闭流
-
程序
public static void main(String[] args) throws IOException{ //iStream和oStream的定义不可以写在try外面 try( //流的创建 InputStream iStream = new FileInputStream("E:/test/1.jpg"); OutputStream oStream = new FileOutputStream("E:/text/copy.jpg"); ){ //流操作 int len = 0; byte[] bArr = new byte[1024 * 3]; while((len = iStream.read(bArr)) != -1){ oStream.write(bArr,0,len); } } //流会自动关闭 }
十五、IO流(图片加密)
-
给图片加密
public static void main(String[] args) throws IOException{ try( //流的创建 BufferedInputStream bInputStream = new BufferedInputStream(new FileInputStream("E:/test/1.jpg")); BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream("E:/test/copyJiaMi.jpg")); ){ //文件复制加密 int b = 0; while((b = bInputStream.read()) != -1) { bOutputStream.write(b ^ 123); } } }
-
给图片解密
public static void main(String[] args) throws IOException{ try( //流的创建 BufferedInputStream bInputStream = new BufferedInputStream(new FileInputStream("E:/test/copyJiaMi.jpg")); BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream("E:/test/copyJieMi.jpg")); ){ //文件复制解密 int b = 0; while((b = bInputStream.read()) != -1) { bOutputStream.write(b ^ 123); } } }
十六、IO流(拷贝文件)
在控制台录入文件的路径,将文件拷贝到当前项目下
-
程序
-
分析
- 定义getFile()方法来获取用户输入并判断
- 主方法中实现文件的拷贝
- 注意面向对象的特点,尽量写出易读的代码
-
Code
public class TestIO_7 { public static void main(String[] args) throws IOException{ //创建输入输出流对象 BufferedInputStream biStream = null; BufferedOutputStream bOutputStream = null; try { //实例化流 biStream = new BufferedInputStream(new FileInputStream(getFile())); bOutputStream = new BufferedOutputStream(new FileOutputStream("des.jpg")); //文件拷贝 int b = 0; while((b = biStream.read()) != -1) { bOutputStream.write(b); } }finally { //关闭流 try { if(biStream != null) biStream.close(); }finally { bOutputStream.close(); } } } /* * 定义getFile()方法 * 1. 获取用户输入 * 2. 判断合法性,不合法重新输入 * 3. 封装成为File对象后返回 * */ public static File getFile() { //获取用户输入 Scanner input = new Scanner(System.in); File file = null; System.out.print("请输入源文件路径: "); while(true) { String line = input.nextLine(); file = new File(line); //封装为File对象,方便判断是否为文件 if(file.isFile()) { break; } else { System.out.println("您输入的文件不存在,请重新输入"); } } return file; } }
-
十七、IO流(录入数据拷贝到文件)
- 将键盘录入的数据拷贝到当前项目下的text.txt文件中,键盘录入数据当遇到quit时就退出
-
程序
public class TestIO_8 { public static void main(String[] args) throws IOException{ //接受用户输入 Scanner input = new Scanner(System.in); System.out.println("请输入内容:"); StringBuffer line = new StringBuffer(); String str; while(!input.hasNext("quit")) { str = input.nextLine(); line.append(str); } //将内容写入文件 writeFile(line.toString()); } private static void writeFile(String string) throws IOException{ // TODO Auto-generated method stub try( //创建输出流对象 BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream("text.txt")); ){ //将内容写入文件 bOutputStream.write(string.getBytes()); } } }