IO流 [TOC]
IO流 1.File类的理解
File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
File类声明在java.io包下
File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,
并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。
后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的”终点”.
2.File的实例化 2.1 常用构造器 File(String filePath) File(String parentPath,String childPath) File(File parentFile,String childPath)
2.2 路径的分类 相对路径:相较于某个路径下,指明的路径。 绝对路径:包含盘符在内的文件或文件目录的路径
说明: IDEA中: 如果大家开发使用JUnit中的单元测试方法测试,相对路径即为当前Module下。 如果大家使用main()测试,相对路径即为当前的Project下。
Eclipse中: 不管使用单元测试方法还是使用main()测试,相对路径都是当前的Project下。
2.3 路径分隔符 windows和DOS系统默认使用“\”来表示 UNIX和URL使用“/”来表示
3.File类的常用方法
IO流概述 1.流的分类
1.操作数据单位:字节流、字符流
2.数据的流向:输入流、输出流
3.流的角色:节点流、处理流
图示:
2.流的体系结构
说明:红框对应的是IO流中的4个抽象基类。 蓝框的流需要大家重点关注。
3.重点说明的几个流结构
4.输入、输出的标准化过程 4.1 输入过程 ① 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在) ② 创建相应的输入流,将File类的对象作为参数,传入流的构造器中 ③ 具体的读入过程: 创建相应的byte[] 或 char[]。 ④ 关闭流资源 说明:程序中出现的异常需要使用try-catch-finally处理。
4.2 输出过程 ① 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在) ② 创建相应的输出流,将File类的对象作为参数,传入流的构造器中 ③ 具体的写出过程: write(char[]/byte[] buffer,0,len) ④ 关闭流资源 说明:程序中出现的异常需要使用try-catch-finally处理。
节点流(或文件流) 1.FileReader/FileWriter的使用: 1.1 FileReader的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 /* 将day09下的hello.txt文件内容读入程序中,并输出到控制台 说明点: 1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1 2. 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理 3. 读入的文件一定要存在,否则就会报FileNotFoundException。 */ @Test public void testFileReader1() { FileReader fr = null; try { //1.File类的实例化 File file = new File("hello.txt"); //2.FileReader流的实例化 fr = new FileReader(file); //3.读入的操作 //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1 char[] cbuf = new char[5]; int len; while((len = fr.read(cbuf)) != -1){ //方式一: //错误的写法 // for(int i = 0;i < cbuf.length;i++){ // System.out.print(cbuf[i]); // } //正确的写法 // for(int i = 0;i < len;i++){ // System.out.print(cbuf[i]); // } //方式二: //错误的写法,对应着方式一的错误的写法 // String str = new String(cbuf); // System.out.print(str); //正确的写法 String str = new String(cbuf,0,len); System.out.print(str); } } catch (IOException e) { e.printStackTrace(); } finally { if(fr != null){ //4.资源的关闭 try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1.2 FileWriter的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @Test public void testFileWriter () { FileWriter fw = null ; try { File file = new File("hello1.txt" ); fw = new FileWriter(file,false ); fw.write("I have a dream!\n" ); fw.write("you need to have a dream!" ); } catch (IOException e) { e.printStackTrace(); } finally { if (fw != null ){ try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }
1.3 文本文件的复制: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 @Test public void testFileReaderFileWriter () { FileReader fr = null ; FileWriter fw = null ; try { File srcFile = new File("hello.txt" ); File destFile = new File("hello2.txt" ); fr = new FileReader(srcFile); fw = new FileWriter(destFile); char [] cbuf = new char [5 ]; int len; while ((len = fr.read(cbuf)) != -1 ){ fw.write(cbuf,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fw != null ) fw.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fr != null ) fr.close(); } catch (IOException e) { e.printStackTrace(); } } }
对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 * 2. @Test public void testFileInputOutputStream () { FileInputStream fis = null ; FileOutputStream fos = null ; try { File srcFile = new File("爱情与友情.jpg" ); File destFile = new File("爱情与友情2.jpg" ); fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); byte [] buffer = new byte [5 ]; int len; while ((len = fis.read(buffer)) != -1 ){ fos.write(buffer,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null ){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
【注意】 相对路径在IDEA和Eclipse中使用的区别?
IDEA: 如果使用单元测试方法,相对路径基于当前的Module的。 如果使用main()测试,相对路径基于当前Project的。
Eclipse: 单元测试方法还是main(),相对路径都是基于当前Project的。
缓冲流的使用 1.缓冲流涉及到的类:
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
2.作用: 作用:提供流的读取、写入的速度 提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb
3.典型代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public void copyFileWithBuffered (String srcPath,String destPath) { BufferedInputStream bis = null ; BufferedOutputStream bos = null ; try { File srcFile = new File(srcPath); File destFile = new File(destPath); FileInputStream fis = new FileInputStream((srcFile)); FileOutputStream fos = new FileOutputStream(destFile); bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); byte [] buffer = new byte [1024 ]; int len; while ((len = bis.read(buffer)) != -1 ){ bos.write(buffer,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (bos != null ){ try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if (bis != null ){ try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3.2 使用BufferedReader和BufferedWriter:处理文本文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 @Test public void testBufferedReaderBufferedWriter () { BufferedReader br = null ; BufferedWriter bw = null ; try { br = new BufferedReader(new FileReader(new File("dbcp.txt" ))); bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt" ))); String data; while ((data = br.readLine()) != null ){ bw.write(data); bw.newLine(); } } catch (IOException e) { e.printStackTrace(); } finally { if (bw != null ){ try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } if (br != null ){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } }
转换流的使用 1.转换流涉及到的类:属于字符流
InputStreamReader:将一个字节的输入流转换为字符的输入流
解码:字节、字节数组 —>字符数组、字符串
OutputStreamWriter:将一个字符的输出流转换为字节的输出流
编码:字符数组、字符串 —> 字节、字节数组
说明:编码决定了解码的方式
2.作用:提供字节流与字符流之间的转换 3.图示:
4.典型实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Test public void test1 () throws IOException { FileInputStream fis = new FileInputStream("dbcp.txt" ); InputStreamReader isr = new InputStreamReader(fis,"UTF-8" ); char [] cbuf = new char [20 ]; int len; while ((len = isr.read(cbuf)) != -1 ){ String str = new String(cbuf,0 ,len); System.out.print(str); } isr.close(); } @Test public void test2 () throws Exception { File file1 = new File("dbcp.txt" ); File file2 = new File("dbcp_gbk.txt" ); FileInputStream fis = new FileInputStream(file1); FileOutputStream fos = new FileOutputStream(file2); InputStreamReader isr = new InputStreamReader(fis,"utf-8" ); OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk" ); char [] cbuf = new char [20 ]; int len; while ((len = isr.read(cbuf)) != -1 ){ osw.write(cbuf,0 ,len); } isr.close(); osw.close(); }
5.说明: //文件编码的方式(比如:GBK),决定了解析时使用的字符集(也只能是GBK)。
6.编码集 1.常见的编码表
ASCII:美国标准信息交换码。
ISO8859-1:拉丁码表。欧洲码表
GB2312:中国的中文编码表。最多两个字节编码所有字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
Unicode:国际标准码,融合了目前人类使用的所字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
2.对后面学习的启示
客户端/浏览器端 <—-> 后台(java,GO,Python,Node.js,php) <—-> 数据库
其它的流的使用 1.标准的输入输出流:
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
修改默认的输入和输出行为:
System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。
2.打印流:
3.数据流: DataInputStream 和 DataOutputStream 作用: 用于读取或写出基本数据类型的变量或字符串
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Test public void test3 () throws IOException { DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt" )); dos.writeUTF("刘建辰" ); dos.flush(); dos.writeInt(23 ); dos.flush(); dos.writeBoolean(true ); dos.flush(); dos.close(); } @Test public void test4 () throws IOException { DataInputStream dis = new DataInputStream(new FileInputStream("data.txt" )); String name = dis.readUTF(); int age = dis.readInt(); boolean isMale = dis.readBoolean(); System.out.println("name = " + name); System.out.println("age = " + age); System.out.println("isMale = " + isMale); dis.close(); }
对象流的使用 1.对象流: ObjectInputStream 和 ObjectOutputStream
2.作用: ObjectOutputStream:内存中的对象—>存储中的文件、通过网络传输出去:序列化过程 ObjectInputStream:存储中的文件、通过网络接收过来 —>内存中的对象:反序列化过程
3.对象的序列化机制: 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘 上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的 Java对象
4.序列化代码实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Test public void testObjectOutputStream () { ObjectOutputStream oos = null ; try { oos = new ObjectOutputStream(new FileOutputStream("object.dat" )); oos.writeObject(new String("我爱北京天安门" )); oos.flush(); oos.writeObject(new Person("王铭" ,23 )); oos.flush(); oos.writeObject(new Person("张学良" ,23 ,1001 ,new Account(5000 ))); oos.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if (oos != null ){ try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } }
5.反序列化代码实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Test public void testObjectInputStream () { ObjectInputStream ois = null ; try { ois = new ObjectInputStream(new FileInputStream("object.dat" )); Object obj = ois.readObject(); String str = (String) obj; Person p = (Person) ois.readObject(); Person p1 = (Person) ois.readObject(); System.out.println(str); System.out.println(p); System.out.println(p1); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if (ois != null ){ try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
6.实现序列化的对象所属的类需要满足: 1.需要实现接口:Serializable 2.当前类提供一个全局常量:serialVersionUID 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所属性也必须是可序列化的。(默认情况下,基本数据类型可序列化) RandomAccessFile的使用 1.随机存取文件流:RandomAccessFile 2.使用说明:
2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流 *
3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
如果写出到的文件存在,则会对原文件内容进行覆盖。(默认情况下,从头覆盖)
4.可以通过相关的操作,实现RandomAccessFile“插入”数据的效果。seek(int pos)
3.典型代码1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 @Test public void test1 () { RandomAccessFile raf1 = null ; RandomAccessFile raf2 = null ; try { raf1 = new RandomAccessFile(new File("爱情与友情.jpg" ),"r" ); raf2 = new RandomAccessFile(new File("爱情与友情1.jpg" ),"rw" ); byte [] buffer = new byte [1024 ]; int len; while ((len = raf1.read(buffer)) != -1 ){ raf2.write(buffer,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (raf1 != null ){ try { raf1.close(); } catch (IOException e) { e.printStackTrace(); } } if (raf2 != null ){ try { raf2.close(); } catch (IOException e) { e.printStackTrace(); } } } }
典型代码2: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Test public void test3 () throws IOException { RandomAccessFile raf1 = new RandomAccessFile("hello.txt" ,"rw" ); raf1.seek(3 ); StringBuilder builder = new StringBuilder((int ) new File("hello.txt" ).length()); byte [] buffer = new byte [20 ]; int len; while ((len = raf1.read(buffer)) != -1 ){ builder.append(new String(buffer,0 ,len)) ; } raf1.seek(3 ); raf1.write("xyz" .getBytes()); raf1.write(builder.toString().getBytes()); raf1.close(); }
Path、Paths、Files的使用 1.NIO的使用说明:
Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java IO AP。 NIO与原来的IO同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于 通道的IO操作。 NIO将以更加高效的方式进行文件的读写操作。 随着 JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为 NIO.2。
2.Path的使用 —jdk7提供 2.1Path的说明: Path替换原有的File类。
2.2如何实例化:
2.3常用方法:
3.Files工具类 —jdk7提供 3.1作用: 操作文件或文件目录的工具类
3.2常用方法: