Java 中的IO 流,讲解(参考尚硅谷素材)

Java I/O 流

一 、File 类的使用

1、File 类的作用

  • java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关
  • File 能新建、删除、重命名文件和目录,但File 不能访问文件本身的内容。如果需要访问文件内容本身,则需要使用输入或输出流。
  • 想要在Java 程序中表示一个真实存在的文件或者目录,那么必须有一个File 对象,但是Java 程序中的一个File 对象,可能没有一个真实存在的文件或目录。
  • File 对象可以作为参数传递给流的构造器

2、File 类的使用:常用构造器

  • public File(String pathname)

    pathname 为路径创建File 对象,可以是绝对路径或者相对路径,如果pathname 是相对路径,则默认的当前路径在系统属性use.dir 中存储。

    • 绝对路径:是一个固定的路径,从盘符开始
    • 相对路径:是相对于某个位置开始
  • public File(String parent,String child)

    以 parent 为父路径,child 为子路径创建File 对象。

  • public File(File parent,String child)

    根据一个父File对象和子文件路径创建File对象

3、File 类的使用:路径分隔符

  • 路径中的每级目录之间用一个路径分隔符隔开

  • 路径分隔符和系统有关:

    • window 和 dos 系统默认使用“\”来表示
    • UNIX 和 URL 使用“/” 来表示
  • Java 程序支持跨平台运行,因此路径分隔符要慎用。(现在版本可以在win上使用/)

  • 可以使用public static final String separator 。可以根据操作系统,动态的提供分隔符。

    举例:

    File file1 = new File("d:\\atguigu\\info.txt");
    File file2 = new File("d:" + File.separator + "atguigu" + File.separator + "info.txt");
    File file3 = new File("d:/atguigu");
    

4、File 类的使用:常用方法

  • File 类的获取功能

    • public String getAbsolutePath() :获取绝对路径
    • public String getPath() :获取路径
    • public String getName() : 获取名称
    • public String getParent():获取上层文件目录路径。若无,返回null
    • public long length:获取文件长度(即:字节数)。不能获取目录的 长度
    • public long lastModified():获取最后一次的修改时间,毫秒值
    • public String[] list():获取指定目录下的所有文件或者文件目录的名称数组
    • public File[] listFiles():获取指定目录下的所有文件或者文件目录的File数组
  • File 类的重命名功能

    • public boolean renameTo(File dest):把文件重命名为指定的文件路径
  • File 类的判断功能

    • public boolean isDirectory():判断是否是文件目录
    • public boolean isFile():判断是否为文件
    • public boolean exist() :判断是否存在
    • public boolean canRead():判断是否可读
    • public boolean canWrite():判断是否可写
    • pubic boolean isHidden():判断是否隐藏
  • File 类的创建功能

    • public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
    • public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
    • public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建。

    注意事项:如果你创建文件或者文件目录没有写盘符路径,那么默认在项目路径下。

  • File 类的删除功能

    • public boolean delete() :删除文件或者文件夹

      删除注意事项:

      java 中的删除不走回收站。

      要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。

5、File 类的使用:代码示例

public class FileTest {
	public static void main(String[] args) throws IOException {
		//使用绝对路径创建一个File 对象
		File file01 = new File("D:/DxOffice/FileTest/a.txt");
		if (!file01.exists()) {
			file01.createNewFile();
		} 
		//获取相对路径
		System.out.println(file01.getAbsolutePath()); //
		System.out.println(file01.getPath());
		//获取名称
		System.out.println(file01.getName());
		System.out.println(file01.getParent());
		System.out.println(file01.length());
		File file02 = new File(file01.getParent());
		File[] fileList = file02.listFiles();
		for(File f : fileList) {
			System.out.println(f.toString());
		}
		
	}
}

输出结果

D:\DxOffice\FileTest\a.txt
D:\DxOffice\FileTest\a.txt
a.txt
D:\DxOffice\FileTest
13
D:\DxOffice\FileTest\a.txt

二、I/O 流的原理及流的分类

1、Java IO 原理

  • I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
  • Java程序中,对于数据的输入/输出操作以==“流(stream)"==的方式进行。
  • java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
  • 输入input读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中
  • 输出output :将程序内存中数据输出到磁盘、光盘等存储设备中。

2、流的分类

  • 操作数据单位不同分为:字节流(8bit)字符流(16bit)

  • 数据流的流向不同分为:输入流输出流

  • 流的角色的不同分为:节点流处理流

    • 节点流:直接从数据源或目的地读写数据
    • 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
    (抽象基类)字节流字符流
    输入流InputStreamReader
    输出流OutputStreamWriter

    image-20200729202220192

    image-20200729202312522

2.1(输入)InputStream & Reader
  • InputStream 和 Reader 是所有输入流的基类。

  • InputStream(典型实现:FileInputStream

    • int read()

      从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。

    • int read(byte[] b)

      从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取的字节数。

    • int read(byte[] b,int off, int len)

      将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于文件末尾而没有可用的字节,则返回值 -1。

    • public void close() throws IOException

      关闭此输入流并释放与该流关联的所有系统资源。

  • Reader(典型实现:FileReader

    • int read()

      读取单个字符。作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码),如果已到达流的末尾,则返回 -1

    • int read(char[] c)

      将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。

    • int read(char[] c,int off,int len)

      将字符读入数组的某一部分。存到数组cbuf中,从off处开始存储,最多读len个字符。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。

    • public void close() throws IOException

      关闭此输入流并释放与该流关联的所有系统资源。

  • 程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资

    源,所以应该显式关闭文件 IO 资源对象 . close() 先定义的后回收。

  • FileInputStream 从文件系统中的某个文件中获得输入字节。FileInputStream

    用于读取非文本数据之类的原始字节流。要读取字符流,需要使用 FileReader

2.2(输出)OutputStream & Write
  • OutputStream 和 Write是所有输出流的基类。

  • OutputStream (典型实现:FileOutputStream

    • int write(int b)

      将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入0~255范围的。

    • int write(byte[] b)

      将 b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定是:应该与调用 write(b, 0, b.length) 的效果完全相同。

    • int write(byte[] b,int off, int len)

      将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

    • void flush()

      刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。

    • public void close() throws IOException

      关闭此输入流并释放与该流关联的所有系统资源。(需要先刷新,再关闭此流)

  • Writer(典型实现:FileWriter

    注意,write中的参数也可用字符串来代替字符数组

    • int write(String str)

      写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。 即写入0 到 65535 之间的Unicode码。(或者写入字符串。)

    • int write(char[] c)

      写入字符数组。

    • int write(char[] c,int off,int len)

      写入字符数组的某一部分。从off开始,写入len个字符

    • void flush()

      刷新该流的缓冲,则立即将它们写入预期目标。

    • public void close() throws IOException

      关闭此输入流并释放与该流关联的所有系统资源。

  • 程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资

    源,所以应该显式关闭文件 IO 资源对象 . close() 先定义的后回收。

  • FileInputStream 从文件系统中的某个文件中获得输入字节。FileInputStream

    用于读取非文本数据之类的原始字节流。要读取字符流,需要使用 FileReader

2.3、节点流(或文件流)
  • 读取文件

    	public void fileRead() throws IOException {
    		File f1 = new File("D:/DxOffice/FileTest/a.txt");
    		
    		//建立一个流对象,将已存在的一个文件加载进流
    		FileReader fr = new FileReader(f1);
    		
    		//创建一个临时存放数据的数组
    		char[] ch = new char[1024];
    		
    		//调用流对象的读取方法将流中的数据读入到数组中
    		fr.read(ch);
    		
    		//关闭资源
    		fr.close();
    	}
    
  • 写入文件

    	public void fileWrite() throws IOException {
    		File f1 = new File("D:/DxOffice/FileTest/a.txt");
    		
    		//创建流对象,建立数据存放文件
    		FileWriter fw = new FileWriter(f1);
    		
    		//创建一个已经存入数据的字符串,写入文件
    		String str = "adadadadadad";
    		
    		//调用流对象的写入方法,将数据写入流
    		fw.write(str);
    		
    		//刷新缓冲
    		fw.flush();
    		
    		//关闭流
    		fw.close();
    	}
    
  • 字节流(或文件流):注意点

    • 定义文件路径时,注意:可以用“/”或者“\”。

    • 在写入一个文件时,如果使用构造器FileOutputStream(file),则目录下有同名文件将被覆盖。

    • 如果使用构造器FileOutputStream(file,true),则目录下的同名文件不会被覆盖,在文件内容末尾追加内容。

    • 在读取文件时,必须保证该文件已存在,否则报异常。

    • 字节流操作字节,比如:.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt

    • 字符流操作字符,只能操作普通文本文件。最常见的文本文

      件:.txt,.java,.c,.cpp 等语言的源代码。尤其注意.doc,excel,ppt这些不是文本文件。

2.4、处理流
2.4.1、处理流之一:缓冲流
  • 缓冲流的作用

    • 为了提高读写的速度 ,Java API 提供了带缓冲的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8kb)的缓冲区

      源码

      image-20200730081511286

    • 缓冲流要“套接”在相应的字节流之上,根据数据单位可以把缓冲流分为:

      BufferedInputStrem 和 BufferedOutputStream

      BufferedReader 和 BufferedWriter

  • 缓冲流的特点:

    • 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区

    • 当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。

    • 向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,

    BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法

    flush()可以强制将缓冲区的内容全部写入输出流

    • 关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也

      会相应关闭内层节点流

    • flush()方法的使用:手动将buffer中内容写入文件

    • 如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷

      新缓冲区,关闭后不能再写出

  • 代码示例

    	@Test
    	public void bufferedRW() throws IOException {
    		//创建输入输出节点流
    		FileReader fr = new FileReader("D:/DxOffice/FileTest/a.txt");
    		FileWriter fw = new FileWriter("D:/DxOffice/FileTest/b.txt");
    		//创建缓冲流对象:它是处理流,是对节点流的包装
    		BufferedReader br = new BufferedReader(fr);
    		BufferedWriter bw = new BufferedWriter(fw);
    		String str;
    		while ((str = br.readLine()) != null) { //一次读取字符文本文件的一行字符
    			bw.write(str); //一次写入一行字符串
    			bw.newLine(); //写入分隔符
    		}
    		bw.flush();
    		//关闭流对象
    		//关闭缓冲流对象时,会自动关闭它所包装的节点流
    		bw.close();
    		br.close();
    		
    	}
    
2.4.2、处理流之二:转换流
  • 转换流的作用

    • 转换流提供了在字节流和字符流之间的转换
    • Java API提供了两个转换流:
      • InputStreamReader:将InputStream转换为Reader
      • OutputStreamWriter:将Writer转换为OutputStream
    • 字节流中的数据都是字符时,转成字符流操作更高效
    • 很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
  • InputStreamReader

    • 实现将字节的输入流按指定字符集转换为字符的输入流

    • 需要和InputStream“套接”。

    • 构造器

      • public InputStreamReader(InputStream in)

      • public InputSreamReader(InputStream in,String charsetName)

        示例

        Reader isr = new InputStreamReader(System.in;"gbk");
        //gbk 为字符编码集
        
  • OutputStreamWriter

    • 实现将字符的输出流按指定字符集转换为字节的输出流
    • 需要和OutputStream“套接”。
    • 构造器
      • public OutputStreamWriter(OutputStream out)
      • public OutputSreamWriter(OutputStream out,String charsetName)
  • 图解

    image-20200730085717699

  • 代码示例

    	@Test
    	public void transformStream() throws IOException {
    		//创建字节输入输出流对象
    		FileInputStream fis = new FileInputStream("D:/DxOffice/FileTest/a.txt");
    		FileOutputStream fos = new FileOutputStream("D:/DxOffice/FileTest/b.txt");
    		//用转换流把字节的输入,输出流包装
    		InputStreamReader isr = new InputStreamReader(fis,"GBK");
    		OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
    		//然后再把转换流用缓冲流包装
    		BufferedReader br = new BufferedReader(isr);
    		BufferedWriter bw = new BufferedWriter(osw);
    		//读取写入
    		String str = null;
    		while((str = br.readLine()) != null) {
    			bw.write(str);
    			bw.newLine();
    			bw.flush();
    		}
    		//关闭流
    		bw.close();
    		br.close();
    	}
    
  • 拓展

    image-20200730091153435

2.4.3、处理流之三:对象流
  • ObjectInputStream和OjbectOutputSteam

  • 对象流的作用

    • 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可

      以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

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

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

    • ObjectOutputStream和ObjectInputStream不能序列化static和transient修

      饰的成员变量

  • 对象的序列化 和 反序列化

    序列化 分为 局部序列化 和 全部序列化 所实现的接口不同

    • 全部序列化 和反序列化

      • 所实现的接口:Serializable ,还得需要获取一个版本号,==private static final long serialVersionUID;==不需要重写方法

      • 注意点

        • 若某个类实现了 Serializable 接口,该类的对象就是可序列化的:

          1. 创建一个 ObjectOutputStream
          2. 调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象
          3. 注意写出一次,操作flush()一次
        • **强调:**如果某个类的属性不是基本数据类型或 String 类型,而是另一个

          引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的

          Field 的类也不能序列化

      • 代码实现:

        public class ObjectStream implements Serializable {
        
        	/**
        	 * 版本号
        	 */
        	private static final long serialVersionUID = 1L;
        
        	private int id;
        	private String name;
        
        	public ObjectStream() {
        
        	}
        
        	public ObjectStream(int id, String name) {
        		this.id = id;
        		this.name = name;
        	}
        
        	@Override
        	public String toString() {
        		return "ObjectStream [id=" + id + ", name=" + name + "]";
        	}
        	public static void main(String[] args) throws IOException, ClassNotFoundException {
        		//序列化
        		ObjectStream os = new ObjectStream(001,"张三");
        		System.out.println(os);
        		FileOutputStream fo = new FileOutputStream("D:/DxOffice/FileTest/a.txt",false);
        		ObjectOutputStream oos = new ObjectOutputStream(fo);
        		
        		oos.writeObject(os);
        		oos.flush();
        		oos.close();
                //反序列化
        		FileInputStream fi = new FileInputStream("D:/DxOffice/FileTest/a.txt");
        		@SuppressWarnings("resource")
        		ObjectInputStream oi = new ObjectInputStream(fi);
        		
        		Object o = oi.readObject();
        		if(o instanceof ObjectStream) {
        			ObjectStream os1 = (ObjectStream) o;
        			System.out.println(os1);
        		}
            }
        }
        
    • 局部序列化 和 反序列化

      • 所实现的接口:Externalizabl ,不需要获取一个版本号,需要重写两个方法

        //注意下面的两个重写的方法
        	@Override
        	public void writeExternal(ObjectOutput out) throws IOException {
        		out.writeDouble(age);
        		out.writeChars(name);
        		//里边代码中定义的顺序不可改变
        	}
        
        	@Override
        	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        		age = in.readDouble();
        		name = in.readLine();
        		
        	}
        
      • 代码实现

        /**
         * 局部序列化
         * @author 聆听者
         *
         */
        public class ExterObject implements Externalizable{
        	private int id;
        	private double age;
        	private String name;
        	
        	public ExterObject() {
        		
        	}
        	public ExterObject(int id,double age,String name) {
        		this.id = id;
        		this.age = age;
        		this.name = name;
        	}
        	
        	@Override
        	public String toString() {
        		return "ExterObject [id=" + id + ", age=" + age + ", name=" + name + "]";
        	}
        	//注意下面的两个重写的方法
        	@Override
        	public void writeExternal(ObjectOutput out) throws IOException {
        		out.writeDouble(age);
        		out.writeChars(name);
        		
        	}
        
        	@Override
        	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        		age = in.readDouble();
        		name = in.readLine();
        		
        	}
        	
        	public static void main(String[] args) throws IOException, ClassNotFoundException {
        		//序列化
        		ExterObject eo = new ExterObject(1, 20.0, "gjh");
        		System.out.println(eo);
        		File f1 = new File("D:\\DxOffice\\FileTest\\b.txt");
        		FileOutputStream fo = new FileOutputStream(f1);
        		ObjectOutputStream oos = new ObjectOutputStream(fo);
        		oos.writeObject(eo);
        		oos.flush();
        		oos.close();
        		//反序列化
        		FileInputStream fi = new FileInputStream(f1);
        		ObjectInputStream ois = new ObjectInputStream(fi);
        		Object o = ois.readObject();
        		if(o instanceof ExterObject) {
        			ExterObject eo1 = (ExterObject) o;
        			System.out.println(eo1);
        		}
        		ois.close();
        	}
        
        }
        
        
2.4.4、处理流之四:标准输入、输出流(了解)
2.4.5、处理流之五:打印流(了解)
2.4.6、处理流之五:数据流(了解)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值