Java IO流什么是流?
概念:内存和存储设备之间传输数据的通道。
数据借助流传输。
流分类:
- 按照方向:输入流(将存储设备中的内容读入到内存中)和输出流(将内存中的内容写入到存储设备中)
- 按照单位:字节流(以字节为单位,可以读写所有数据)和字符流(以字符为单位,只能读取文本数据)
- 按照功能:节点流(具有实际传输数据的读写功能)和过滤流(在节点流的基础之上增强功能)
字节流
字节流的父类(抽象类):
- InputStream:字节输入流:提供一些如read(),close()的方法
- OutputStream:字节输出流:提供一些如write(),close()的方法
文件字节流
- FileInputStream:文件字节输入流,继承字节输入流
- FileOutputStream:文件字节输出流,继承字节输入流
文件字节输入流操作:
//创建FileInputStream并且指定文件路径FileInputStream fis = new FileInputStream("d:\\aa.txt");int data = 0;//read返回的int,当等于-1表示读完了,如果是字符返回对应的asc码//一次读取一个字节while ((data=fis.read())!=-1){ System.out.println((char) data);}/*abc
什么为一次读取一个字节的情况
当需要一次读取多个字节
//创建FileInputStream并且指定文件路径FileInputStream fis = new FileInputStream("d:\\aa.txt");//一次读取多个个字节byte[] buf = new byte[3];//本处read返回实际读取个数,读完返回-1,并且将读取到的存储在buf中//因为数组大小一次读取三个System.out.println(fis.read(buf));System.out.println(new String(buf));fis.close();/*3abc*///或者FileInputStream fis = new FileInputStream("d:\\aa.txt"); byte[] buf = new byte[3]; int count=0; while ((count=fis.read(buf))!=-1){ System.out.println(new String(buf,0,count)); } fis.close();/*abcdefg
本处只是例子,实际操作时缓冲区数组不需要创建得太小,可以是1024以上
文件字节输出流操作:
//创建文件字节输出流,为true代表文件已经存在时追加,false每次都会覆盖(默认)FileOutputStream fos=new FileOutputStream("d://aa.txt",false);fos.write(97);fos.write('b');fos.write('c');//文件中:abc//要写入字符串:转成byte数组String s = "helloworld";fos.write(s.getBytes());//文件中:abchelloworld
实现复制操作:
FileInputStream fis = new FileInputStream("d:\\aa.txt");FileOutputStream fos = new FileOutputStream("d:\\bb.txt");byte[] buf = new byte[1024];int count=0;while ((count=fis.read(buf))!=-1){ fos.write(buf,0,count);}fis.close();fos.close();
字节缓冲流
- 缓冲流:BufferedInputStream/BufferedOutputStream
- 继承了过滤流(FilterOutputStream/FilterInputStream),而过滤流又继承了文件字节流
- 内置了缓存区(8k)
- 作用:提高IO效率,减少访问磁盘次数;数据存储在缓存区,flush是将缓冲区的内容写入文件中,也可以直接close,后面实现缓冲区的类类似
字节输入缓冲流:
// 创建BufferedInputStream,需要传入一个底层流 FileInputStream fis = new FileInputStream("d:\\aa.txt"); BufferedInputStream bis = new BufferedInputStream(fis);// 读取:类似,但是这个有缓冲区效率更高 int data = 0; while ((data=bis.read())!=-1){ System.out.print((char)data); } //当然也可以和文件字节流一样,直接再创建一个缓冲区实现,一模一样但是因为内部缓冲区的存在效率更高 // 关闭这一个就行 bis.close();//out:abchelloworld
字节输出缓冲流:
FileOutputStream fos = new FileOutputStream("d://bb.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);//转义符如换行等也可以写入也可以String s = "hello\r\n";bos.write(s.getBytes());//这是写入了缓冲区,没有写入文件bos.flush();//需要刷新才能从缓冲区真正写入文件bos.close();//当然close时自动flush
对象流
- 对象流:ObjectOutputStream/ObjectInputStream
- 可以实现写入或者读取对象
- 增强了缓冲区功能
- 增强了读写8种基本数据类型和字符串的功能,不只是能读写int和byte
- readObject()从流中读取一个对象;writeObject(Object obj)向流中写入一个对象
- 使用流传输对象的过程被称为序列化(写入)和反序列化(读取)
- 继承文件字节流,需要基于其才能创建
- 序列化和反序列化的对象类都必须实现Serializable接口(该接口本身没有任何方法仅仅标志该类可以序列化),而且其中关联的其他类也要实现该接口
- 可以在类中自定义生成常量private static final long serialVersionUID ,该常量为序列化版本号用来标识该类,即使是同一个类如果UID不同依旧被认为不是同一个类无法反序列化不同UID的类
- 使用transient修饰实现,表示该属性不需要序列化(例如:private transient int age )
- 静态属性不能序列化
序列化:
public class Student implements Serializable {}//main:FileOutputStream fos = new FileOutputStream("d://aa.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos);// 序列化 Student student = new Student(); oos.writeObject(student);// oos.writeBoolean();写入boolean// oos.writeBytes("hellow");//写入字符串// 其他基本类型也有相应的办法写入 oos.close();
反序列化:
FileInputStream fis = new FileInputStream("d://aa.txt");ObjectInputStream ois = new ObjectInputStream(fis);//读取存入的第一个对象Student s = (Student)ois.readObject();ois.close();
序列化、反序列化多个对象时可以使用集合:
//序列化 FileOutputStream fos = new FileOutputStream("d://aa.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos);// 序列化 Student student = new Student(); Student student1 = new Student(); ArrayList arrayList = new ArrayList(); arrayList.add(student); arrayList.add(student1); oos.writeObject(arrayList); oos.close();//反序列化FileInputStream fis = new FileInputStream("d://aa.txt"); ObjectInputStream ois = new ObjectInputStream(fis); ArrayList arrayList = (ArrayList) ois.readObject(); ois.close();
常见字符编码
字符流
问题的引出:
FileInputStream fis = new FileInputStream("d://aa.txt");int data = 0;while ((data=fis.read())!=-1){ System.out.println((char)data);}fis.close();//上述代码当我们读取的文件中为中文时得到乱码。//原因:我们是运用字节流一个一个字节读取文件,而本处的文件编码方式是utf-8(中文常见的编码方式),每个中文字占3个字节。当一个一个字节读取时出现乱码
这种情况下我们需要字符流
字符流的父类(抽象类):
Reader(字符输入流)和Writer(字符输出流)
只能用于文本文件
文件字符流
- FileReader和FileWriter
- 父类是InputStreamReader和OutputStreamWriter,而这两者的父类又是Reader和Writer
- 采用默认字符编码
FileReader:
FileReader fr = new FileReader("d://aa.txt"); //单个字符的读取// int data = 0;// while ((data=fr.read())!=-1){//读取一个字符// System.out.println((char)data);// }//创建缓冲区读取//缓冲区为2字符 char[] buf = new char[2]; int count = 0; while ((count = fr.read(buf))!=-1){ System.out.println(new String(buf,0,count)); } fr.close();/*out:你好呀
FileWriter:
FileWriter fw = new FileWriter("d://aa.txt");fw.write("你好吗");fw.flush();fw.close();
字符缓冲流
- 缓冲流:BufferedReader/BufferedWriter
- 高效读写
- 支持输入换行符
- 可以一次写一行、读一行
- 可以指定缓冲区大小,也可以默认(8K)
- 新建需要基础字符流(文件字符流)
- 继承Reader和Writer
读取:
FileReader fr = new FileReader("d://aa.txt"); BufferedReader br = new BufferedReader(fr);// 和上面其他类类似的方法不再重写// 特有的:读一行,末尾返回null String s = null; //一行一行的读取 while ((s=br.readLine())!=null){ System.out.println(s); } br.close();//out:你好呀
写入:
FileWriter fw = new FileWriter("d:\\aa.txt"); BufferedWriter bw = new BufferedWriter(fw);// 写入 bw.write("好好学习");// 写入一个换行windows:\r\n linux:\n bw.newLine(); bw.write(",天天向上"); bw.close();/*文件:好好学习,天天向上
打印流
PrintWriter:
- 支持print()/println(),支持写入后换行
- 支持数据原样打印
- 继承Writer类
- 类似PrintStream,但是PrintWriter只能打印字符流,而PrintStream可以打印字节流
PrintWriter pw = new PrintWriter("d://aa.txt");// 打印并且换行 pw.println(97); pw.println(true);//打印 pw.print("a");pw.print("b"); pw.close();/*文件中:97trueab
转换流
- 也叫桥转换流:InputStreamReader/OutputStreamWriter
- 可以将字节流转换为字符流
- 可设置字符的编码方式
- 继承字符流Reader/Writer
- 创建时需要基本的文件字符流
InputStreamReader:
FileInputStream fis = new FileInputStream("d://aa.txt");InputStreamReader isr = new InputStreamReader(fis,"utf-8");int data=0;//一个一个字符读取while ((data=isr.read())!=-1){ System.out.print((char)data);}isr.close();
OutputStreamWriter:
FileOutputStream fos = new FileOutputStream("d://aa.txt");OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");for(int i=0;i<10;i++){ osw.write("我爱中国\r\n"); osw.flush();}osw.close();
File类
- 概念:代表物理盘符中的一个文件或者文件夹
// 分隔符 System.out.println("路径分割符"+File.pathSeparator); System.out.println("名字分割符"+File.separator); File file = new File("d://cc.txt");// 判断文件是否存在 if(!file.exists()){// 创建文件 boolean b = file.createNewFile(); System.out.println("创建结果:"+b); } if(file.exists()) {// 直接删除 System.out.println("删除结果" + file.delete()); //使用jvm退出时删除 file.deleteOnExit(); }// 获取文件信息 System.out.println("绝对路径"+file.getAbsolutePath()); //看你创建时传入的路径 System.out.println("获取路径"+file.getPath());// 获取名称 System.out.println("获取名称"+file.getName());// 获取父目录 System.out.println("获取父目录"+file.getParent());// 获取文件长度 System.out.println("获取文件长度"+file.length());// 文件创建时间 System.out.println("文件创建时间"+new Date(file.lastModified()).toString());// 判断文件是否可写 System.out.println("是否可写"+file.canWrite());// 是否是文件 System.out.println("是否是文件"+file.isFile());// 是否隐藏 System.out.println("是否隐藏"+file.isHidden());/*路径分割符;名字分割符\创建结果:true删除结果true绝对路径d:\cc.txt获取路径d:\cc.txt获取名称cc.txt获取父目录d:\获取文件长度0文件创建时间Thu Jan 01 08:00:00 CST 1970是否可写false是否是文件false是否隐藏false
文件夹操作:
File dir = new File("d://cc/aa");// 判断文件是否存在 if(!dir.exists()){// 创建文件夹:只能创建单集目录// boolean b = dir.mkdir();// 创建多级目录 boolean b = dir.mkdirs(); System.out.println("创建结果:"+b); } if(dir.exists()) {// 直接删除:最下层且必须为空目录 System.out.println("删除结果" + dir.delete()); //使用jvm退出时删除,休眠结束后删除 dir.deleteOnExit(); Thread.sleep(5000); }// 获取文件信息 System.out.println("绝对路径"+dir.getAbsolutePath()); //看你创建时传入的路径 System.out.println("获取路径"+dir.getPath());// 获取名称 System.out.println("获取名称"+dir.getName());// 获取父目录 System.out.println("获取父目录"+dir.getParent());// 文件创建时间 System.out.println("文件创建时间"+new Date(dir.lastModified()).toString());// 判断是否是文件夹 System.out.println("是否可写"+dir.isDirectory());// 是否隐藏 System.out.println("是否隐藏"+dir.isHidden());// 遍历文件夹 String[] file = dir.list();
FileFilter接口
public interface FileFIlter
- boolean accept(File pathname)
当调用File类的listFiles()方法时,支持传入一个实现了FileFilter接口的实现类对文件进行过滤,只有满足条件的文件才能出现在listFiles()返回值中
实现过滤
File dir = new File("d://cc/aa");File[] files= dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { //如果名字以.jpg结尾返回,否则不返回 if(pathname.getName().endsWith(".jpg")){ return true; } else{ return false; } } });
递归遍历文件夹(递归删除文件夹:先把文件内删空再删除文件夹):
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { listDir(new File("d://aa"));}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.getAbsolutePath()); } } }}
Prorerties
属性集合
特点:
- 存储属性名和属性值
- 属性名和属性值都是字符串类型
- 没有泛型
- 继承Hashtable集合,具体看集合那一章笔记
- 和流有关
// 创建集合 Properties properties = new Properties();// 添加数据 properties.setProperty("username","zhangsan"); properties.setProperty("age","20"); System.out.println(properties.toString()); //遍历// 1.keySet遍历// properties.keySet();// 2.entrySet遍历// 3.stringPropertyNames变量 Set set = properties.stringPropertyNames(); for (String s : set) { System.out.println(s+":"+properties.getProperty(s)); }// 和流有关的办法// list方法 PrintWriter pw = new PrintWriter("d://aa.txt"); //将properties写入该文件 properties.list(pw); pw.close(); //store方法保存写入该文件 FileOutputStream fos = new FileOutputStream("d://aa.txt"); properties.store(fos,"这是注释"); fos.close();/*{age=20, username=zhangsan}age:20username:zhangsan
Properties properties1 = new Properties();FileInputStream fis = new FileInputStream("d://aa.txt");properties1.load(fis);fis.close();System.out.println(properties1.toString());//{age=20, username=zhangsan}