3.缓冲流
* 为了提高数据读写的速度 , Java API 提供了带缓冲功能的流类,在使用这些流类 时,会创建一个内部缓冲区数组,缺省使用 8192 个字节 (8Kb) 的缓冲区 。
*缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为:
BufferedInputStream 和 BufferedOutputStream
BufferedReader 和 BufferedWriter
/* 实现非文本文件的复制 使用BufferedInputStream,BufferedOutputStream */ @Test public void BufferedStreamTest() { BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //1.造文件 File srcFile = new File("pucture.jpg"); File destFile = new File("pucture3.jpg"); //2.造流 //2.1造节点流 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //2.2造缓冲流 bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); //3.复制的细节:读取、写入 byte[] buffer = new byte[10]; int len; while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (bos != null) { try { bos.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (bis != null) { try { bis.close(); } catch (IOException e) { throw new RuntimeException(e); } } //4.资源关闭 //要求:先关闭外层的流,再关闭内层的流 //说明:关闭外层流的同时,内层流也会自动的进行关闭 // fos.close(); // fis.close(); } } //******************************************** /* 使用BufferedReader和BufferedWriter */ @Test public void testBufferedReaderBufferedWriter(){ BufferedReader br = null; BufferedWriter bw = null; try { //创建文件和对应的流 br = new BufferedReader(new FileReader(new File("hello.txt"))); bw = new BufferedWriter(new FileWriter(new File("hello3.txt"))); //读写操作 //方式一:使用char[]数组 // char[] cbuf = new char[1024]; // int len; // while ((len = br.read(cbuf)) != -1){ // bw.write(cbuf,0,len); // //bw.flush(); // } //方式二:使用String String data; while ((data = br.readLine()) != null){ //方法一: // bw.write(data + "\n");//data不包含换行符 //方法二: bw.write(data);;//data不包含换行符 bw.newLine(); } } catch (IOException e) { throw new RuntimeException(e); } finally { //关闭资源 if (bw != null){ try { bw.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (br != null){ try { br.close(); } catch (IOException e) { throw new RuntimeException(e); } } } }
4.转换流
/* 此时处理异常仍然应该使用try-catch-finally InputStreamReader的使用,实现字节的输入流到字符输入与流的转换 将字符集为utf-8的txt文件,改成字符集为gbk的txt文件 */ @Test public void test2() throws IOException { //1.造文件、造流 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"); //2.读写过程 char[] cbuf = new char[20]; int len; while ((len = isr.read(cbuf)) != -1){ osw.write(cbuf,0,len); } //3.关闭资源 isr.close(); osw.close(); }
补充:字符编码的说明
5.其他流的使用
1.标准的输入、输出流
2.打印流
3.数据流
①输入输出流
/* 1.标准的输入、输出流 1.1 System.in:标准的输入流,默认从键盘输入(字节流) System.out:标准的输出流,默认从控制台输出 1.2 System类的setIn(InputStream is) / setOut(printStream)方式指定输入和输出的流 1.3练习 从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续 进行输入操作,直至当输入“e”或者“exit”时,退出程序。 方法一:使用Scanner实现,调用next()返回一个字符串 方法二:使用System.in实现 -----> 转换流 -------> bufferedReader的readLine() */ public static void main(String[] args) { BufferedReader br = null; try { InputStreamReader isr = new InputStreamReader(System.in); br = new BufferedReader(isr); while (true){ System.out.println("请输入字符串:"); String data = br.readLine(); if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){ System.out.println("程序结束"); break; } String upperCase = data.toUpperCase(); System.out.println(upperCase); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (br != null){ try { br.close(); } catch (IOException e) { throw new RuntimeException(e); } } } }
②打印流
/* 2.打印流:PrintStream和PrintWriter 2.1提供了一系列重载的print()和println() 2.2练习: */ @Test public void test2(){ PrintStream ps = null; try { FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt")); // 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区) ps = new PrintStream(fos, true); if (ps != null) {// 把标准输出流(控制台输出)改成文件 System.setOut(ps); } for (int i = 0; i <= 255; i++) { // 输出ASCII字符 System.out.print((char) i); if (i % 50 == 0) { // 每50个数据一行 System.out.println(); // 换行 } } } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (ps != null) { ps.close(); } } }
③数据流
DataOutputStream dos = null; try { // 创建连接到指定文件的数据输出流对象 dos = new DataOutputStream(new FileOutputStream("destData.dat")); dos.writeUTF("我爱北京天安门"); // 写UTF字符串 dos.writeBoolean(false); // 写入布尔值 dos.writeLong(1234567890L); // 写入长整数 System.out.println("写文件成功!"); } catch (IOException e) { e.printStackTrace(); } finally { // 关闭流对象 try { if (dos != null) { // 关闭过滤流时,会自动关闭它包装的底层节点流 dos.close(); } } catch (IOException e) { e.printStackTrace(); } }
6.对象流
注意:
①序列化的过程:将内存中的java对象保存到磁盘中或通过网络传输出去
②一个类可序列化的前提
1.需要实现接口Serializable
2.需要当前类提供一个全局常量:serialVersionUID
3.除了当前的类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。 (默认情况下,基本数据和String类型是可序列化的)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt")); Person p = new Person("韩梅梅", 18, "中华大街", new Pet()); oos.writeObject(p); oos.flush(); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt")); Person p1 = (Person)ois.readObject(); System.out.println(p1.toString()); ois.close();
7.随机存取文件流
我们可以用 RandomAccessFile 这个类,来实现一个 多线程断点下载 的功能,
用过下载工具的朋友们都知道,下载前都会建立 两个临时文件 ,一个是与
被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次
暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上
一次的地方下载,从而实现断点下载或上传的功能,有兴趣的朋友们可以
自己实现下。
@Test public void test1(){ RandomAccessFile raf1 = null; RandomAccessFile raf2 = null; try { raf1 = new RandomAccessFile(new File("pucture.jpg"),"r"); raf2 = new RandomAccessFile(new File("pucture1.jpg"),"rw"); byte[] buffer = new byte[1024]; int len; while ((len = raf1.read(buffer)) != -1) { raf2.write(buffer,0,len); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (raf1 != null){ try { raf1.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (raf2 != null){ try { raf2.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } @Test public void test2() throws IOException { RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw"); raf1.seek(3);//将指针调到角标为3的位置 raf1.write("xyz".getBytes()); raf1.close(); } /* 使用RandomAccessFile实现数据插入效果 */ @Test public void test3() throws IOException { RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw"); raf1.seek(3);//将指针调到角标为3的位置 //保存指针3后面的所有数据到StringBuilder中 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);//调回指针写入xyz raf1.write("xyz".getBytes()); //将StringBuilder中的数据写入到文件中 raf1.write(builder.toString().getBytes()); raf1.close(); }
8.NIO.2中Path、Paths、Files类的使用