IO Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。
但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
对象创建 1 2 FileInputStream stream = new FileInputStream ("C:\\JavaIO\\a.txt" );FileInputStream stream1 = new FileInputStream (new File ("C:\\JavaIO\\a.txt" ));
一次读取一个字节 1 2 3 4 FileInputStream stream = new FileInputStream (new File ("C:\\JavaIO\\a.txt" ));int read = stream.read();stream.close(); System.out.println(read);
当读到 - 1 时则表示读取结束了1 2 3 4 5 6 FileInputStream stream = new FileInputStream (new File ("C:\\JavaIO\\a.txt" ));int b;while ((b=stream.read()) != -1 ){ System.out.println(b); } stream.close();
循环读取全部内容
一次读一个字节数组 1 2 3 4 FileInputStream stream = new FileInputStream (new File ("C:\\JavaIO\\a.txt" ));byte [] bytes = new byte [5 ];stream.read(bytes); System.out.println(Arrays.toString(bytes));
一次读完文件 1 2 3 4 5 6 7 8 FileInputStream stream = new FileInputStream (new File ("C:\\JavaIO\\a.txt" ));byte [] bytes = new byte [1024 * 2 ];int len;while ((len=stream.read(bytes))!=-1 ){ System.out.println(len); System.out.println(new String (bytes,0 ,len)); } stream.close();
资源释放 解决读取期间出现异常如何正确释放资源
jdk7 之前 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 FileInputStream stream = null ;try { stream = new FileInputStream (new File ("C:\\JavaIO\\a.txt" )); byte [] bytes = new byte [1024 * 2 ]; int len; while ((len=stream.read(bytes))!=-1 ){ System.out.println(new String (bytes,0 ,len)); } }catch (IOException ioException){ ioException.printStackTrace(); }finally { if (!Objects.isNull(stream)){ try { stream.close(); } catch (IOException e) { e.printStackTrace(); } } }
jdk7 版本 1 2 3 4 5 6 7 8 9 10 11 12 try (FileInputStream stream = new FileInputStream (new File ("C:\\JavaIO\\a.txt" ))) { byte [] bytes = new byte [1024 * 2 ]; int len; while ((len=stream.read(bytes))!=-1 ){ System.out.println(new String (bytes,0 ,len)); } stream.close(); }catch (IOException e){ e.printStackTrace(); }
jdk7 版本是如何做到自动释放资源的呢?下面通过代码来讲解一下。
在代码 try(FileInputStream stream = new FileInputStream(new File("C:\\JavaIO\\a.txt")))
中,创建的对象 FileInputStream 是继承了 InputStream 的
而在 InputStream 中实现了了 Closeable 接口
在 Closeable 中定义了一个 close 方法,该方法继承于 AutoCloseable
因为 FileInputStream 继承了 InputStream,而 InputStream 实现了 Closeable 接口,所以在 FileInputStream 产生异常时就会执行它的 close 方法。
通过自己写代码来重现一下这个过程1 2 3 4 5 6 7 public class Res implements Closeable { @Override public void close () throws IOException { System.out.println("资源已经释放" ); } }
1 2 3 4 5 6 7 public static void main (String[] args) { try (Res res = new Res ()) { }catch (IOException e){ e.printStackTrace(); } }
jdk9 版本 1 2 3 4 5 6 7 8 public static void main (String[] args) { Res res = new Res (); try (res) { }catch (Exception e){ e.printStackTrace(); } }
在 jdk9 中在 jdk7 的基础上做了优化,定义不一定要放到 try 中,只需要讲对象放在 try () 中就可以实现自动执行 close 方法的效果
FileOutputStream 对象创建 1 2 FileOutputStream fileOutputStream = new FileOutputStream ("C:\\JavaIO\\b.txt" );FileOutputStream fileOutputStream1 = new FileOutputStream (new File ("C:\\JavaIO\\b.txt" ));
一次写一个字节 1 2 3 4 5 6 7 FileOutputStream fos = new FileOutputStream ("C:\\JavaIO\\b.txt" );try (fos) { fos.write('a' ); }catch (IOException e){ e.printStackTrace(); }
一次写一个字节数组 1 2 3 4 5 6 7 8 9 FileOutputStream fos = new FileOutputStream ("C:\\JavaIO\\b.txt" ); byte [] bytes; try (fos) { bytes = "abc" .getBytes(); fos.write(bytes); }catch (IOException e){ e.printStackTrace(); } }
文件续写 1 2 3 4 5 6 7 8 FileOutputStream fos = new FileOutputStream ("C:\\JavaIO\\b.txt" ,true );try (fos) { byte [] bytes = "defgh" .getBytes(); fos.write(bytes); }catch (IOException e){ e.printStackTrace(); }
文件的复制 文件的复制就是循环的循环读写1 2 3 4 5 6 7 8 9 10 11 12 13 private static void copyFile (File from, File to) throws IOException{ FileInputStream inputStream = new FileInputStream (from); FileOutputStream outputStream = new FileOutputStream (to); try (inputStream;outputStream) { byte [] bytes = new byte [1024 * 2 ]; int len; while ((len=inputStream.read(bytes))!=-1 ){ outputStream.write(bytes,0 ,len); } }catch (IOException e){ e.printStackTrace(); } }
定义一个方法,循环读取旧文件的内容并且写到新文件中1 2 3 4 5 public static void main (String[] args) throws IOException { File oldFile = new File ("C:\\JavaIO\\file.mp3" ); File newFile = new File ("C:\\JavaIO\\newFile.mp3" ); copyFile(oldFile,newFile); }
文件夹的复制 从简单到困难,先写一个不考虑子文件夹递归的复制文件操作
不考虑递归版本 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 public static void main (String[] args) throws IOException { File fromDir = new File ("C:\\本地素材库\\2022-07-19" ); File toDir = new File ("C:\\本地素材库\\2022年07月19日" ); copyFolderFile(fromDir,toDir); } private static void copyFolderFile (File from,File to) throws IOException { File[] files = from.listFiles(); byte [] bytes = new byte [1024 * 2 ]; for (File file : files) { if (file.isDirectory()){ continue ; } File oldFile = new File (from, file.getName()); File newFile = new File (to, file.getName()); FileInputStream fis = new FileInputStream (oldFile); FileOutputStream fos = new FileOutputStream (newFile); try (fis;fos) { int len; while ((len=fis.read(bytes))!=-1 ){ fos.write(bytes,0 ,len); } }catch (IOException e){ e.printStackTrace(); } } }
源文件夹共有 148 个文件,对该文件夹进行复制后,所以文件都复制到了目标文件夹
递归版本 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 public static void main (String[] args) throws IOException { File fromDir = new File ("C:\\本地素材库\\2022-07-19" ); File toDir = new File ("C:\\本地素材库\\2022年07月19日" ); copyAllFile(fromDir,toDir); } private static void copyAllFile (File from,File to) throws IOException { File[] files = from.listFiles(); byte [] bytes = new byte [1024 * 2 ]; for (File file : files) { if (file.isFile()){ FileInputStream inputStream = new FileInputStream (file); FileOutputStream outputStream = new FileOutputStream (new File (to, file.getName())); try (inputStream;outputStream) { int len; while ((len=inputStream.read(bytes))!=-1 ){ outputStream.write(bytes,0 ,len); } }catch (IOException e){ e.printStackTrace(); } }else { File newDir = new File (to, file.getName()); if (!newDir.exists()){ newDir.mkdir(); } copyAllFile(file,newDir); } } }
FileReader 对象创建 文件的目标不可以是文件夹,否则会产生异常1 2 FileReader fileReader = new FileReader ("C:\\JavaIO\\file.mp3" );FileReader reader = new FileReader (new File ("C:\\JavaIO\\file.mp3" ));
一次读取一个字节 1 2 3 4 5 6 FileReader fileReader = new FileReader ("C:\\JavaIO\\a.txt" );try (fileReader) { System.out.println((char )fileReader.read()); }catch (IOException e){ e.printStackTrace(); }
1 2 3 4 5 6 7 8 9 FileReader fileReader = new FileReader ("C:\\JavaIO\\a.txt" );try (fileReader) { int ch; while ((ch=fileReader.read())!=-1 ){ System.out.println((char ) ch); } }catch (IOException e){ e.printStackTrace(); }
一次读一个数组 1 2 3 4 5 6 7 8 9 try (FileReader fileReader = new FileReader ("C:\\JavaIO\\a.txt" )) { char [] chars = new char [1024 * 2 ]; int len; while ((len=fileReader.read(chars))!=-1 ){ System.out.println(new String (chars,0 ,len)); } } catch (IOException e) { e.printStackTrace(); }
需要注意的是需要使用 char [] 接收内容
FileWriter 对象创建 1 FileWriter fw = new FileWriter ("C:\\JavaIO\\a.txt" );
缓冲区 1 2 3 4 5 6 7 8 9 FileWriter fw = new FileWriter ("C:\\JavaIO\\a.txt" );try (fw) { fw.write("12345678910" ); fw.flush(); }catch (IOException e){ e.printStackTrace(); }
在写操作中需要从缓冲区写到文件的操作,也就是需要通过 flush 写入文件。
复制文本文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void main (String[] args) throws IOException { copyText(new File ("C:\\JavaIO\\斗破苍穹.txt" ),new File ("C:\\JavaIO\\Break through the sky.txt" )); } private static void copyText (File from, File to) throws IOException { FileReader reader = new FileReader (from); FileWriter writer = new FileWriter (to); char [] chars = new char [1024 * 2 ]; try (reader;writer) { int len; while ((len=reader.read(chars))!=-1 ){ writer.write(chars,0 ,len); writer.flush(); } }catch (IOException e){ e.printStackTrace(); } }
其实跟字节流的读写相比,其实差得并不算多。
设置字符流编码表 1 FileReader reader = new FileReader (from, StandardCharsets.UTF_8);
高速缓冲流 对象创建 1 2 3 4 BufferedInputStream bufferedInputStream = new BufferedInputStream (new FileInputStream ("C:\\JavaIO\\a.txt" ));BufferedOutputStream bufferedOutputStream = new BufferedOutputStream (new FileOutputStream ("C:\\JavaIO\\a.txt" ));BufferedReader bufferedReader = new BufferedReader (new FileReader ("C:\\JavaIO\\Break through the sky.txt" ));BufferedWriter bufferedWriter = new BufferedWriter (new FileWriter ("C:\\JavaIO\\Break through the sky.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 public static void main (String[] args) throws IOException { FileReader fr = new FileReader ("C:\\JavaIO\\Break through the sky.txt" ); FileWriter fw = new FileWriter ("C:\\JavaIO\\斗破苍穹.txt" ); BufferedReader br = new BufferedReader (new FileReader ("C:\\JavaIO\\Break through the sky.txt" )); BufferedWriter bw = new BufferedWriter (new FileWriter ("C:\\JavaIO\\斗破苍穹.txt" )); copyFile(fr,fw); bufferCopyFile(br,bw); } private static void copyFile (FileReader fr,FileWriter fw) throws IOException { long start = System.nanoTime(); char [] chars = new char [1024 * 2 ]; int len; while ((len=fr.read(chars))!=-1 ){ fw.write(chars,0 ,len); } fr.close(); fw.close(); long end = System.nanoTime(); System.out.println("普通复制运行时间:" +(end-start)+"ms" ); } private static void bufferCopyFile (BufferedReader br,BufferedWriter bw) throws IOException { long start = System.nanoTime(); String line; while ((line=br.readLine())!=null ){ bw.write(line); bw.newLine(); } br.close(); bw.close(); long end = System.nanoTime(); System.out.println("高速缓存运行时间:" +(end-start)+"ms" ); }