Java——I/O(字节流、字符流与转换流 )


目录
字节流和字符流
1. 流操作流程
2. 字节输出流(OutputStream)
2.1 输出方法
3. 自动关闭支持AutoCloseable-JDK1.7
【Java——I/O(字节流、字符流与转换流 )】4. 字节输入流(InputSream)
4.1 输入方法
5. 字符流
5.1 字符输出流(Writer)
5.2 字符输入流(Reader)
6. 字节流与字符流
7. 转换流
字节流和字符流 字节流(byte):InputStream、OutputStream
字符流(char):Reader、Writer

  • 字节流与字符流的区别:
字节流是原生的操作,而字符流是字节流经过处理后的操作。
  • 一般使用字节流——无论是网络传输还是磁盘的数据保存均以字节为单位,只有处理中文文本时才会用到字符流。
1. 流操作流程
  • 输入流:
  1. 准备文件
  2. 实例化FileInputSream对象
  3. read()读取数据
  4. 业务处理数据
  5. 关闭输入流-finally
  • 输出流:
  1. 准备文件,文件不存在自动创建,但是目录一定要存在
  2. 实例化FileOutputSream对象
  3. 业务处理数据
  4. write()输出数据
  5. 关闭输出流-finally
  • 业务处理
    读取数据 -> while( ){ },读到末尾返回-1
