【java】IO流
一、流的概念
是内存与存储设备之间传输数据的通道。
二、流的分类
1. 按照方向分:
(1)输入流:将<存储设备>中的内容读入到<内存>中
(2)输出流:将<内存>中的内容写入到<存储设备>中
2. 按处理单位分:
(1)字节流:以字节为单位,可以读写所有数据
(2)字符流:以字符为单位,只能读写文本数据
3. 按功能分:
(1)节点流:具有实际传输数据的读写功能。
(2)过滤流:在节点流的基础之上增强功能。
三、字节流
3.1 字节流
字节流的父类(抽象类):InputStream:字节输入流(read)、OutputStream:字节输出流(write)
文件字节流:FileInputStream、FileOutputStream
案例:
//单个字节读取 public static void main(String[] args) throws Exception {//这里为了代码可读性,异常暂时抛出 //1. 创建FileInputStream,并指定文件路径 FileInputStream fis = new FileInputStream("d:\\aa.txt"); //2. 读取文件 data对象用来保存我们读取的字节 int data = 0; //如果都读取完了,会返回-1 ,不过这个read方法读取比较慢,是一个字节一个字节的读 while ((data=fis.read())!=-1){ System.out.println((char)data);//假设txt文件中存的是abcdefg ,那么每次会输出一个 } //3. 关闭 fis.close(); } //多个字节读取 public static void main(String[] args) throws Exception{ //1. 创建FileInputStream,并指定文件路径 FileInputStream fis = new FileInputStream("d:\\aa.txt"); //2. 创建一个数组用来存放读取到的字节,这里暂定长度为3 byte[] buf = new byte[3]; //3. 读取文件 count就是我们实际读取的字节数 int count = 0; //如果都读取完了,会返回-1 ,这个read方法,是按照上面数组的长度,即三个三个的读 while ((count=fis.read(buf))!=-1){ System.out.println(new String(buf,0,count));//假设txt文件中存的是abcdefg ,那么每次会输出三个 } //4. 关闭 fis.close(); } //输出流写入 public static void main(String[] args) throws Exception{ //1. 创建文件字节输出流对象 ,没有此文件会创建,有此文件调用下面的write方法的时候会覆盖txt里的内容。 FileOutputStream fos = new FileOutputStream("d:\\bb.txt"); //可以通过加参数 true 来实现非覆盖而是追加的效果 //FileOutputStream fos = new FileOutputStream("d:\\bb.txt",true); //2. 写入文件. String str = "helloword"; //str.getBytes()意思为获取这个字符串所对应的字符数组 fos.write(str.getBytes()); //3. 关闭 fos.close(); } //使用文件字节流(输入流和输出流)实现文件的复制 //注意:文件字节流不带缓冲效率会比较低 public static void main(String[] args) throws Exception{ //1. 创建流 //1.1 文件字节输入流 ,如果没有会报错java.io.FileNotFoundException: d:\001.jpg (系统找不到指定的文件。) FileInputStream fis = new FileInputStream("d:\\001.jpg"); //1.2 文件字节输出流 FileOutputStream fos = new FileOutputStream("d:\\002.jpg"); //2. 一边读,一边写 byte[] buf = new byte[1024]; int count =0; while((count=fis.read(buf))!=-1){ fos.write(buf,0,count); } //3. 关闭 fis.close(); fos.close(); }
3.2 字节缓冲流
缓冲流:BufferedInputStream、BufferedOutputStream
作用:
(1)提高IO效率,减少访问磁盘的次数
(2)数据存储在缓存区中,flush是将缓存区的内容写入文件中,也可以直接close.
//输入缓冲流 public static void main(String[] args) throws Exception{ //1. 创建文件输入流 FileInputStream fis = new FileInputStream("d:\\aa.txt"); //2. 创建缓冲流,来增强文件输入流 BufferedInputStream bis = new BufferedInputStream(fis); //3. 读取 int data = 0; //注意:这里read并非一个个的读,而是一次读8k到缓冲区,即BufferedInputStream源码中的private static int DEFAULT_BUFFER_SIZE = 8192; while ((data=bis.read())!=-1){ System.out.println((char)data); } //当然也可以自己定义缓冲区 //byte[] buf = new byte[1024]; //int count =0; //while ((count=bis.read(buf))!=-1){ //System.out.println(new String(buf,0,count)); //} //4. 关闭 只关闭缓冲流即可,它内部会把文件输入流也关闭了. bis.close(); } //输出缓冲流 public static void main(String[] args) throws Exception{ //1. 创建字节输出流 FileOutputStream fos = new FileOutputStream("d:\\cc.txt"); //2. 创建字节输出缓冲流 BufferedOutputStream bos = new BufferedOutputStream(fos); //3. 写入文件 for(int i=0;i<10;i++){ bos.write("helloworld".getBytes());//只要不超过8k都会写入到8k缓冲区,此时文件中实际上是没有内容的 bos.flush();//只有刷新才会将数据刷新到硬盘 } //4. 关闭(内部也会调用flush方法) bos.close(); }
3.3 对象流+(反)序列化
对象流:ObjectOutputStream、ObjectInputStream 使用流传输对象的过程称为序列化/反序列化。
作用:
(1)增强了缓冲区功能。
(2)增强了读写8中基本数据类型和字符串功能。
(3)增强了读写对象的功能 readObject() 从流中读取一个对象 writeObject(Object obj) 向流中写入一个对象。
要求:
(1)序列化类必须要实现Serializable接口
(2)序列化类中对象属性也要求实现Serializable接口
(3)序列化版本号ID(serialVersionUID),保证序列化的类和反序列化的类是同一个类
(4)使用transient(瞬间的)修饰属性,这个属性不能序列化
(5)静态属性也不能序列化
(6)序列化多个对象 即下面的例子中可以创建多个对象,之后将多个对象放入一个list中,当然获取的时候返回的也是一个List即可
案例:
//使用ObjectOutputStream实现对象的序列化 public static void main(String[] args) throws Exception{ //1. 创建文件输出流 FileOutputStream fos = new FileOutputStream("d:\\stu.bin"); //2. 创建文件输入流 ObjectOutputStream oos = new ObjectOutputStream(fos); //3. 创建一个对象并赋值 //注意:这里要求必须要对象实现序列化,否则会报错java.io.NotSerializableException: com.company.Student Student stu = new Student(); stu.setAge(21); stu.setName("张三"); //4. 写入操作(序列化) oos.writeObject(stu); //5. 关闭 oos.close(); } //这里要求对象必须实现序列化 public class Student implements Serializable { private String name; private int age; //private transient int age;//被transient修饰的不能序列化,即序列化后再反序列化是没值的 private static final long serialVersionUID = -8778349856468359639L; //省略setter、getter、toString方法 } //使用ObjectInputStream实现反序列化(读取重构成对象) public static void main(String[] args) throws Exception{ //1. 创建文件输入流 FileInputStream fis = new FileInputStream("d:\\stu.bin"); //2. 创建对象流 ObjectInputStream ois = new ObjectInputStream(fis); //3. 读取文件(反序列化) Student stu = (Student)ois.readObject(); //4. 关闭 ois.close(); System.out.println(stu.toString());//结果: Student{name='张三', age=21} }
四、编码方式
常见编码字符
1. ISO-8859-1 收录除了ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号
2. UTF-8 针对Unicode码表的可变长度字符编码
3. GB2312 简体中文
4. GBK 简体中文、扩充
5. BIG5 台湾,简体中文
当编码方式和解码方式不一致时,会出现乱码。
五、字符流
5.1 字符流
涉及到汉字的一般用字符流 FileReader、FileWriter
字符流的父类(抽象类):Reader:字符输入流 read()、Writer:字符输出流 write()
案例:
//FileReader读取文件 public static void main(String[] args) throws Exception{ //1. 创建FileReader 文件字符输入流 FileReader fr = new FileReader("d:\\hello.txt"); //2. 读取 (单个字符读取) int data = 0; while ((data=fr.read())!=-1){ System.out.println((char)data); } //3. 关闭 fr.close(); } //FileWriter写入文件 public static void main(String[] args) throws Exception{ //1. 创建FileWriter对象 FileWriter fw = new FileWriter("d:\\write.txt"); //2. 写入 for(int i=0;i<10;i++){ fw.write("你好"); fw.flush(); } //3. 关闭 fw.close(); } //使用FileWriter和FileReader复制文件 //注意:只能复制文本文件,不能复制图片和二进制文件(声音/视频等) 字节流可以复制任何文件 public static void main(String[] args) throws Exception{ //1. 创建FileWriter和FileReader FileReader fr = new FileReader("d:\\write.txt"); FileWriter fw = new FileWriter("d:\\write2.txt"); //2. 读写 int data=0; while ((data=fr.read())!= -1){ fw.write(data); fw.flush(); } //3. 关闭 fr.close(); fw.close(); }
5.2 字符缓冲流
缓冲流:BufferedReader、BufferedWriter
作用:
(1)高效读写(缓冲区)
(2)支持输入换行符
(3)可一次读/写一行
//使用字符缓冲流读取文件 (单个字符读+一行一行读) public static void main(String[] args) throws Exception{ //1. 创建缓冲流 FileReader fr = new FileReader("d:\\write.txt"); BufferedReader br = new BufferedReader(fr); //2. 读取 //2.1 第一种 //char[] buf = new char[1024]; //int count = 0; //while ((count=br.read())!=-1){ //System.out.println(new String(buf,0,count)); //} //2.2 第二种 一行一行读 String line = null; while ((line=br.readLine())!=null){ System.out.println(line); } //3. 关闭 br.close(); } //使用字符缓冲流写入文件 public static void main(String[] args) throws Exception{ //1. 创建缓冲流 FileWriter fw = new FileWriter("d:\\buffer.txt"); BufferedWriter bw = new BufferedWriter(fw); //2. 写入 for(int i=0;i<10;i++){ bw.write("你好"); bw.newLine();//写入一个换行符 windows:\r\n linux:\n bw.flush(); } //3. 关闭 bw.close(); }
六、打印流
PrintWriter:
作用:
(1)封装了print() / println() 方法,支持写入后换行
(2)支持数据原样打印
//PrintWriter的使用 public static void main(String[] args) throws Exception{ //1. 创建打印流 PrintWriter pw = new PrintWriter(""); //2. 打印 pw.println(97);//换行 打印到文件之后不会变成a,仍然是97 pw.print(true);//不换行 打印到文件里是true字符串 pw.println('a');//打印到文件里是a //3. 关闭 pw.close(); }
七、转换流
又称为桥转换流:InputStreamReader、OutputStreamWriter
(1)可将字节流转换为字符流
(2)可设置字符的编码方式
案例:
//使用InputStreamReader读取文件,指定使用的编码 public static void main(String[] args) throws Exception{ //1. 创建InputStreamReader对象 FileInputStream fis = new FileInputStream("d:\\write.txt"); InputStreamReader isr = new InputStreamReader(fis,"utf-8");//gbk //2. 读取文件 int data=0; while ((data=isr.read())!=-1){ System.out.println((char)data); } //3. 关闭 isr.close(); } //使用OutputStreamWriter写入文件,指定使用的编码 public static void main(String[] args) throws Exception{ //1. 创建OutputStreamWriter对象 FileOutputStream fos = new FileOutputStream("d:\\info.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk"); //2. 写入文件 for(int i=0;i<10;i++){ osw.write("你好"); osw.flush(); } //3. 关闭 osw.close(); }
八、File对象
8.1 概念和方法
概念:代表物理盘符中的一个文件或者文件夹
方法:
(1)createNewFile() # 创建一个新文件
(2)mkdir() # 创建一个新目录
(3)delete() # 删除文件或空目录
(4)exists() # 判断File对象所代表的对象是否存在
(5)getAbsolutePath() # 获取文件的绝对路径
(6)getName() # 取得文件的名字
(7)getParent() # 获取文件/目录所在的父目录
(8)isDirectory() # 是否是目录
(9)isFile() # 是否是文件
(10)length() # 获得文件的长度
(11)listFiles() # 列出目录中的所有内容
(12)renameTo() # 修改文件名为
8.2 文件操作
8.2.1 分隔符
路径分隔符+名称分隔符
案例:
//分隔符 public static void main(String[] args) throws Exception{ separator(); } public static void separator(){ //路径分隔符,结果为一个分号 ; (还记得配置环境变量中的path里都是用分号隔开的嘛) System.out.println(File.pathSeparator); //名称分隔符 结果为一个斜线 \ (windows下电脑文件的目录) System.out.println(File.separator); }
8.2.2 文件操作
创建文件+删除文件+获取文件信息+判断
案例:
//文件操作 public static void main(String[] args) throws Exception{ //1. 创建文件 File file = new File("d:\\file.txt"); //判断文件是否存在 if(!file.exists()){ //判断文件是否创建成功 如果文件没有返回true: 成功 如果文件已经存在返回false boolean b = file.createNewFile(); } //2. 删除文件 删除成功true boolean result = file.delete(); // 使用jvm退出时删除文件 //file.deleteOnExit(); //加5s延时是为了看到效果 //Thread.sleep(5000); //3. 获取文件信息 绝对路径 getPath为相对路径,即上面写什么就是什么 String url = file.getAbsolutePath();//结果为d:\file.txt //获取名称 String name = file.getName();//结果为:file.txt //获取父目录 String parentsource = file.getParent();//结果为:d:\ //获取文件的长度 字节数 long length = file.length(); //获取文件的创建时间 String data = new Date(file.lastModified()).toLocaleString();//结果为年月日时分秒的结构 //4.判断 //判断是否可写 boolean iswrite = file.canWrite(); //判断是否是文件 boolean isFile = file.isFile(); //判断是否是隐藏的 boolean ishide = file.isHidden(); }
8.2.3 文件夹操作
创建+删除+获取信息+判断+遍历
案例:
//文件夹操作 public static void main(String[] args) throws Exception{ //1. 创建文件夹 File dir = new File("d:\\aa\\bb\\cc"); //判断文件夹是否存在 if(!dir.exists()){ //创建文件夹 mkdir:创建单级目录 mkdirs:创建多级目录 boolean b = dir.mkdirs(); } //2. 删除文件夹 这个删除是只删除最底层的,比如上面的cc目录,并且要求里面是空的 boolean result = dir.delete(); // 使用jvm退出时删除文件夹 //dir.deleteOnExit(); //加5s延时是为了看到效果 //Thread.sleep(5000); //3. 获取文件夹信息 绝对路径 getPath为相对路径,即上面写什么就是什么 String url = dir.getAbsolutePath();//结果为d:\aa\bb\cc // 获取名称 String name = dir.getName();//结果为:cc //获取父目录 String parentsource = dir.getParent();//结果为:d:\aa\bb //获取文件的创建时间 String data = new Date(dir.lastModified()).toLocaleString();//结果为年月日时分秒的结构 //4.判断 //判断是否是文件夹 boolean isdirectory = dir.isDirectory(); //判断是否是隐藏的 boolean isFile = dir.isHidden(); //5. 遍历文件夹 File dir2 = new File("d:\\图片"); String[] files = dir2.list();//返回的是字符串数组 //File[] files2 = dir2.listFiles();//返回的是file数组 for(String str:files){ System.out.println(str); } }
8.3 FileFilter接口
public interface FileFilter boolean accept(File pathname)
当调用File类中的listFiles()方法时,支持传入FileFilter接口接口实现类,对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中.
案例:
public static void main(String[] args) throws Exception{ File dir = new File("d:\\图片"); File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { //只筛选.jpg结尾的文件 if(pathname.getName().endsWith(".jpg")){ return true; } return false; } }); for(File file:files){ System.out.println(file.getName()); } }
8.4 递归遍历和递归删除
递归遍历文件夹+递归删除文件夹
public static void main(String[] args) throws Exception{ //递归遍历文件夹 listDir(new File("d:\\myfiles")); //递归删除文件夹 deleteDir(new File("d:\\myfiles")); } //递归遍历文件夹 public static void listDir(File dir){ File[] files = dir.listFiles(); if(files!=null&&files.length>0){ for(File file:files){ if(file.isDirectory()){ listDir(file);//这用到了递归 }else { System.out.println(file.getAbsoluteFile()); } } } } //递归删除文件夹 public static void deleteDir(File dir){ File[] files = dir.listFiles(); if(files!=null&&files.length>0){ for(File file:files){ if(file.isDirectory()){ deleteDir(file);//递归 }else{ file.delete(); } } } dir.delete(); }
8.5 Properties
Properties:属性集合
特点:
(1)存储属性名和属性值
(2)属性名和属性值都是字符串类型
(3)没有泛型
(4)和流有关
案例:
public static void main(String[] args) throws Exception{ //1. 创建一个集合 Properties properties = new Properties(); //2. 添加数据 properties.setProperty("username","zhangsan"); properties.setProperty("age","20"); System.out.println(properties.toString());//结果为:{age=20, username=zhangsan} //3. 遍历 //3.1 keySet //3.2 entrySet //3.3 stringPropertiesNames() Set<String> pronames = properties.stringPropertyNames(); for(String pro:pronames){ System.out.println(pro+"---"+properties.getProperty(pro));//结果:age---20 username---zhangsan } //4. 和流有关的方法 //-----------list------------ PrintWriter pw = new PrintWriter("d:\\print.txt"); properties.list(pw); //之后print.txt文件中就有两条数据了 age=20 username=zhangsan pw.close(); //-----------store保存----------- FileOutputStream fos = new FileOutputStream("d:\\print.properties"); properties.store(fos,"注释"); fos.close(); //-----------load加载------------ Properties properties2 = new Properties(); FileInputStream fis = new FileInputStream("d:\\store.properties"); properties2.load(fis); fis.close(); }
参考:
1. 千锋教育视频
持续更新!!!