IO流

装饰流(缓冲处理流)

概述

1、Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。

2、当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。

3、因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。

特性

1、提高了性能

2、底层还是节点流

3、自动释放底层节点流资源

分类

1、处理字节

2、处理字符

3、打印流

4、数据流和对象流

处理字节

BufferedInputStream:字节缓冲输入流
BufferedOutputStream:字节缓冲输出流

构造方法

  1. //字节缓冲输入流
  2. BufferedInputStream(InputStream in)
  3. BufferedInputStream(InputStream in, int size)
  4. //字节缓冲输出流
  5. BufferedOutputStream(OutputStream out)
  6. BufferedOutputStream(OutputStream out, int size)

文件拷贝代码示例

  1. /**
  2. *文件拷贝
  3. * 文件的拷贝:字节缓冲输入流+字节缓冲输出流
  4. * BufferedInputStream:字节缓冲输入流
  5. * BufferedOutputStream:字节缓冲输出流、
  6. */
  7. public class Copy_BufferedIntputOutputStream {
  8. public static void main(String[] args) {
  9. long t1=System.currentTimeMillis();
  10. copyFile("G:\\学习相关\\javaweb学习\\jsp视频\\12_EL 表达式 (隐式对象)__rec.avi","C:\\Users\\tfp12\\Desktop\\sp.avi");
  11. long t2=System.currentTimeMillis();
  12. System.out.println(t2-t1);
  13. }
  14. public static void copyFile(String srcPath,String destPath){
  15. File src=new File(srcPath);
  16. File dest=new File(destPath);
  17. // InputStream is=null;
  18. // OutputStream os=null
  19. try(InputStream is=new BufferedInputStream(new FileInputStream(src));
  20. OutputStream os=new BufferedOutputStream(new FileOutputStream(dest))) {
  21. int len=-1;
  22. byte[]flush=new byte[1024];
  23. while ((len=is.read(flush))!=-1){
  24. os.write(flush,0,len);
  25. os.flush();
  26. }
  27. } catch (FileNotFoundException e) {
  28. e.printStackTrace();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }

处理字符

BufferedReader:字符输入缓冲流

BufferedWriter:字符输出缓冲流

构造方法(不发生多态)

  1. BufferedReader(Reader in)
  2. BufferedReader(Reader in, int sz)

新增方法

  1. readLine():读取一行
  2. newLine():换行

示例

  1. /**
  2. * 纯文本的拷贝:字符输入缓冲流+字符输出缓冲流
  3. * BufferedReader:字符输入缓冲流
  4. * BufferedWriter:字符输出缓冲流
  5. * 操作单位:字符
  6. * 注:只适用于纯文本,是FileReader和FileWriter的装饰流类。
  7. * 提高性能
  8. *1、readLine():读取一行
  9. * 2、newLine():换行
  10. */
  11. public class Copy_BufferedReaderWriterStream {
  12. public static void main(String[] args) {
  13. //创建源和目的地
  14. File src=new File("test.txt");
  15. File dest=new File("paji1号.txt");
  16. //BufferedWriter bw=null;
  17. //选择流,不发生多态
  18. try(BufferedWriter bw=new BufferedWriter(new FileWriter(dest));
  19. BufferedReader br=new BufferedReader(new FileReader(src))) {
  20. String line=null;
  21. //操作(逐行读取)
  22. while ((line=br.readLine())!=null){
  23. bw.append(line); //逐行写出
  24. bw.newLine(); //换行
  25. }
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }

**InputStreamReader:输入转换流

OutputStreamWrite:输出转换流**

概述

当字节流中都是字符时,转换为字符流效率更高

InputStreamReader:将字节流转换为指定编码的字符流输入

OutputStreamWrite:将字符流转换为指定编码的字节流输出

示例一:控制台输入输出

  1. **
  2. *转换流:InputStreamReader OutputStreamWrite
  3. * 字节流中都是字符时,转换为字符流效率更高
  4. * InputStreamReader:将字节流转换为指定编码的字符流输入
  5. * OutputStreamWrite:将字符流转换为指定编码的字节流输出
  6. * 1、以字符流的形式操作字节流(纯文本的)
  7. * 2、指定字符集
  8. */
  9. public class InputStreamReader_test {
  10. public static void main(String[] args) {
  11. test02();
  12. }
  13. public static void test01() {
  14. //System.in为一个字节输入流
  15. //System.out为一个字节输出流
  16. try(BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
  17. BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(System.out))) {
  18. //循环获取键盘的输入
  19. String msg="";
  20. while (!msg.equals("exit")){
  21. msg=reader.readLine(); //循环读取
  22. writer.write(msg); //循环写出
  23. writer.newLine(); //换行
  24. writer.flush(); //强制刷新
  25. }
  26. } catch (IOException e) {
  27. System.out.println("操作异常");
  28. }
  29. }

示例二:下载网络资源163页面到本地

  1. public static void test02(){
  2. //解码
  3. //url.openStream()返回一个字节输入流InputStream
  4. try(BufferedReader reader=
  5. new BufferedReader(
  6. new InputStreamReader(
  7. //下载网络资源
  8. new URL("http://www.163.com").openStream(),"GBK"));
  9. //编码
  10. BufferedWriter writer=
  11. new BufferedWriter(
  12. new OutputStreamWriter(
  13. new FileOutputStream("C:/Users/tfp12/Desktop/163.html"),"GBK"))){
  14. //3、操作(读取)
  15. String msg;
  16. while ((msg=reader.readLine())!=null){
  17. writer.write(msg);
  18. writer.newLine();
  19. }
  20. writer.flush();
  21. } catch (MalformedURLException e) {
  22. e.printStackTrace();
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }

**PrintStream:打印输入转换流

PrintWriter:打印输出流**

  1. /**
  2. * @auther TongFangPing
  3. * @date 2019/9/28 23:22.
  4. * PrintStream :输出流
  5. */
  6. public class PrintStream_study {
  7. public static void main(String[] args) throws FileNotFoundException {
  8. //输出到控制台
  9. java.io.PrintStream ps=System.out;
  10. ps.println("扒鸡");
  11. ps.println("真好吃!");
  12. //true:为自动刷新
  13. ps=new java.io.PrintStream(new BufferedOutputStream(new FileOutputStream("paji2.txt")),true);
  14. ps.println("德州扒鸡");
  15. ps.println("真扒!");
  16. ps.close();
  17. }
  18. }
  1. /**
  2. * PrintWriter :输出流
  3. * 用法和printStream差不多
  4. */
  5. public class PrintWrite_study {
  6. public static void main(String[] args) throws FileNotFoundException {
  7. PrintWriter pw=new java.io.PrintWriter(new BufferedOutputStream(new FileOutputStream("paji2.txt")),true);
  8. pw.println("德州扒鸡");
  9. pw.println("真扒呀!");
  10. pw.close();
  11. }
  12. }

**DataStream:数据流

ObjectStream:对象流**

数据流DataStream:读取数据流保持其中的数据类型

1、写出后读取

2、读取顺序与写出顺序保持一致

**DataOutputStream

DataInputStream**

  1. /**
  2. * 数据流:读取数据流保持其中的数据类型
  3. * 1、先写出后读取
  4. * 2、读取顺序与写出顺序保持一致
  5. * DataOutputStream
  6. * DataInputStream
  7. */
  8. public class DataStream {
  9. public static void main(String[] args) throws IOException {
  10. //写出
  11. ByteArrayOutputStream baos=new ByteArrayOutputStream();
  12. DataOutputStream dos=new DataOutputStream(baos);
  13. //操作数据
  14. dos.writeUTF("我爱吃扒鸡");
  15. dos.writeInt(18);
  16. dos.writeBoolean(true);
  17. dos.writeChar('a');
  18. dos.flush();
  19. byte[]datas=baos.toByteArray();
  20. //读取
  21. DataInputStream dis=new DataInputStream(new ByteArrayInputStream(datas));
  22. //读取顺序保持一致
  23. String msg=dis.readUTF();
  24. int n=dis.readInt();
  25. boolean flag=dis.readBoolean();
  26. char ch=dis.readChar();
  27. System.out.println(ch);
  28. }
  29. }

对象流:ObjectStream

ObjectInputStream

ObjectOutputStream

用于存储和读取基本数据类型数据或对象的处理流。它的强大之处在于可以把java中的对象写入到数据源当中,也能把对象从数据源中还原回来。

序列化:用ObjectOutputStream类保存基本数据类型或对象的机制。

反序列化:用ObjectInputStream类读取基本数据类型或对象的机制。

对象的序列化

  • 对象的序列化机制允许把内存中的java对象转换成与平台无关的二进制流,从而允许把这种二进制流持久保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。(序列化过程)当其他程序获取到这种二进制流,就可以恢复成为原来的java对象。(反序列化过程)

  • 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。
    -序列化是RMI(Remote Method Invoke:远程方法调用)过程的参数和返回值都必须实现的机制,而RMIJavaEE的基础。因此序列化机制是JavaEE平台的基础。

  • 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现以下两个接口之一。否则,则会抛出NotSerializableException异常

    • Serializable
    • Externalizable

1、写出后读取

2、读取顺序与写出顺序保持一致

3、不是所有的对象都可以序列化,必须实现接口java.io.Serializable

  1. /**
  2. * 序列化(写出)+反序列化(读入)
  3. * 对象流:在数据流的基础上添加了Object对象
  4. * 1、先写出后读取
  5. * 2、读取顺序与写出顺序保持一致
  6. * 3、不是所有的对象都可以序列化,必须实现接口java.io.Serializable
  7. * ObjectOutputStream
  8. * ObjectInputStream
  9. */
  10. public class ObjectStream {
  11. public static void main(String[] args) throws IOException, ClassNotFoundException {
  12. //写出-->序列化(将内存中的对象保存到磁盘中)
  13. ObjectOutputStream oos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("paji.txt")));
  14. //操作数据类型+数据
  15. oos.writeUTF("我爱吃扒鸡");
  16. oos.writeInt(18);
  17. oos.writeBoolean(true);
  18. oos.writeChar('a');
  19. //对象
  20. oos.writeObject("猴赛雷");
  21. oos.writeObject(new Date());
  22. Employee ep=new Employee("扒鸡",22);
  23. oos.writeObject(ep);
  24. oos.flush();
  25. oos.close();
  26. //读取--->反序列化(从磁盘中读取数据进行还原成对象)
  27. ObjectInputStream ois=new ObjectInputStream(new BufferedInputStream(new FileInputStream("paji.txt")));
  28. //读取顺序保持一致
  29. String msg=ois.readUTF();
  30. int n=ois.readInt();
  31. boolean flag=ois.readBoolean();
  32. char ch=ois.readChar();
  33. //对象的数据还原
  34. Object str=ois.readObject();
  35. Object date=ois.readObject();
  36. Object employee=ois.readObject();
  37. if(str instanceof String){
  38. String strObj=(String)str;
  39. System.out.println(strObj);
  40. }
  41. if(date instanceof Date){
  42. Date dateObj=(Date)date;
  43. System.out.println(date);
  44. }
  45. if(employee instanceof Employee){
  46. Employee employeeObj=(Employee)employee;
  47. System.out.println(employeeObj);
  48. }
  49. ois.close();
  50. }
  51. static class Employee implements java.io.Serializable{
  52. private String name;
  53. private int age;
  54. public Employee(String name, int age) {
  55. this.name = name;
  56. this.age = age;
  57. }
  58. public void setAge(int age) {
  59. this.age = age;
  60. }
  61. public void setName(String name) {
  62. this.name = name;
  63. }
  64. public int getAge() {
  65. return age;
  66. }
  67. public String getName() {
  68. return name;
  69. }
  70. }
  71. }

文件的切割读写(一)

  1. /**
  2. * 文件切割读写
  3. * 随机读取和写入流:RandomAccessFile
  4. */
  5. public class RandomAccessFile_study {
  6. public static void main(String[] args) throws IOException {
  7. //文件可以分为多少块
  8. File src=new File("randomAccess_study.iml");
  9. //文件的总长度
  10. long len=src.length();
  11. //设置每块大小
  12. int blockSize=100;
  13. //块数:不够一块,按一块处理
  14. int blockNumber=(int)Math.ceil(len*1.0/blockSize);
  15. System.out.println("文件总长度:"+len+"字节,可以分为:"+blockNumber+"块");
  16. int beginPos=0;
  17. //如果一块的大小不够实际需要的大小,则去一块的大小,否则取实际大小
  18. int actualSize=(int)(blockSize>len?len:blockSize);
  19. //分块读取
  20. for(int i=0;i<blockNumber;i++){
  21. beginPos=i*blockSize;
  22. if(i==blockNumber-1){ //最后一块
  23. actualSize=(int)len;
  24. }else{
  25. actualSize=blockSize;
  26. len-=actualSize; //剩余量
  27. }
  28. System.out.println(i+"-->"+beginPos+"-->"+actualSize);
  29. split(i,beginPos,actualSize);
  30. }
  31. }
  32. //分开思想,起始、实际大小
  33. /**
  34. * 分段读取
  35. * 指定第i块的起始位置和实际长度
  36. * @param i
  37. * @param beginPos
  38. * @param actualSize
  39. * @throws IOException
  40. */
  41. public static void split(int i,int beginPos,int actualSize) throws IOException {
  42. RandomAccessFile raf=new RandomAccessFile(new File("randomAccess_study.iml"),"r");
  43. //随机读写
  44. raf.seek(beginPos);
  45. byte[]flush=new byte[1024];
  46. int len=-1;
  47. while ((len=raf.read(flush))!=-1){
  48. if(actualSize>len){ //获取本次读取的所有内容
  49. System.out.println(new String(flush,0,len));
  50. actualSize-=len;
  51. }else{
  52. System.out.println(new String(flush,0,actualSize));
  53. break;
  54. }
  55. }
  56. }
  57. public static void Test01() throws IOException {
  58. //随机读写流,第一个参数:文件路径 第二个参数,模式:r、rw、rws、rwd
  59. RandomAccessFile raf=new RandomAccessFile(new File("randomAccess_study.iml"),"r");
  60. //设置操作(读写)文件的指针位置
  61. raf.seek(2);
  62. //读取
  63. byte[]flush=new byte[1024];
  64. int len=-1;
  65. while ((len=raf.read(flush))!=-1){
  66. System.out.println(new String(flush,0,len));
  67. }
  68. }
  69. }

文件的切割读写(二)

  1. * 文件切割读写
  2. * 随机读取和写入流:RandomAccessFile
  3. */
  4. public class RandomAccessFile_study02 {
  5. public static void main(String[] args) throws IOException {
  6. //文件可以分为多少块
  7. File src=new File("io.png");
  8. //文件的总长度
  9. long len=src.length();
  10. //设置每块大小
  11. int blockSize=1024;
  12. //块数:不够一块,按一块处理
  13. int blockNumber=(int)Math.ceil(len*1.0/blockSize);
  14. System.out.println("文件总长度:"+len+"字节,可以分为:"+blockNumber+"块");
  15. int beginPos=0;
  16. //如果一块的大小不够实际需要的大小,则去一块的大小,否则取实际大小
  17. int actualSize=(int)(blockSize>len?len:blockSize);
  18. //分块读取
  19. for(int i=0;i<blockNumber;i++){
  20. beginPos=i*blockSize;
  21. if(i==blockNumber-1){ //最后一块
  22. actualSize=(int)len;
  23. }else{
  24. actualSize=blockSize;
  25. len-=actualSize; //剩余量
  26. }
  27. System.out.println(i+"-->"+beginPos+"-->"+actualSize);
  28. split(i,beginPos,actualSize);
  29. }
  30. }
  31. //分开思想,起始、实际大小
  32. /**
  33. * 分段读取
  34. * 指定第i块的起始位置和实际长度
  35. * @param i
  36. * @param beginPos
  37. * @param actualSize
  38. * @throws IOException
  39. */
  40. public static void split(int i,int beginPos,int actualSize) throws IOException {
  41. RandomAccessFile raf=new RandomAccessFile(new File("io.png"),"r");
  42. RandomAccessFile raf2=new RandomAccessFile(new File("dest/"+i+"io.png"),"rw");
  43. //随机读写
  44. raf.seek(beginPos);
  45. byte[]flush=new byte[1024];
  46. int len=-1;
  47. while ((len=raf.read(flush))!=-1){
  48. if(actualSize>len){ //获取本次读取的所有内容
  49. raf2.write(flush,0,len);
  50. actualSize-=len;
  51. }else{
  52. raf2.write(flush,0,actualSize);
  53. break;
  54. }
  55. }
  56. }
  57. public static void Test01() throws IOException {
  58. //随机读写流,第一个参数:文件路径 第二个参数,模式:r、rw、rws、rwd
  59. RandomAccessFile raf=new RandomAccessFile(new File("randomAccess_study.iml"),"r");
  60. //设置操作(读写)文件的指针位置
  61. raf.seek(2);
  62. //读取
  63. byte[]flush=new byte[1024];
  64. int len=-1;
  65. while ((len=raf.read(flush))!=-1){
  66. System.out.println(new String(flush,0,len));
  67. }
  68. }
  69. }

文件的切割与合并Demo

  1. /**
  2. * 面向对象封装文件分割与合并
  3. * 文件切割读写
  4. *
  5. */
  6. public class SplitFile {
  7. //源头
  8. private File src;
  9. //目的地(文件夹)
  10. private String desDir;
  11. //所有分割后的文件存储路径
  12. private List<String> desPaths;
  13. //每块大小
  14. private int blockSize;
  15. //块数
  16. private int size;
  17. /**
  18. *构造方法
  19. * @param srcPath:文件源
  20. * @param desDir:目的地路径
  21. * @param blockSize:每个文件大小
  22. */
  23. public SplitFile(String srcPath, String desDir, int blockSize) {
  24. this.src = new File(srcPath);
  25. this.desDir = desDir;
  26. this.blockSize = blockSize;
  27. this.desPaths=new ArrayList<String>();
  28. //初始化
  29. init();
  30. }
  31. //初始化
  32. private void init(){
  33. //文件的总长度
  34. long len=this.src.length();
  35. //块数:不够一块,按一块处理
  36. this.size=(int)Math.ceil(len*1.0/blockSize);
  37. //路径
  38. for(int i=0;i<size;i++){
  39. this.desPaths.add(this.desDir+"/"+i+"-"+this.src.getName());
  40. }
  41. }
  42. /**
  43. * 分割
  44. * 1、计算每一块的起始大小
  45. * 2、分割
  46. */
  47. public void split() throws IOException {
  48. //文件的总长度
  49. long len=src.length();
  50. int beginPos=0;
  51. //如果一块的大小不够实际需要的大小,则去一块的大小,否则取实际大小
  52. int actualSize=(int)(blockSize>len?len:blockSize);
  53. //分块读取
  54. for(int i=0;i<size;i++) {
  55. beginPos = i * blockSize;
  56. if (i == size - 1) { //最后一块
  57. actualSize = (int) len;
  58. } else {
  59. actualSize = blockSize;
  60. len -= actualSize; //剩余量
  61. }
  62. splitDetail(i,beginPos,actualSize);
  63. }
  64. }
  65. //分开思想,起始、实际大小
  66. /**
  67. * 分段读取
  68. * 指定第i块的起始位置和实际长度
  69. * @param i
  70. * @param beginPos
  71. * @param actualSize
  72. * @throws IOException
  73. */
  74. public void splitDetail(int i,int beginPos,int actualSize) throws IOException {
  75. RandomAccessFile raf=new RandomAccessFile(this.src,"r");
  76. RandomAccessFile raf2=new RandomAccessFile(this.desPaths.get(i),"rw");
  77. //随机读写
  78. raf.seek(beginPos);
  79. byte[]flush=new byte[1024];
  80. int len=-1;
  81. while ((len=raf.read(flush))!=-1){
  82. if(actualSize>len){ //获取本次读取的所有内容
  83. raf2.write(flush,0,len);
  84. actualSize-=len;
  85. }else{
  86. raf2.write(flush,0,actualSize);
  87. break;
  88. }
  89. }
  90. raf2.close();
  91. raf.close();
  92. }
  93. public void merge(String destPath) throws IOException {
  94. //输出流(文件追加的方式)
  95. OutputStream os=new BufferedOutputStream(new FileOutputStream(destPath,true));
  96. //输入流
  97. for(int i=0;i<desPaths.size();i++){
  98. InputStream is=new BufferedInputStream(new FileInputStream(desPaths.get(i)));
  99. //拷贝
  100. byte[]flush=new byte[1024];
  101. int len=-1;
  102. while ((len=is.read(flush))!=-1){
  103. os.write(flush,0,len);
  104. }
  105. os.flush();
  106. is.close();
  107. }
  108. os.close();
  109. }
  110. public static void main(String[] args) throws IOException {
  111. SplitFile sf=new SplitFile("E:/idea/randomAccess_study/src/randomaccess_study/SplitFile.java","dest",1024);
  112. sf.split();
  113. sf.merge("合并Test.java");
  114. }
  115. }