package com.qqy.io; import java.io.*; import java.nio.file.Paths; /** * 将文件当作输入流,读取内容并处理,再输出到另一个文件中 * Author: qqy */ public class Test { public static void main(String[] args) { File inputFile = Paths.get("E:" , "JAVA" ,"input.txt").toFile(); File outputFile = Paths.get("E:" , "JAVA" ,"output.txt").toFile(); if(!outputFile.getParentFile().exists()){ outputFile.getParentFile().mkdirs(); }FileInputStream ins=null; FileOutputStream out=null; try { ins=new FileInputStream(inputFile); //输出流中的内容向后追加 //out=new FileOutputStream(outputFile,true); //默认false,不追加 out=new FileOutputStream(outputFile); //若读取结束,则返回-1 int value=https://www.it610.com/article/-1; //输入 //从输入流读取数据的下一个字节 while((value=ins.read())!=-1){ //将大写变为小写 value= value +32; //输出 out.write(value); } } catch (IOException e) { e.printStackTrace(); }finally{ if(ins!=null) { //关闭数据流 try { ins.close(); } catch (IOException e) { e.printStackTrace(); } } if(out!=null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }

  • I/O操作属于于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)使用后必须要进行关闭。
2. 字节输出流(OutputStream)
public abstract class OutputStream implements Closeable, Flushable

//Closeable接口: public void close() throws IOException; //Flushable接口: public void ?ush() throws IOException;

  • 2.1 输出方法
//将给定的字节数组内容全部输出 public void write(byte b[]) throws IOException //将部分字节数组内容输出 public void write(byte b[], int o?, int len) throws IOException //输出单个字节 public abstract void write(int b) throws IOException;

  • 要进行文件内容的输出,使用FileOutputStream()
//文件内容覆盖 public FileOutputStream(File file) throws FileNotFoundException //文件内容追加 public FileOutputStream(File file,boolean append) throws FileNotFoundException

  • 当使用FileOutputStream进行文件内容输出时,只要文件父路径存在,FileOutputStream会自动创建文件
import java.io.*; /** * 字节输出流 * Author: qqy */ public class Test { public static void main(String[] args) throws IOException { //1.取得终端对象 File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt"); //只要文件父路径存在,FileOutputStream会自动创建文件 //OutputStream为抽象方法,需要借用子类进行实例化 OutputStream out =null; OutputStream out1 =null; //2.取得终端对象的输出流 try { out = new FileOutputStream(file); //允许内容的追加 out1 = new FileOutputStream(file,true); //3.进行数据的输出 String msg="你好世界!!!\r\n"; //当出现中文时,最好全部输出,避免出现乱码 out.write(msg.getBytes(),0,6); //你好 out1.write(97); //a } catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }finally{ //4.关闭流 out.close(); out1.close(); } } }

3. 自动关闭支持AutoCloseable-JDK1.7
  • 使用前提:结合try...catch...
/** * 自动关闭 * Author: qqy */ public class Test1 { public static void main(String[] args) { //try-with-resources //实现AutoCloseable接口后,对资源的一些释放、关闭,JVM可以自动调用close() //try(实例化对象的代码,实例化对象的类实现AutoCloseable接口) //实例化多个对象时,用分号隔开,最后一个不用加分号 try(Msg msg1=new Msg() ){ //自动调用close() msg.print(); //normal method...auto close... }catch (Exception e){} } }class Msg implements AutoCloseable{@Override public void close() throws Exception { System.out.println("auto close..."); }public void print(){ System.out.println("normal method..."); } }

4. 字节输入流(InputSream)
public abstract class InputStream implements Closeable

  • 4.1 输入方法
//读取数据到字节数组b中 public int read(byte b[]) throws IOException //读取单个字节 public int read() throws IOException

  • 返回值:
返回b长度:读取数据大小>字节数组大小,返回字节数组大小
返回大于0但是小于b长度:读取数据大小<字节数组大小,返回真正读取个数
返回-1:数据读取完毕
import java.io.*; /** * 字节输入流和输出流的缓存方式读取和写入 * Author: qqy */ public class Test{ public static void main(String[] args) throws IOException { //1.取得File对象 File file = new File("E:" + File.separator + "JAVA" + File.separator + "input.txt"); File destFile = new File("E:" + File.separator + "JAVA" + File.separator + "output.txt"); //2.取得输入流、输出流 InputStream in = null; OutputStream out = null; try { in = new FileInputStream(file); out = new FileOutputStream(destFile); } catch (FileNotFoundException e) { e.printStackTrace(); } //3.读取文件内容、写入内容 byte[] data = https://www.it610.com/article/new byte[5]; int value = -1; try { //从输入流读取数据的一些字节数,并将其存储到缓冲区data //每次循环,先开辟一个长度为5的数组,读取文件中从头开始的3个字节,放入该数组的第1个位置 // value存放每次读的内容的长度,b是每次数组中存放的内容 while ((value = in.read(data, 1, 3)) != -1) { System.out.println(value); //31 System.out.println(new String(data)); // ABCDBCout.write(data); //写入为ABCDBC //缓冲方式写数组的时候,偏移量为0,res为每一批读的数据的量 out.write(data, 0, value); } } catch (IOException e) { e.printStackTrace(); } //4.关闭流 in.close(); out.close(); }}

5. 字符流
  • 5.1 字符输出流(Writer)
实现了Closeable接口,可以自动关闭
public abstract class Writer implements Appendable, Closeable, Flushable

除了参数为字符数组外,多了一个传入String对象的方法
public void write(String str) throws IOException

import java.io.*; /** * 字符输出流 * Author: qqy */ public class Test3 { public static void main(String[] args) throws IOException { //1.取得File对象 File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt"); //2.取得输出流 Writer writer=new FileWriter(file); //3.写入数据 String str="你好 Bonjour !!"; writer.write(str); writer.write(new char[]{'a','b','c','\n'}); writer.write(new char[]{'A','B','C'},2,1); //4.关闭流 writer.close(); } }

  • 5.2 字符输入流(Reader)
Reader类中没有方法可以直接读取字符串,只能通过字符数组来读取
import java.io.*; /** * 字符输入流 * Author: qqy */ public class Test4 { public static void main(String[] args) throws IOException { //1.取得File对象 File file = new File("E:"+File.separator+"JAVA"+File.separator+"Test.txt"); //2.取得输入流 Reader reader= new FileReader(file); //3.读取数据 char[] data=https://www.it610.com/article/new char[1024]; int result=reader.read(data); System.out.println(result); System.out.println(new String(data,0,result)); //4.关闭流 reader.close(); } }

6. 字节流与字符流
  • 开发中,优先考虑字节流,只有处理中文时才考虑使用字符流。
  • 所有字符流操作,无论是写入还是输出,数据都先保存在缓存中——字符输出流不关闭,文件中无内容;字节输出流不关闭,文件中有内容。
  • 想要将字符输出流在文件中显示,要么正常关闭—out.close(),要么强制清空缓存区—out.flush()
练习:文件复制(字节流)
import java.io.*; import java.nio.file.Paths; /** * 文件复制 * Author: qqy */ public class Test6 { public static void main(String[] args) throws IOException { String src=""; String dest=""; long start=System.currentTimeMillis(); //毫秒数 copy(src,dest); long end=System.currentTimeMillis(); System.out.println(end-start/1000+"s"); //秒数 }public static void copy(String srcFilePath,String destFilePath){ //参数校验 if (srcFilePath==null||srcFilePath.isEmpty()) { throw new IllegalArgumentException("srcFilePath not null/empty!"); } if (destFilePath==null||destFilePath.isEmpty()) { throw new IllegalArgumentException("destFilePath not null/empty!"); }File srcFile =Paths.get(srcFilePath).toFile(); File destFile =Paths.get(destFilePath).toFile(); //文件校验以及准备工作 if(!srcFile.exists()||!srcFile.isFile()){ throw new IllegalArgumentException("srcFilePath not exists or not file!") }File parentFile= destFile.getParentFile(); if(!parentFile.exists()){ if(!parentFile.mkdirs()){ throw new RuntimeException("can't create"+parentFile.getAbsolutePath()+"directory"); } }//文件复制 try(FileInputStream in=new FileInputStream(srcFile); FileOutputStream out =new FileOutputStream(destFile) ){ //缓冲数组 //引入缓冲区 byte[] buff = new byte[1024]; //1k,2k,4k,8k int len=-1; //一次只读一个字节,再输出一个字节 while((len=in.read(buff))!=-1){ //为了避免数据读取不全,使用下列方式进行写入 out.write(buff,0,len); } }catch(IOException e){ System.out.println(e.getMessage()); } } }

7. 转换流 字节流—>字符流,用于将底层的字节流转为字符流供子类使用
OutputStreamWriter:字节输出流—>字符输出流
InputStreamReader:字节输入流—>字符输入流
import java.io.*; /** * 转换流 * Author: qqy */ public class Test7 { public static void main(String[] args) throws IOException { //1.取得文件对象 File file = new File ("E:"+File.separator+"JAVA"+File.separator+"Test.txt"); //2.取得输出流 OutputStream outputStream=new FileOutputStream(file); //3.字节流变为字符流,注意编码格式 OutputStreamWriter out=new OutputStreamWriter(outputStream); out.write("你好 Bonjour"); //4.关闭流 out.close(); } }


    推荐阅读