IO
什么是流?
概念:内存与存储设备(硬盘)之间传输数据的通道。
数据借助流传输。
流的分类
按流向:
-
输入流:将【存储设备】中的数据内容读到【内存】中。
-
输出流:将【内存】中的数据内容读到【存储设备】中。
按单位:
-
字节流:以字节为单位,可以读写所有数据。
-
字符流:以字符为单位,只能读写文本数据。
按功能:
-
节点流:具有实际传输数据的读写功能。
-
过滤流:再节点流的基础之上增强功能。
字节流
字节流的父类(抽象类):
InputStream: public int read(){} public int read(byte[] b){} public int read(byte[] b,int off,int len){} OutputStream: public void write(int n){} public void write(byte[] b){} public void write(byte[] b,int off,int len){}
FileInputStream的使用:
FileInputStream fis = new FileInputStream("D:\\a.txt"); --创建FileInputStream,并指定需要读取文件的路径 fis.read(); --单个字节读取文件内容 int data = 0; while((data = fis.read()) != -1){ System.out.println((char)data); } fis.close(); --关闭 ? ? FileInputStream fis = new FileInputStream("D:\\a.txt"); byte[] buf = new byte[1024]; -- 一次性读取多个字节,使用数组进行缓冲 int count = 0; while((count=fis.read(buf)) != -1){ System.out.println(new String(buf,0,count)); }
FileOutputStream的使用:
FileOutputStream fos = new FileOutputStream("D:\\b.txt",true); --创建FileOutputStream对象,指定输出文件的路径 当后面加上true时,则是在文件后面追加内容,而不是全部覆盖。 fos.write(97); --单个字节输出 fos.write('b'); fos.write('c'); ? String string = "helloword"; --多个字节输出,调用getBytes()方法,转化为字节 fos.write(string.getBytes()); fos.close();
应用:文件复制
FileInputStream fis = new FileInputStream("D:\\a.jpg"); FileOutputStream fos = new FileOutputStream("D:\\b.jpg"); 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
-
提高IO效率,减少访问磁盘的次数。
-
数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close。
FileInputStream fis = new FileInputStream("D:\\a.jpg"); BufferedInputStream bis = new BufferedInputStream(fis); int data = 0; while((data = bis.read()) != -1){ System.out.print((char(data))); } bis.close(); System.out.print("执行完毕!"); FileOutputStream fos = new FileOutputStream("D:\\b.jpg"); BufferedOutputStream bos = new BufferedOutputStream(fos); for(int i=0; i<10; i++){ bos.write("helloword\r\n".getBytes()); --只是写入缓冲区,还没有写入文件 bos.flush(); --刷新到硬盘 } bos.close();
对象流
ObjectOutputStream/ObjectInputStream
-
增强了缓冲区功能。
-
增强了读写8种基本数据类型和字符串功能。
-
增强了读写对象的功能。
-
readObject() --从流中读取一个对象
-
writeObject() --向流中写入一个对象
-
使用流传输对象的过程称为序列化、反序列化。
序列化
使用ObjectOutputStream实现对象的序列化。 注意点:序列化的对象必须要实现Serializable接口,否则会报异常 ? 1.创建对象流 FileOutputStream fos = new FileOutputStream("D:\\stu.bin"); ObjectOutputStream oos = new ObjectOutputStream(fos); 2.序列化(写入操作) Student lihui = new Student("lihui",20); oos.writeObject(lihui); 3.关闭 oos.close(); System.out.print("执行完毕!") ? public class Student implements Serializable{ ? }
反序列化
1.创建对象流 FileInputStream fis = new FileInputStream("D:\\stu.bin"); ObjectInputStream ois = new ObjectInputStream(fis); 2.读取文件(反序列化) Student s = (Student)ois.readObject(); 3.关闭 ois.close(); System.out.println("执行完毕!"); System.out.println(s.toString());
注意事项:
-
序列化类必须要实现Serializable接口。
-
序列化类中对象属性要求实现Serializable接口(类属性里夹杂了其它类对象)。
-
序列化版本号ID serialVersionUID,保证系列化的类和反序列化的类是同一个类。
-
使用transient(瞬间的)修饰属性,这个属性不能被序列化。
-
静态属性不能被序列化。
-
序列化多个对象,可以借助集合实现。
字符编码
ISO-8859-1:一般是美国使用,英文中一个字母代表一字节。中国字比较复杂,1字节=8位。
1字节(byte)=8位(bit)
1024字节=1K
1024k=1M
UTF-8:国际使用,基本上所有语言都包括。
GBK2312:简体中文。
GBK:简体中文,扩充。
当编码方式与解码方式不一致时,会出现乱码。
字符流
读取文件中的中文内容,中文并不是一个字代表一个字节,而是一个字代表多个字节,因此,使用字节流读取会出现乱码,要使用字符流。
字符流的父类(抽象类):
Reader:字符输入流 public int read(){} public int read(char[] c){} public int read(char[] b,int off,int len){} Writer:字符输出流 public void write(int n){} public void write(String str){} public void write(char[] c){}
文件字符流
-
FileReader:
public int read(char[] c)
-
FileWriter:
public void write(String str)
FileReader
1.创建FileReader 文件字符输入流 FileReader fr = new FileReader("D:\\hello.txt"); 2.读取 char[] buf = new char[1024]; int count = 0; while((count=fr.read(buf)) != -1){ System.out.println(new String(buf,0,count)); } 3.关闭 fr.close();
FileWriter
1.创建FileWriter对象 FileWriter fw = new FileWriter("D:\\hello.txt"); 2.写入 for(int i=0; i<10; i++){ fw.writer("java是世界上最好的语言!"); fw.flush(); } 3.关闭 fw.close();
应用:字符流复制文件
1.创建写入写出对象 FileReader fr = new FileReader("D:\\hello.txt"); FileWriter fw = new FileWriter("D:\\hello1.txt"); 2.读写 int data = 0; while((data=fr.read()) != -1){ fw.write(data); fw.flush(); } fr.close(); fw.close();
注意:
-
使用FileReader和FileWriter复制文本文件,不能复制图片或二进制文件(0101010....)。
-
使用字节流可以复制任何形式文件。
字符缓冲流
BuffererReader\BufferedWrite
-
高效读写
-
支持输入换行符
-
可一次写一行、读一行 readLine()
1.创建缓冲流 FileReader fr = new FileReader("D:\\hello.txt"); BufferedReader br = new BufferedReader(fr); 2.读取 char[] buf = new char[1024]; int count = 0; while((count = br.read()) != -1){ System.out.print(new String(buf, 0, count)); } 3.关闭 br.close(); ? -- 也可以一行一行读取 String line = null; while((line = br.readLine() != null)){ System.out.println(line); } 1.创建缓冲流 FileWrite fw = new FileWrite("D:\\HELLO.txt"); BufferedWrite bw = new BufferedWrite(fw); 2.写入 for(i =0; i<10; i++){ bw.write("好好学习,天天向上!"); bw.newLine(); --写入一个换行符 bw.flush(); } 3.关闭 bw.close();
打印流
PrintWrite()的使用:
-
封装了prInt()/println()方法,支持写入后换行。
-
支持数据原样打印。
1.创建打印流 PrintWrite pw = new PrintWrite("D:\\print.txt"); 2.打印 pw.println(97); pw.println(true); pw.println('a'); 3.关闭 pw.close();
转换流
桥转换流:InputStreamReader/OutputStreamWriter
-
可将字节流转换为字符流。
-
可设置字符的编码方式。
1.创建InputStreamReader对象 FileInputStream fis = new FileInputStream("D:\\write.txt"); InputStreamReader isr = new InputStreamReader(fis,"utf-8"); --带上编码方式 2.读取文件 int data = 0; while((data=isr.read()) != -1){ System.out.println((char)data); } 3.关闭 isr.close(); 1.创建OutputStreamWrite FileOutputStream fos = new FileOutputStream("D:\\info.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); 2.写入 for(int i =0; i<10; i++){ osw.write("好好学习,天天向上!"); osw.flush(); } 3.关闭 osw.close();
File类
File类的使用:
-
分隔符。
-
文件操作。
-
文件夹操作。
-- 分隔符 public static void separator(){ System.out.println("路径分隔符"+File.pathSeparator); --路径分隔符 ; System.out.println("名称分隔符"+File.separator); --名称分隔符 \ } ? -- 文件操作 public static void fileOpe(){ ? 1.创建文件 File file = new File("d:\\file.txt"); if(!file.exists){ boolean b = file.createNewFile(); System.out.println("创建结果" + b); } 2.删除文件 file.delete(); 3.获取文件信息 System.out.println("获取文件的绝对路径" + file.getAbsolutePath()); System.out.println("获取文件路径" + file.getPath()); System.out.println("获取文件的名称" + file.getName()); System.out.println("获取文件的父目录" + file.getParent()); System.out.println("获取文件的长度" + file.getLength()); System.out.println("获取文件的创建时间" + new Date(file.lastModified().toLocaleString()); 4.判断 System.out.println("文件是否可写" + file.canWrite()); System.out.println("是否是文件" + file.isFile()); System.out.println("是否隐藏" + file.isHidden()); } ? -- 文件夹的操作与文件的操作类似 有一点需要注意 dir.mkdir(); --只能创建单级目录 dir.mkdirs(); --可以创建多级目录
Properties
Map接口中还有一个实现类Hashtable,它和HashMap 十分相似,区别在于Hashtable是线程安全的。Hashtable存取元素时速度很慢,目前基本上被HashMap类所取代,但Hashtable类有一个子类Properties在实际应用中非常重要,Properties主要用来存储字符串类型的键和值,在实际开发中,经常使用Properties集合来存取应用的配置项。
-
Properties:属性集合。
-
特点:
-
存储属性名和属性值
-
属性名和属性值都是字符串类型
-
没有泛型
-
和流有关 可保存在流中或从流中加载
-
1.创建集合 Properties properties = new Properties(); 2.添加数据 properties.setProperties("username", "lihui"); properties.setProperties("age", "20"); 3.遍历 Setpronames = properties.stringPropertyNames(); for(String pro : pronames){ System.out.println(pro + "-----------" + propeoties.getProperties(pro)); } ? -- 和流有关的方法 -- list 方法 PrintWriter pw = new PrintWriter("D:\\print.txt"); properties.list(pw); pw.close(); ? -- store方法 保存 FileOutputStream fos = new FileOutputStream("D:\\store.properties"); properties.store(fos); fos.close(); ? -- load方法 加载 FileInputStream fis = new FileInputStream("D:\\store.properties"); properties.load(fis); fis.close();
总结:
-
内存与存储设备之间的传输数据的通道。
流的分类:
-
输入流,输出流;字节流,字符流;节点流,功能流。
序列化、反序列化:
-
将对象通过流写入到文件,或将对象通过流读取到内存,必须实现Serializable。
File对象: