IO和NIO
一、文件的概念以及文件基本函数的操作
1. 什么是文件:文件可认为是相关记录或放在一起的数据的集合
2. File类是“文件和目录路径名的抽象表示”。 而不是指文件的内容。
3. File类定义了一些与平台无关的方法操作,如:创建、删除文件和重命名等。
4. Java中目录被看成是一个特殊的文件。List()方法可以返回目录中所有的子目录和文件。
5. 在unix下路径分隔符为(/),而在windos中则是为(\),在java中可以正确的处理不同系统中的分隔符。
示例代码:
1 package com.study.test; 2 3 import java.io.*; 4 import java.util.Date; 5 6 import static java.lang.System.*; 7 8 //什么是文件:文件可认为是相关记录或放在一起的数据的集合 9 //File类是“文件和目录路径名的抽象表示”。 而不是指文件的内容。 10 //File类定义了一些与平台无关的方法操作,如:创建、删除文件和重命名等。 11 //Java中目录被看成是一个特殊的文件。List()方法可以返回目录中所有的子目录和文件。 12 //在unix下路径分隔符为(/),而在windos中则是为(\),在java中可以正确的处理不同系统中的分隔符。 13 public class MyFile { 14 15 public static void main(String[] args) { 16 // //F:\\temp\\java\\luna\\io\\src\\aa.txt 17 File f1 = new File("D:\\study\\aa.txt");// 通过File类的构造函数传入一个文件名称 18 out.println(f1.getName()); 19 out.println(f1.getPath());// 获取相对路径 20 out.println(f1.getAbsolutePath());// 获取绝对路径 21 out.println(f1.getAbsoluteFile());// 目录也可以看作一个文件 22 out.println(f1.getParent());// 返回此文件对象的父目录 23 File f2 = new File("D:\\study\\bb.txt"); 24 out.println(f1.renameTo(f2));// 把文件aa.txt重新命名为bb.txt 25 out.println(f2.exists()); 26 out.println(f1.canRead()); 27 out.println(f1.canWrite()); 28 out.println(f1.isFile()); 29 out.println(f1.isDirectory()); 30 out.println(new Date(f2.lastModified()));// 文件最后的修改时间 31 out.println(f1.length());// 获取文件内容的长度 32 33 } 34 35 }
二、文件字节流FileInputStream与FileOutputStream的区别以及文件复制的实现
1. 文件输入流(FileInputStream)与文件输出流(FileOutputStream)的区别
1.1 FileInputStream:从已经存在的文件中获取里面已输入的内容,获取的是ASCII码字节
1.2 FileOutputStream:把内容写入到指定的文件中去,如果指定的文件不存在则自己创建一个,写入是以字节为单位的,每次只能写一个
2. 文件复制的实质就是从一个文件中读取内容到另一个文件中去,如果目标文件不存在则自动创建一个
示例代码:
1 package com.study.test; 2 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 7 //文件输入流(FileInputStream)与文件输出流(FileOutputStream)的区别 8 //FileInputStream:从已经存在的文件中获取里面已输入的内容,获取的是ASCII码字节 9 //FileOutputStream:把内容写入到指定的文件中去,如果指定的文件不存在则自己创建一个,写入是以字节为单位的,每次只能写一个 10 11 //文件复制的实质就是从一个文件中读取内容到另一个文件中去,如果目标文件不存在则自动创建一个 12 public class FileCopy { 13 public static void main(String[] args) throws IOException { 14 FileInputStream f1 = new FileInputStream("D:\\study\\bb.txt"); 15 FileOutputStream f2 = new FileOutputStream("D:\\study\\aa.txt"); 16 while (true) { 17 int i = f1.read(); 18 f2.write(i); 19 if (i == -1) 20 break; 21 22 } 23 f1.close(); 24 f2.close(); 25 26 } 27 28 }
3. 往文件里面写入字符串
示例代码:
1 package com.study.test; 2 3 import java.io.BufferedWriter; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.OutputStreamWriter; 7 8 public class ReadFileAndWirteFile { 9 10 public static void main(String[] args) throws IOException { 11 12 // 写内容(以字节写入)到指定文件中,如果文件不存在则自动创建 13 FileOutputStream f2 = new FileOutputStream("D:\\study\\dd.txt"); 14 // 把写入的字节转换成字符流 15 OutputStreamWriter osw = new OutputStreamWriter(f2); 16 // 以整行方式把字符流写入目标文件中 调用 17 BufferedWriter bw = new BufferedWriter(osw); 18 bw.write("您好!"); 19 bw.write("您好!"); 20 bw.write("您好!"); 21 bw.close();// 一定要关闭,否则不能写入 缓冲区游离 22 f2.close(); 23 24 } 25 26 }
三、文件字符流读取(FileReader)与写入(FileWriter)的区别
1 package com.study.test; 2 3 import java.io.*; 4 5 //文件字符流读取FileReader与写入FileWriter的区别 6 import static java.lang.System.*; 7 8 public class ReadFileAndWirteFile { 9 10 public static void main(String[] args) throws IOException { 11 // 文件字符流读取:FileReader 12 FileReader fr = new FileReader("D:\\study\\bb.txt");// 读取指定文件的内容并将其转换为字符流 13 BufferedReader br = new BufferedReader(fr);// 将字符流包装到缓冲区 14 String s; 15 while ((s = br.readLine()) != null) { 16 out.println(s); 17 } 18 19 // 文件字符流写入:FileWriter 20 // 把字符文件写入指定文件中,如果文件不存在则自动创建, FileWriter已经将字节转换为字符不用再用OutputStreamWriter来转换 21 FileWriter fw = new FileWriter("D:\\study\\ee.txt"); 22 BufferedWriter bw = new BufferedWriter(fw); 23 bw.write("我们"); 24 bw.close();// 一定要关闭 否则不能写入 25 26 } 27 28 }
四、找到指定目录下指定文件格式的文件
1 package com.study.test; 2 3 import static java.lang.System.out; 4 5 import java.io.File; 6 import java.io.FilenameFilter; 7 import java.io.IOException; 8 9 class AA implements FilenameFilter { 10 private String i; 11 12 AA(String i) { 13 this.i = i; 14 } 15 16 @Override 17 public boolean accept(File dir, String name) { 18 return name.endsWith(this.i); 19 } 20 21 } 22 23 public class ReadFileAndWirteFile { 24 public static void main(String[] args) throws IOException { 25 File f = new File("D:\\study"); 26 // 只想搜索.txt文件 27 for (File temp : f.listFiles(new AA("txt"))) 28 out.println(temp.getName()); 29 30 } 31 }
输出结果:
aa.txt
bb.txt
dd.txt
ee.txt
五、什么是NIO
NIO提供了一个全新的底层I/O模型,与最初的java.io包中面向流的概念不同,NIO中采用了面向块的概念。
I/O操作以大的数据块为单位进行,而不是一次一个字节或字符进行。
采用这样的操作方式java的I/O性能有很大提高,但也牺牲了java操作的简单性。
NIO中所有的操作都要使用到缓冲区(内存)处理,且所有的读写操作都是通过缓冲区(内存)完成的。
NIO提供与平台无关的非阻塞I/O。与面向线程的、阻塞式I/O方式比较,多道通信、非阻塞I/O技术可以使应用程序更有效地处理大量连接的情况。
Java新IO中使用Buffer和Channel支持以上的操作。
六、NIO之Buffer类以及其方法的使用
1. Buffer类与StringBuffer非常类似,都可以自动扩容,只不过Buffer的效率更高,因为Buffer类是把内容放入内存中(缓冲区)以数据块的方式读写的,而StringBuffer是以流的方式读写的
示例代码:
1 package com.study.test; 2 3 import static java.lang.System.*; 4 5 import java.nio.CharBuffer; 6 7 public class NIOBuffer { 8 9 public static void main(String[] args) { 10 // Buffer类与StringBuffer非常类似,都可以自动扩容,只不过Buffer的效率更高, 11 // 因为Buffer类是把内容放入内存中(缓冲区)以数据块的方式读写的,而StringBuffer是以流的方式读写的 12 13 // 创建缓冲 14 // CharBuffer存储字符 用allocate 用allocate(int capacity)分配缓冲区空间 15 CharBuffer buffer = CharBuffer.allocate(4); 16 buffer.put('a');// 位置0插入a 17 buffer.put('b');// 位置1插入b 18 out.println(buffer.position());// 当前位置为2 缓冲区的指针指向即将操作的下一个位置 19 out.println(buffer.limit());// limit=4 //把缓冲区的容量限制为当前容量 不能再自动扩容 只能存储4个字符 20 // out.println(buffer.capacity());//capacity=4//缓冲区的当前容量 21 // buffer.put('c'); 22 // buffer.put('d'); 23 // buffer.put('e');//异常 bufferoverflowexception 因为缓冲区容量已被limit方法限制为4 24 // 所以此时不能插入多余数据到缓冲区 25 26 out.println(buffer);// 从当前位置输出什么都没有 27 out.println("-------------------改变指针-------------------------"); 28 // 改变指针 29 buffer.position(0); 30 out.println(buffer.limit());// limit=4 31 out.println(buffer.capacity());// capacity=4; 32 out.println(buffer);// 输出内容 ab 33 // 重置缓冲区 34 out.println("-------------------重置缓冲区-------------------------"); 35 buffer.flip(); 36 out.println(buffer.position()); 37 out.println(buffer.limit());// limit=2 38 out.println(buffer.capacity());// capacity=4; 39 out.println(buffer);// 输出内容,仅仅输出到limit,不会输出多余字符 40 41 out.println(buffer.position(4));// 定位到b之后继续输入 42 buffer.put('c');// 缓冲区已经重置到0位置 所以不能插入 必须 重置到位置2才能插入 43 // //子缓冲区 44 // CharBuffer childBuffer=buffer.slice();//截取0到达limit的位置 45 // out.println(childBuffer);// 46 // out.println(childBuffer.limit()); 47 // out.println(childBuffer.capacity()); 48 // //只读缓冲区 49 // CharBuffer bufferRO=buffer.asReadOnlyBuffer(); 50 // bufferRO.put('x');//出错 51 52 } 53 54 }
七、NIO之内存映射与传统IO流的区别
1. 内存映射可以把文件映射到内存中,这样文件内的数据就可以用内存读写指令来访问,而不是用InputStream或OutputStream这样的I/O操作类,采用此方式读取文件的速度是最快的。使用FileChannel类提供的map()方法。
2. Map()方法在使用时要指定映射模式,在内存映射中提供三种模式:读取和写入:READ_WRITE,只读READ_ONLY,专用(写入时复制)映射模式
示例代码:
1 package com.study.test; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.RandomAccessFile; 6 import java.nio.MappedByteBuffer; 7 import java.nio.channels.FileChannel; 8 9 //内存映射可以把文件映射到内存中,这样文件内的数据就可以用内存读写指令来访问,而不是用InputStream或OutputStream这样的I/o操作类, 10 //采用此方式读取文件的速度是最快的。使用FileChannel类提供的map()方法。 11 //Map()方法在使用时要指定映射模式,在内存映射中提供三种模式:读取和写入:READ_WRITE,只读READ_ONLY,专用(写入时复制)映射模式 12 public class NIOBuffer { 13 14 public static void main(String[] args) throws IOException { 15 // 下面再次读取文件,原来的流其实是一个管子 16 RandomAccessFile fis = new RandomAccessFile("D:\\study\\cc.txt", "rw");// 获取一个文件 17 // 不直接通过流了,出现了一个管道 18 FileChannel fc = fis.getChannel();// 通过通道把文件映射到内存中去 19 // 怎么用通道读取内容? 通过FileChannel的map()方法读写文件 20 MappedByteBuffer mb = fc.map(FileChannel.MapMode.READ_WRITE, 4, 21 new File("D:\\study\\cc.txt").length()); 22 mb.put(1, (byte) '2'); 23 mb.put(2, (byte) '3'); 24 25 } 26 27 }