流的分类
按操作数据的单位不同,可以分为:字节流(8bit)、字符流(16bit)
按数据流的流向不同,可以分为:输入流、输出流
按流的角色不同,分为:节点流、处理流
抽象基类
字节流
字符流
输入流
InputStream
Reader
输出流
OutputStream
Writer
Java的IO流设计40多个类,实际上都非常规则。都是从上面的4个基本派生的
由这四个类派生出来的子类都是以其父类的名称作为子类的后缀
IO流体系
流的体系结构
抽象基类
节点流(文件流)
缓冲流(处理流的一种)
InputStream
FileInputStream
BufferedInputStream
OutputStream
FileOutputStream
BufferedOutputStream
Reader
FileReader
BufferedReader
Writer
FileWriter
BufferedWriter
FileReader 类读取文件
read() 方法的理解:返回读取到的一个字符,返回-1时表示读取完毕
文件流必须手动调用 close 方法关闭,使用 try-catch-fianlly 包裹 FileReader 类的调用方法
读取的文件必须存在,否则会报错
提示:idea中选中一段代码,然后 CTRL+ALT+T 快速添加 try-catch 方法
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 package com.songzx.exer;import org.junit.Test;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;public class Exer1 { @Test public void test1 () { File file = new File("src\\hello.txt" ); FileReader fr = null ; try { fr = new FileReader(file); int data; while ((data = fr.read()) != -1 ){ char s = (char ) data; System.out.print(s); } } catch (IOException e) { e.printStackTrace(); } finally { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
read(char[] cbuf) 一次读取多位字符 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 package com.songzx.exer;import org.junit.Test;import java.io.File;import java.io.FileReader;import java.io.IOException;public class Exer2 { @Test public void test1 () { File file = new File("src\\hello.txt" ); FileReader fr = null ; try { fr = new FileReader(file); char [] cbuf = new char [5 ]; int len; while ((len = fr.read(cbuf)) != -1 ){ for (int i = 0 ; i < len; i++) { System.out.print(cbuf[i]); } } } catch (IOException e) { e.printStackTrace(); } finally { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
FileWrite 写入字符到文件中
写入文件时如果文件不存在会自动创建
new FileWrite(File file,appent true)
实例化 FileWrite
类时第二个参数用来控制写入的文件是覆盖文件或者在原有文件基础上追加字符
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 package com.songzx.exer;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class FileWriteTest { public static void main (String[] args) { File file = new File("hello1.txt" ); FileWriter fr = null ; try { fr = new FileWriter(file,true ); fr.write("hello world\n" ); fr.write("你好中国" ); } catch (IOException e) { e.printStackTrace(); } finally { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
复制一个文件内容到另外一个文件 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 package com.songzx.exer;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class CopyFileTest { public static void main (String[] args) { FileReader readerFr = null ; FileWriter writeFr = null ; try { File file = new File("hello1.txt" ); readerFr = new FileReader(file); File file1 = new File("copyHello1.txt" ); writeFr = new FileWriter(file1); int data; while ((data = readerFr.read()) != -1 ){ writeFr.write(data); } } catch (IOException e) { e.printStackTrace(); } finally { try { readerFr.close(); writeFr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
复制一个图片 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 package com.songzx.exer;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class CopyPng { public static void main (String[] args) { FileInputStream fr = null ; FileOutputStream fw = null ; try { File file = new File("向日葵.png" ); File file1 = new File("向日葵1.png" ); fr = new FileInputStream(file); fw = new FileOutputStream(file1); int len; byte [] bytes = new byte [5 ]; while ((len = fr.read(bytes)) != -1 ){ fw.write(bytes,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }
复制文件方法 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 package com.songzx.exer;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class CopyAvi { public static void main (String[] args) { String strpath = "D:\\开发工具包\\IllustratorCS6.zip" ; String descpath = "D:\\开发工具包\\IllustratorCS6-copy.zip" ; long start = System.currentTimeMillis(); CopyAvi.copyFileTest(strpath,descpath); long end = System.currentTimeMillis(); System.out.println("复制耗时:" + (end - start)); } static void copyFileTest (String strPaht,String descPath) { FileInputStream fis = null ; FileOutputStream fos = null ; try { File file = new File(strPaht); File file1 = new File(descPath); fis = new FileInputStream(file); fos = new FileOutputStream(file1); int len; byte [] bytes = new byte [1024 ]; while ((len = fis.read(bytes)) != -1 ){ fos.write(bytes,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } }
使用缓冲流复制字节文件
实例化缓冲流对象时需要传入节点流
关闭流时要先关闭外面的缓冲流,再关闭里面的节点流
关闭缓冲流的同时会关闭里面的节点流
使用缓冲流读写文件的速度会得到提高,这是应为在其内部存在一个缓冲区
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 package com.songzx.exer;import java.io.*;public class BufferCopyByte { public static void main (String[] args) { String path1 = "D:\\工具\\navicat15破解版.zip" ; String path2 = "D:\\工具\\navicat15破解版-copy2.zip" ; try { long start = System.currentTimeMillis(); BufferCopyByte.BufferCopyFile(path1,path2); long end = System.currentTimeMillis(); System.out.println(end - start); } catch (IOException e) { e.printStackTrace(); } } static void BufferCopyFile (String strpath,String descpath) throws IOException { File file = new File(strpath); File file1 = new File(descpath); FileInputStream fir = new FileInputStream(file); FileOutputStream fow = new FileOutputStream(file1); BufferedInputStream bis = new BufferedInputStream(fir); BufferedOutputStream bow = new BufferedOutputStream(fow); int len; byte [] bytes = new byte [1024 ]; while ((len = bis.read(bytes)) != -1 ){ bow.write(bytes,0 ,len); } bis.close(); bow.close(); } }
使用缓冲流复制字符文件 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 package com.songzx.exer;import java.io.*;public class BufferCopyChar { public static void main (String[] args) { String fromPath = "hello1.txt" ; String descPath = "hello2.txt" ; try { BufferCopyChar.BufferCopy(fromPath,descPath); } catch (IOException e) { e.printStackTrace(); } } static void BufferCopy (String fromPath,String descPath) throws IOException { File file = new File(fromPath); File file1 = new File(descPath); FileReader fr = new FileReader(file); FileWriter fw = new FileWriter(file1); BufferedReader bfr = new BufferedReader(fr); BufferedWriter bfw = new BufferedWriter(fw); int len; char [] chars = new char [5 ]; while ((len = bfr.read(chars)) != -1 ){ bfw.write(chars,0 ,len); } bfr.close(); bfw.close(); } }
缓冲流都会有 flush
操作去刷新缓冲区。
统计文件中每个字符出现的次数并写入到新的文件中 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 package com.songzx.exer;import java.io.*;import java.util.HashMap;import java.util.Map;import java.util.Set;public class GetTxtNumber { public static void main (String[] args) { try { GetTxtNumber.getCount("hello1.txt" ); } catch (IOException e) { e.printStackTrace(); } } static void getCount (String filePath) throws IOException { File file = new File(filePath); FileReader fr = new FileReader(file); BufferedReader bis = new BufferedReader(fr); HashMap<Character, Integer> map = new HashMap<>(); int key; while ((key = bis.read()) != -1 ){ char mapKey = (char ) key; if (map.containsKey(mapKey)){ int befor = map.get(mapKey); befor+=1 ; map.put(mapKey,befor); }else { map.put(mapKey,1 ); } } File file1 = new File("helloCount.txt" ); FileWriter fileWriter = new FileWriter(file1,true ); Set<Map.Entry<Character, Integer>> entries = map.entrySet(); for (Map.Entry<Character, Integer> entry : entries) { if (map.containsKey(entry.getKey())){ String row = entry.getKey() + ":" + entry.getValue(); fileWriter.write(row + "\n" ); } } bis.close(); fileWriter.close(); } }
转换流概述
两个转换流(都属于字符流)
InputStreamReader
OutputStreamWriter
作用:将字节流和字符流之间相互转换
转换流的综合使用 将原本需要用字节读取的文件用字符来读取
下面代码的逻辑为:
hello2.txt
–> 字节读取(byte
)–> InputStreamReader
转换流 –> 字符读取(char
)
new FileOutputStream("hello3.txt");
–> 字节写入(bytes
) –> OutputStreamWriter
–> 字符写入(char
)
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 package com.songzx.exer;import java.io.*;public class InputStarm { public static void main (String[] args) throws IOException { FileInputStream fr = new FileInputStream("hello2.txt" ); InputStreamReader isr = new InputStreamReader(fr,"utf-8" ); FileOutputStream fos = new FileOutputStream("hello3.txt" ); OutputStreamWriter osw = new OutputStreamWriter(fos); int len; char [] chars = new char [5 ]; while ((len = isr.read(chars)) != -1 ){ osw.write(chars,0 ,len); } osw.close(); isr.close(); } }
数据流的写入和读取
DataOutputStream
DataInputStream
只能写出基本数据类型
在读取数据时要按照写入的顺序读取
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 package com.songzx.exer;import java.io.*;public class DataInput { public static void main (String[] args) throws IOException { DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt" )); dos.writeUTF("zhangsan" ); dos.flush(); dos.writeBoolean(true ); dos.flush(); dos.close(); DataInputStream dis = new DataInputStream(new FileInputStream("data.txt" )); String s = dis.readUTF(); boolean b = dis.readBoolean(); System.out.println(s); System.out.println(b); dis.close(); } }
对象的序列化机制
对象序列化允许把内存中的Java对象转换成与平台无关的二进制流,从而允许把这种二进制流持久的保存再磁盘上,或者通过网络将这种二进制流传输到另外一个网络节点
当其他程序获取到这种二进制流后可以恢复到原来的Java对象
如果需要让某个对象支持序列化机制,则必须让对象的所属类及其属性是可序列化的。为了让某个类是可序列化的,必须让该类继承下面两个接口之一:
Serializable
当实现 Serializable
接口时必须再类内部显示的声明 static final long serialVersionUID = 54564565L;
Externalizable
类内部标记为 static
和 transient
的属性不能被序列化
对象流的写入和读取
ObjectOutputStream
ObjectInputStream
除了可以写出基本数据类型之外,还可以写入Object
类型的数据
在读取数据时可能会报 ClassNotFoundException
错误
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 package com.songzx.exer;import java.io.*;import java.util.Date;public class ObjectStream { public static void main (String[] args) throws IOException, ClassNotFoundException { FileOutputStream fos = new FileOutputStream("objectdata.dat" ); BufferedOutputStream bos = new BufferedOutputStream(fos); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(new Date()); oos.flush(); oos.writeInt(123 ); oos.flush(); FileInputStream fis = new FileInputStream("objectdata.dat" ); BufferedInputStream bis = new BufferedInputStream(fis); ObjectInputStream ois = new ObjectInputStream(bis); Object o = ois.readObject(); int i = ois.readInt(); System.out.println(o); System.out.println(i); oos.close(); ois.close(); } }
自定义类的序列化和反序列化 首先定义一个自定义类,实现 Serializable
接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.songzx.exer;import java.io.Serializable;public class Person implements Serializable { static final long serialVersionUID = 54564565L ; private String name; private int age; public Person (String name, int age) { this .name = name; this .age = age; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } }
实现自定义类的序列化和反序列
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 package com.songzx.exer;import java.io.*;public class ObjectStream2 { public static void main (String[] args) { ObjectOutputStream oos = null ; ObjectInputStream ois = null ; try { oos = new ObjectOutputStream(new FileOutputStream("Person.data" )); oos.writeObject(new Person("张三" ,15 )); oos.flush(); ois = new ObjectInputStream(new FileInputStream("Person.data" )); try { Object o = ois.readObject(); System.out.println(o); } catch (ClassNotFoundException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } finally { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
随机读取文件类
RandomAccessFile
创建一个 RandomAccessFile
时可以指定两种模式
每次读写数据后指针自动往后移动一位
一位表示一个字节
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 package com.songzx.exer;import java.io.IOException;import java.io.RandomAccessFile;public class ReadomAccessTest { public static void main (String[] args) throws IOException { RandomAccessFile raf = new RandomAccessFile("random.txt" ,"rw" ); raf.setLength(0 ); raf.writeByte(1 ); raf.writeByte(2 ); raf.writeByte(3 ); raf.writeByte(4 ); raf.seek(2 ); raf.writeByte(22 ); System.out.println(raf.readByte()); raf.seek(0 ); for (int i = 0 ; i < raf.length(); i++) { System.out.println(raf.readByte()); } } }
RandomAccessFile
实现数据插入
字符串调用 getBytes() 方法将字符转换成字节
使用 list 保存文件中的数据然后遍历重新读取
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 package com.songzx.exer;import java.io.IOException;import java.io.RandomAccessFile;import java.util.ArrayList;public class RandomAccessTest2 { public static void main (String[] args) throws IOException { RandomAccessTest2.setIndex(2 ,"123" .getBytes()); } static void setIndex (int index,byte [] bs) { RandomAccessFile raf = null ; try { raf = new RandomAccessFile("random.data" , "rw" ); raf.seek(index); byte [] bytes = new byte [1024 ]; int len; ArrayList<Byte> oldlist = new ArrayList<>(); while ((len = raf.read(bytes)) != -1 ){ for (int i = 0 ; i < len; i++) { oldlist.add(bytes[i]); } } raf.seek(index); raf.write(bs); for (Byte aByte : oldlist) { raf.writeByte(aByte); } } catch (IOException e) { e.printStackTrace(); } finally { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } }
使用第三方包复制文件 这里我们用到了操作文件的第三方包 org.apache.commons.io.FileUtils
官方网站:https://commons.apache.org/proper/commons-io/
首先我们选择版本下载
点击 download 进入具体的下载页面,然后选择 zip 格式的文件进行下载
下载后解压复制 commons-io-2.11.0.jar
文件
然后回到IDEA中,在我们的工程下右键新建 Directory
输入名称 libs
,然后将我们复制的 jar 文件粘贴到该处并点击OK
然后在这个包上右键选择 Add as Library
将依赖包应用到项目中
点击后在弹出的框中点击ok
然后再代码中就可以用这个包提供的相关方法了
下面的代码将使用这个包提供的复制方法复制一个文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.songzx.io;import org.apache.commons.io.FileUtils;import java.io.File;import java.io.IOException;public class UtilsFilsTest { public static void main (String[] args) { File srcFile = new File("向日葵.png" ); File descFile = new File("向日葵2.png" ); try { FileUtils.copyFile(srcFile,descFile); } catch (IOException e) { e.printStackTrace(); } } }
编程练习题 创建文本文件并追加数据 实现往一个文本文件中追加100个随机生成的整数,如果文件不存在则创建该文件。整数用空格分隔,文件名:Exer01.txt
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 package com.songzx.test;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Exer1 { public static void main (String[] args) throws IOException { FileWriter fw = new FileWriter("Exer01.txt" ,true ); for (int i = 0 ; i < 100 ; i++) { int v = (int ) (Math.random() * 100 + 1 ); fw.write(v + "\t" ); } fw.close(); } }
创建字节文件并追加数据 实现往一个字节文件中追加100个随机生成的整数,如果文件不存在则创建该文件。整数用空格分隔,文件名:Exer02.txt
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 package com.songzx.test;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class Exer2 { public static void main (String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("Exer02.data" ); for (int i = 0 ; i < 100 ; i++) { int v = (int ) (Math.random() * 100 ) + 1 ; fos.write(v); } fos.close(); FileInputStream fis = new FileInputStream("Exer02.data" ); int len; byte [] bytes = new byte [5 ]; while ((len = fis.read(bytes))!=-1 ){ for (int i = 0 ; i < len; i++) { System.out.println(bytes[i] + "===>" + i); } } fis.close(); } }
对字节文件中的所有整数进行求和 这道题默认你已经完成了第二道题目
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 package com.songzx.test;import java.io.FileInputStream;import java.io.IOException;public class Exer3 { public static void main (String[] args) throws IOException { FileInputStream fis = new FileInputStream("Exer02.data" ); int len; int count = 0 ; byte [] bytes = new byte [5 ]; while ((len = fis.read(bytes)) != -1 ){ for (int i = 0 ; i < len; i++) { count += bytes[i]; } } System.out.println(count); fis.close(); } }
将文本文件转换为UTF 读取一个文本文件,并将这个文件的数据以utf-8的格式写入一个字节文件中
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 package com.songzx.test;import java.io.*;public class Exer4 { public static void main (String[] args) throws IOException { InputStreamReader isr = new InputStreamReader(new FileInputStream("hello2.txt" ),"utf-8" ); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Exer03.dat" ),"utf-8" ); int len; char [] chars = new char [5 ]; while ((len = isr.read(chars)) != -1 ){ osw.write(chars,0 ,len); } isr.close(); osw.close(); } }
将对象和数组保存在文件中 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 package com.songzx.test;import java.io.*;import java.util.Date;public class Exer5 { public static void main (String[] args) throws IOException, ClassNotFoundException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Exer05.txt" )); int [] ints = {1 , 2 , 3 , 4 , 5 }; Date date = new Date(); double d = 55.55 ; oos.writeObject(ints); oos.writeObject(date); oos.writeDouble(d); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Exer05.txt" )); Object o = ois.readObject(); Object o1 = ois.readObject(); double v = ois.readDouble(); System.out.println(o); System.out.println(o1); System.out.println(v); ois.close(); } }
使用 RandomAccessFile
切割文件 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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package com.songzx.test;import java.io.*;public class SplitPng { public static void main (String[] args) { SplitPng.splitPngFun(); SplitPng.mergePng(); } static void splitPngFun () { RandomAccessFile raf = null ; try { raf = new RandomAccessFile("向日葵.png" , "rw" ); try { System.out.println(raf.length()); raf.seek(0 ); FileOutputStream fis = new FileOutputStream("图片1.png" ,true ); FileOutputStream fis2 = new FileOutputStream("图片2.png" ,true ); FileOutputStream fis3 = new FileOutputStream("图片3.png" ,true ); while ((raf.getFilePointer() < raf.length())){ long nowPoint = raf.getFilePointer(); System.out.println(nowPoint); if (nowPoint >=0 && nowPoint <= 200000 ){ fis.write(raf.readByte()); } if (nowPoint >200000 && nowPoint <= 400000 ){ fis2.write(raf.readByte()); } if (nowPoint >400000 && nowPoint < raf.length()){ fis3.write(raf.readByte()); } } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } static void mergePng () { FileInputStream fis1 = null ; FileInputStream fis2 = null ; FileInputStream fis3 = null ; FileOutputStream fos = null ; try { fis1 = new FileInputStream("图片1.png" ); fis2 = new FileInputStream("图片2.png" ); fis3 = new FileInputStream("图片3.png" ); fos = new FileOutputStream("合成.png" , true ); int len; byte [] bytes = new byte [1024 ]; while ((len = fis1.read(bytes)) != -1 ) { fos.write(bytes, 0 , len); } while ((len = fis2.read(bytes)) != -1 ) { fos.write(bytes, 0 , len); } while ((len = fis3.read(bytes)) != -1 ) { fos.write(bytes, 0 , len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fis1.close(); } catch (IOException e) { e.printStackTrace(); } try { fis2.close(); } catch (IOException e) { e.printStackTrace(); } try { fis3.close(); } catch (IOException e) { e.printStackTrace(); } try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } }