IO流的学习笔记

目录

1.IO流分类

2.字节流

2.1 In/OutputStream

2.2TWR语法

2.3 BufferedIn/OutputStream

2.4 DataIn/OutputStream

2.5 ObjectIn/OutputStream

3.字符流

3.1Read/Writer

3.2FileReader/Writer

3.3 BufferedReader/Writer

3.4 PrintWriter(比BufferedWriter更好用)

4.网络下载 

4.1联网下载

4.2显示百分比进度


1.IO流分类

按照方向:输入流(比如你复制的那个文件) 输出流(比如你复制完的新文件)

按照单位:字节流(以字节为单位进行数据传输byte)       

字符流(以字符为单位进行数据传输char)

按照功能:节点流(相当于针头) 过滤流(相当于针管)

2.字节流

2.1 In/OutputStream

InputStream 输入流统一的父类,是抽象类

三种方法

        int read()
        int read(byte[] data)   最常用(里面参数后面解释)
        int read(byte[] data,int off,int len)

OutputStream 输出流统一的父类,是抽象类

对应的也是三种方法

        write(int data)
        write(byte[] data)    
        write(byte[] data,int off,int len)这个最常用

=========================================================================

FileInputStream 读取文件的,是节点流(打针的针头,它得插文件里,不能插目录里(会报异常))

FileOutputStream 输出文件的,也是节点流(打针的针头,它得插文件里,不能插目录里(会报异常))

*: FileInputStream 最常用的是read(byte[] data)参数代表一次传输的数据大小,默认(啥都不写)一个字节(慢的感人)

FileInputStream 以-1作为读取结束的标识

import java.io.*;
public class TestFileInputStream{
	public static void main(String[] args)throws Exception{
		FileInputStream fis = new FileInputStream("abc.txt");
		int data = 0;
		while((data = fis.read())!=-1//等于-1时结束读取){
			System.out.print((char)data);
		}
		fis.close();
	}
}
//abc.txt里是helloworld
//不推荐使用这种方法,更推荐
/*public static void main(String[] args)throws Exception{
		FileInputStream fis = new FileInputStream("abc.txt");
		int len;
		byte[] data = new byte[3];//byte数组大小代表一次运输的数据量大小
		while((len = fis.read(data))!=-1){
			for(int i = 0;i<len;i++){
				System.out.print((char)data[i]);
			}
		}
        fis.close();//用完要及时关闭流
    }
*/

*: FileOutputStream 最常用的却是write(byte[],int,int)

将指定字节数组byte中从偏移量(第一个int)开始的(第二个int)个字节写入此文件输出流

这种方法(节点输出流的)很危险,当你连接的文件不存在时它会自动帮你创建那个文件。

但是,当你连接一个已经存在的文件,它会在创建流的一瞬间新建一个空白文件替换那个文件,因此使用前需要注意。

如果你需要的是在原本的文件后要继续追加其它内容(比如在一个txt文件a里想让它后面加上txt文件b的内容),可以在构造方法中指定追加模式开启

FileOutputStream fos = new FileOutputStream("a.txt",true)

=========================================================================

2.2TWR语法

正常情况下所有新建流的语句都需要加上trycatch来处理异常。因此就会

import java.io.*;
public class TestFileCopyWithTryCatch{
	public static void main(String[] args){
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try{
			fis = new FileInputStream("1.mp3");
			fos = new FileOutputStream("3.mp3");
			byte[] data = new byte[5<<20];//5*1024*1024
			int len;
			while((len = fis.read(data))!=-1){
				fos.write(data,0,len);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try{
				fis.close();//要确保fis.close()一定能实现,因此放在finally里
			}catch(Exception e){
				e.printStackTrace();
			}finally{
				try{
					fos.close();//不放上面那个try里是防止上面那个关闭失败导致fos也关闭失败
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
	}
}

长的感人。。

因此,JDK7.0后推出了一个新的语法TWR:try - with - resources --->带有资源控制的trycatch

于是,代码变成了

import java.io.*;
public class TestFileCopyWithTryCatch{
	public static void main(String[] args){
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try(fis = new FileInputStream("1.mp3");//给流赋值的语句放到try()中,{}里写方法主体
			fos = new FileOutputStream("3.mp3");//最后的;可写可不写)
            {
			byte[] data = new byte[5<<20];//5*1024*1024
			int len;
			while((len = fis.read(data))!=-1){
				fos.write(data,0,len);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

它会自动帮你关闭流,不需要你操心,就很棒棒


2.3 BufferedIn/OutputStream

BufferedInputSteam        和上面(FileInputStream)基本一样但它不是针头而是管道(过滤流)。

BufferedOutputStream        和上面(FileOutStream)基本一样但它不是针头而是管道(过滤流)。

        1.作为过滤流的它们 是为了给原本的节点流添加缓冲空间,从而提高每次读写的吞吐量,进而提高效率(就和StringBuffer一样)

        2.它们不能直接连接文件,而是要连接其它流(节点流)       

        3.它们构造方法第二个参数 都允许指定缓冲空间的大小 默认8192个字节 就是8k

        4.BufferedInputStream 最常用的方法是read()

        5.             Output           最常用的方法是write(int data)  因为缓冲区大小在构造方法里设置

        6.BufferedInputStream 同样以-1作为读取结束的标识

        7.BufferedOutputStream 是带缓冲的输出流
                使用带缓冲的输出流 务必注意及时清空缓冲
                以防止数据滞留缓冲空间 导致丢失

                缓冲区什么条件下会清空:
                    1.满了自动清空 不需要操作
                    2.关闭流的操作会触发清空缓冲
                    3.主动清空缓冲 flush();

        8.文件复制后变小了是因为什么,文件复制后变大了是因为什么
                    变小了:使用了带缓冲区的输出流 但是没有及时清空缓冲
                                   所以数据滞留缓冲空间导致丢失...
                    变大了:使用了只传数组的write(byte[] data) 写出了多余的冗余数据 

import java.io.*;
public class TestBufferedStream{
	public static void main(String[] args)throws Exception{
		FileInputStream fis = new FileInputStream("1.mp3");//针头
		BufferedInputStream bis = new BufferedInputStream(fis,5<<20);//针管(针头)

		FileOutputStream fos = new FileOutputStream("3.mp3");//针头
		BufferedOutputStream bos = new BufferedOutputStream(fos,5<<20);

		int data;
		while((data = bis.read())!=-1){
			bos.write(data);

		}
		bis.close();
		//bos.flush();不需要手动flush刷新,因为.close()会自动刷新
		bos.close();
	}
}

2.4 DataIn/OutputStream

DataInputStream        输入流 字节流 过滤流
DataOutputStream     输出流 字节流 过滤流

        作用:作为过滤流的它们 是为了给原本节点流添加读写基本数据类型的功能的

        它们不能直接连接文件,而是要连接其它流(节点流)     

        DataInputStream 核心方法 readXxxx();        有返回值
        DataOutputStream 核心方法 writeXxxx();     要参数

        在判断结束上: 

        DataInputStream 不能再以-1作为读取结束的标识了
        而是一旦到达文件结尾 还继续尝试读取
        将会直接触发EOFException => End Of File

        因此trycatch手动修改报错就行

        或者使用集合,数组等将对象存起来,当read时一个一个的从集合或数组里取出来就行了

        

import java.io.*;
public class TestDataStream{
	public static void main(String[] args)throws Exception{
		/*
		int level = 835;
		FileOutputStream fos = new FileOutputStream("save.data");
		DataOutputStream dos = new DataOutputStream(fos);
		dos.writeInt(level);//注意核心方法
		dos.close();
		*/
		FileInputStream fis = new FileInputStream("save.data");
		DataInputStream dis = new DataInputStream(fis);
		int data = dis.readInt();//注意核心方法
		dis.close();
		System.out.println(data);
	}
}


2.5 ObjectIn/OutputStream

有了基本数据类型,那么引用数据类型也是有输入输出流方法的。

ObjectInputStream         输入流 字节流 过滤流

ObjectOutputStream      输出流 字节流 过滤流

        1.作为过滤流的它们 是为了给原本的节点流添加读写对象的功能的

        2.作为过滤流的它们 不能直接连接文件 只能连接其它的流!

        3.ObjectInputStream 提供的核心方法 名叫readObject()

        4.ObjectOutputStream 提供的核心方法 writeObject() 

        5.ObjectInputStream 同样不能以-1作为读取结束的标识

                因为Integer  Byte Short 都有可能读取到-1

                所以它同样是到达文件结尾 再继续读取 

                就直接触发EOFException...

        6.想要持久化 首先需要序列化  implements Serializable

        想要持久化的对象的类型必须要实现序列化接口

                而如果其中还有其它引用类型的属性,就连属性的类型也必须要实现序列化接口

                如果某些属性无关紧要 不需要参与持久化,可以使用transient修饰             

                transient => 短暂的 => 不参与持久化的

         如果要持久化的是一个集合对象,则必须保证集合当中的元素类型必须实现过序列化接口 

         如果要持久化的是一个使用了比较器的TreeSet或者TreeMap

                 就连比较器的类也要实现序列化接口,因为比较器是它们的一个属性

import java.io.*;
import java.util.*;
public class TestObjectStream{
	public static void main(String[] args)throws Exception{
		/*
		Date today = new Date();
		FileOutputStream fos = new FileOutputStream("月光宝盒.data");
		ObjectOutputStream dos = new ObjectOutputStream(fos);
		dos.writeObject(today);
		dos.close();
		*/
		FileInputStream fis = new FileInputStream("月光宝盒.data");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Object obj = ois.readObject();
		ois.close();
		Date theDate = (Date)obj;
		System.out.println(theDate);
	}
}
import java.io.*;
public class TestObjectStream2{
	public static void main(String[] args)throws Exception{

		/*Elephent el = new Elephent("大象");
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("电冰箱.data"));
		oos.writeObject(el);
		oos.close();
*/

		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("电冰箱.data"));
		Object obj = ois.readObject();
		ois.close();
		Elephent ele = Elephent(obj);
		System.out.println(ele.name);
        //没有pc那个属性
	}
}
class Computer{
	String logo;
	public Computer(String logo){
		this.logo = logo;
	}
}
class Elephent implements Serializable{
	String name;
	//transient = 短暂的 转瞬即逝的 = 不参与持久化的~
	transient Computer pc;
	public Elephent(String name){
		this.name = name;
		pc = new Computer("Lenovo");
	}

}

3.字符流

3.1Read/Writer

Reader        所有字符输入流统一的父类 抽象类

        int read() 

        int read(char[] data)

        int read(char[] data,int off,int len)

Writer        所有字符输出流统一的父类 抽象类

        write(int data)

        write(char[] data)

        write(char[] data,int off,int len)

3.2FileReader/Writer

FileReader        输入流 字符流 节点流

FileWriter          输出流 字符流 节点流

        它们都是节点流,构造方法允许传入String路径/File对象

        它们都只能连接文件,不能连接文件夹,否则会抛出异常

        FileReader 最常用read(char[] data)

        FileWriter   最常用write(char[],int,int)

        FileWriter   的其它同FileOutputStream一样(危险性,追加模式)

FileReader 也是以-1为结束标识

用完后要第一时间关闭流,解除文件占用状态

同样可以使用TWR语法来处理异常(JDK7.0)

import java.io.*;
public class TestFileReader{
	public static void main(String[] args)throws Exception{
		FileReader fis = new FileReader("abc.txt");
		int data;
		while((data = fis.read())!=-1){
			System.out.print((char)data);
		}
		fis.close();
	}
}

3.3 BufferedReader/Writer

BufferedReader        字符流 输入流 过滤流
BufferedWriter          字符流 输出流 过滤流

        1.作为过滤流的它们 是为了给原本的节点流添加变长的缓冲空间,从而实现以一行为单位

读写

        2.它们都是过滤流 只能连接其它的流 不能直接连接文件

        3.BufferedReader 核心方法 String readLine() 

        4.BufferedReader 不以-1作为读取结束的标识 而是null

        5.BufferedWriter 核心方法 write(String) + newLine()

import java.io.*;
public class TestBufferedReader{
	public static void main(String[] args)throws Exception{
		BufferedReader br = new BufferedReader(new FileReader("focus.txt"));
		String str;
		while((str = br.readLine())!=null){
			if(str.contains("流")){
				System.out.println(str);
			}
		}
		br.close();
	}
}
import java.io.*;
public class TestBufferedWriter{
	public static void main(String[] args)throws Exception{
		BufferedWriter bw = new BufferedWriter(new FileWriter("鹅鹅鹅.txt"));
		bw.write("鹅鹅鹅");
		bw.newLine();//换行
		bw.write("曲项向天歌");
		bw.newLine();//换行
		bw.write("白毛浮绿水");
		bw.newLine();//换行
		bw.write("鹅掌拨清波");
		//bw.flush();close自动调flush
		bw.close();
	}
}

3.4 PrintWriter(比BufferedWriter更好用)

1. 它既可以当做节点流 又可以当做过滤流

        构造方法允许传入 输出流 或者 文件对象 或者 文件路径

2. 它既可以连接字节流 又可以连接字符流

        构造方法允许传入 OutputStream / Writer

3. 当做节点流使用的时候 其构造方法第二个参数

        可以指定字符编码..

        new PrintWriter("abc.txt","utf-8");

4. 当做过滤流使用的时候 其构造方法第二个参数

        可以指定自动清空缓冲~

        new PrintWriter(new FileWriter("abc.txt",true),true);

        这行代码当中两个true 分别代表 appendMode    / autoFlush

5. println() = write() + newLine()

6. 你对它的孪生兄弟太熟悉了 

        System.out.println();    out是PrintStream

        综上所述 以行为单位的写出文本文件 

        我们根本不会选择 BufferedWriter 而会选择 PrintWriter

import java.io.*;
public class TestPrintWriter{
	public static void main(String[] args)throws Exception{
		PrintWriter pw = new PrintWriter("春晓.txt");
		pw.println("春眠不觉晓");
		pw.println("处处闻啼鸟");
		pw.println("夜来风雨声");
		pw.print("花落知多少");
		pw.close();
	}
}

3.5 InputStreamReader/OutputStreamWriter

InputStreamReader    

OutputStreamWriter

*: 字节流 通向字符流的桥梁 字节流转换成字符流的工具
 

import java.io.*;
public class TestUTF8{
	public static void main(String[] args)throws Exception{
		/*
		PrintWriter pw = new PrintWriter("测试.txt","utf8");
		pw.println("醉里挑灯看剑");
		pw.println("梦回吹角连营");
		pw.close();
		*/
		//FileReader fr = new FileReader("测试.txt");
		FileInputStream fis = new FileInputStream("测试.txt");
		//桥转换器 => 字节流通向字符流的桥梁 字节流转换成字符流的工具
		InputStreamReader r = new InputStreamReader(fis,"utf8");//可以指定编码格式
		BufferedReader br = new BufferedReader(r);
		String str;
		while((str = br.readLine())!=null){
			System.out.println(str);
		}
		br.close();
	}
}

4.网络下载 

4.1联网下载

import java.net.*;
import java.io.*;
//URL => Uniform Resources Locator => 统一资源定位符 => 网址
public class TestURL{
	public static void main(String[] args)throws Exception{
		URL url = new URL("https://tu.duoduocdn.com/uploads/day_190323/5c954198cc3a5.jpg");
		URLConnection uc = url.openConnection();
		InputStream is = uc.getInputStream();

		FileOutputStream fos = new FileOutputStream("Maldini.jpg");
		byte[] data = new byte[65536];
		int len;
		while((len = is.read(data))!=-1){
			fos.write(data,0,len);
		}
		fos.close();
		is.close();
	}
}

4.2显示百分比进度

import java.net.*;
import java.io.*;
//URL => Uniform Resources Locator => 统一资源定位符 => 网址
public class TestURLPlus{
	public static void main(String[] args)throws Exception{
		URL url = new URL("https://mp4.vjshi.com/2022-02-24/5dbea0cbffba416c93a532c16b01d8a9.mp4");
		URLConnection uc = url.openConnection();
		InputStream is = uc.getInputStream();

		int total = uc.getContentLength();//文件总共大小

		FileOutputStream fos = new FileOutputStream("test.mp4");
		byte[] data = new byte[1<<20];
		int len;
		int current = 0;
		int lastPercent = -1;//之前显示的%
		while((len = is.read(data))!=-1){
			fos.write(data,0,len);
			current += len;
			int percent = (int)(current * 100L / total);
			if(lastPercent != percent){
				System.out.print("\r已经完成:"+percent+"%");
				lastPercent = percent;
			}
		}
		fos.close();
		is.close();
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值