黑马程序员 IO流 二

本文深入探讨了Java中的IO流,特别是字节流的分类,包括InputStream的基本使用。同时,详细介绍了Properties类,阐述了其作为Map集合的特性,如键值对均为String类型,并讲解了如何利用Properties与IO流结合进行数据的保存和加载。通过案例展示了如何查找并修改文件中特定键的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

IO流    二

1:IO流
(1)分类
字节流:
输入流:
InputStream

public int read()
从输入流中读取数据的下一个字节。
public int read(byte[] b)
 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
FileInputStream
BufferedInputStream
输出流:
OutputStream
public void write(int b)
将一个 integer(数组长度)写入此流。
public void write(byte[] b,int off,int len)
 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
FileOutputStream
BufferedOutputStream


字符流:
输入流:
Reader
public int read()
读取单个字符。
public int read(char[] cbuf)
将字符读入数组。
FileReader
BufferedReader
String readLine()
输出流:
Writer
public void write(int c)
写入单个字符。
public abstract void write(char[] cbuf,int off,int len)
写入字符数组的某一部分。
FileWriter
BufferedWriter
write(String line)
void newLine()
(2)到底使用谁?
用记事本打开能读懂的,就用字符流。
否则,用字节流。
如果你根本就不知道,用字节流。
(3)复制文本文件:
9种方式:
字节流:
4种
基本流一次读写一个字节
基本流一次读写一个字节数组
高效流一次读写一个字节
高效流一次读写一个字节数组
字符流:
5种
基本流一次读写一个字符
基本流一次读写一个字符数组
高效流一次读写一个字符
高效流一次读写一个字符数组
高效流一次读写一个字符串


一般来说,明明知道是文本文件,那么,肯定不用字节流。
那么,如果是使用字符流,有5种方式,选择哪一种呢?
一般都选择高效流读写一个字符串的方式。




代码体现:
数据源:c:\\a.txt
目的地:d:\\b.txt


			//封装数据源,封装目的地
			BufferedReader br = new BufferedReader(new FileReader("c:\\a.txt"));
			BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\b.txt"));
			
			//读入数据并写入到指定文件中
			String line = null;
			while((line=br.readLine())!=null)
			{
				bw.write(line);
				bw.newLine();
				bw.flush();
			}


			//释放资源
			bw.close();
			br.close();




(4)复制二进制流数据:(图片,视频,音频等)
字节流:
4种
基本流一次读写一个字节
基本流一次读写一个字节数组
高效流一次读写一个字节
高效流一次读写一个字节数组


一般来说,我们选择使用高效流一次读写一个字节数组


代码体现:
数据源:c:\\a.jpg
目的地:d:\\b.jpg

			//封装数据源,目的地
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\a.jpg"));
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\b.jpg"));


			//读入数据并写入到指定文件中
			byte[] bys = new byte[1025];
			int len = 0;
			while((len=bis.read(bys))!=-1)
			{
				bos.write(bys,0,len);
			}


			//释放资源
			bos.close();
			bis.close();
2:转换流
(1)如果有字节流对象,为了使用字符流的功能,就必须使用转换流进行操作。
(2)案例:

键盘录入数据

/*
 * 数据源:
 * 		键盘录入	--	System.in	--	InputStream
 * 目的地:
 * 		文本文件	--	BufferedWriter
 * 
 * 转换流:InputStreamReader 是字节流通向字符流的桥梁
 */
public class SystemInDemo {
	public static void main(String[] args) throws IOException {
		// 封装数据源
		InputStream is = System.in;
		/*
		 * 这个时候,我们拥有的是标准键盘录入。
		 * 而字节的输入流有两种读取方式:
		 * 方式1:一次读取一个字节,但是,这样的话,我们每次都需要对读取到的数据进行保存,将来判断是否一行结束,麻烦。
		 * 方式2:一次读取一个字节数组,但是,这个时候,最大的问题是,数组的长度定义为多大不好确定。
		 * 所以,我们觉得这两种方式都不够好。
		 * 我们就想有没有这样的一种方案,直接一次读取一行数据。
		 * 我们就想到了字符缓冲输入流的:readLine()方法。
		 * 我们就按照默认的写法去做了这件事情,但是,发现报错了。
		 * 因为BufferedReader需要的是一个字符流,而你现在有的确实一个字节流。
		 * 假如能有一个流对象能够实现字节流转成字符流,我们就可以用了。
		 * 转换流:InputStreamReader
		 */
		//InputStreamReader(InputStream in) 
		InputStreamReader isr = new InputStreamReader(is);
		BufferedReader br = new BufferedReader(isr);

		// 封装目的地
		BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
		
		String line = null;
		while((line=br.readLine())!=null){
			//只要是键盘录入,就的自己定义结束条件
			if("over".equals(line)){
				break;
			}
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		
		bw.close();
		br.close();
	}
}

把文本文件的数据通过流对象在控制台显示

/*
 * 需求:把文本文件的数据通过标准输出流的方式显示在控制台。
 * 
 * 数据源:	
 * 		文本文件	--	BufferedReader
 * 目的地:
 * 		控制台显示 -- System.out -- PrintStream -- OutputStream
 * 
 * OutputStreamWriter 是字符流通向字节流的桥梁
 */
public class SystemOutDemo {
	public static void main(String[] args) throws IOException {
		// 封装数据源
		BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
		// 封装目的地
		OutputStream os = System.out;
		/*
		 * 这个时候,往控制台写数据的时候,我们又的方式一次写一个字节,或者一次写一个字节数组。
		 * 但是,我们获取到的确实一个字符串数据。
		 * 所以,我们就想能不能直接写一个字符串在控制台呢?
		 * A:把字符串转换字节数组输出,但是,不满足我的要求。
		 * B:使用字符缓冲流写出一个字符串。
		 */
		//能实现,但是不满足我的要求
//		String line = null;
//		while((line=br.readLine())!=null){
//			os.write(line.concat("\r\n").getBytes());
//		}
		
		OutputStreamWriter osw = new OutputStreamWriter(os);
		BufferedWriter bw  = new BufferedWriter(osw);
		
		String line = null;
		while((line=br.readLine())!=null){
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		
		bw.close();
		br.close();
	}
}

3:打印流
(1)打印流是写数据的。
(2)特点:
A:可以写任意数据类型的数据
B:如果启动了自动刷新,能自动刷新,还会换行。println()
C:可以直接往文件写数据
注意:哪些流对象可以直接读写文件?
看构造方法,如果同时有String和File的构造参数,那么该流对象就可以读写文件。
(3)用打印流改进复制文本文件的操作
数据源:
c:\\a.txt
目的地:
d:\\b.txt

/*
 * 复制文本文件:
 * 数据源:
 * 		c:\\a.txt	--	BufferedReader
 * 目的地:
 * 		d:\\b.txt	--	PrintWriter改写
 * 
 * 注意:
 * 		A:读取文件的时候,如果是文件夹,会出现:FileNotFoundException: test (拒绝访问。)
 * 		B:写文件的时候,如果没有后缀名,它也会自动生成一个文件,而这个种类型的文件通过记事本类型的软件是可以打开的。
 */
public class PrintWriterTest {
	public static void main(String[] args) throws IOException {
		// 封装数据源
		BufferedReader br = new BufferedReader(new FileReader(
				"c:\\a.txt"));
		// 封装目的地
		PrintWriter pw = new PrintWriter(new FileWriter("d:\\b.txt"), true);
		
		String line = null;
		while((line=br.readLine())!=null){
			pw.println(line);
		}
		
		pw.close();
		br.close();
	}
}

4:序列化流
(1)序列化:把对象按照流一样的方式在网络中传输,或者存储到文本文件
  反序列化:把流数据还原成对象
(2)如何实现序列化?
A:被序列化的对象所属的类必须实现序列化接口Serializable
B:用序列化流对象进行操作
(3)序列化(对象)流对象
ObjectInputStream:
Object readObject()
ObjectOutputStream:
void writeObject(Object obj)
(4)掌握:
A:看到类实现了序列化接口,就知道该类可以被序列化流对象操作
B:看到类实现了序列化接口,知道点击鼠标就可以解决黄色警告问题

5:Properties
(1)是Map体系一个集合类。
(2)特点:
A:可以把集合中的数据保存到文本文件,也可以把文本文件的数据加载到集合中。
B:该集合的键和值都是String类型
(3)特殊功能:
A:setProperty(String key,String value)
修改这个键所对应的值,假如没有则添加键值。
B:getProperty(String key)
根据指定键返回对应值,如果没有返回null
getProperty(String key,String defaultValue)
根据指定键返回对应值,如果没有返回defaultValue
C:Set<String> stringPropertyNames()
返回此列表的键集
(4)和IO流结合的方法:
A:list 通过打印流把数据保存到文件中
B:load 通过任意流把文本中的数据加载到集合中
C:store 通过任意流把数据保存到文件中
(5)案例:
查找文件中是否有键为lisi的,如果有,则修改其值为50

/*
 * 需求:请查找文件user.txt中是否有lisi这个键,如果有,则修改其值为50
 * 
 * 思路:
 * 		A:把文本文件的数据加载到集合中
 * 		B:遍历集合,获取到每一个键
 * 		C:判断该键是否是lisi,如果是则修改值
 * 		D:把集合中的数据重新保存到文本文件中
 */
public class PropertiesTest {
	public static void main(String[] args) throws IOException {
		// method1();
		method2();
	}

	private static void method2() throws IOException {
		Properties prop = new Properties();

		// 把文本文件的数据加载到集合中
		FileReader reader = new FileReader("user.txt");
		prop.load(reader);
		reader.close();

		if (prop.containsKey("lisi")) {
			prop.setProperty("lisi", "50");
		}

		// 把集合中的数据重新保存到文本文件中
		FileWriter out = new FileWriter("user.txt");
		prop.store(out, null);
		out.close();
	}

	private static void method1() throws IOException {
		Properties prop = new Properties();

		// 把文本文件的数据加载到集合中
		FileReader reader = new FileReader("user.txt");
		prop.load(reader);
		reader.close();

		// 遍历集合,获取到每一个键
		Set<String> set = prop.stringPropertyNames();
		for (String key : set) {
			if ("lisi".equals(key)) {
				prop.setProperty(key, "50");
				break;
			}
		}

		// 把集合中的数据重新保存到文本文件中
		FileWriter out = new FileWriter("user.txt");
		prop.store(out, null);
		out.close();
	}
}

6:字符编码
(1)编码表:
就是字符和对应的数据组成的一张表。
(2)常见的编码表:
ASCII
ISO-8859-1
GBK
GB2310
GB18030
UTF-8
BIG5
(3)转换流中的编码问题
A:字符流 = 字节流+编码表
B:通过转换流写入数据,指定为UTF-8编码,并通过UTF-8编码读取。

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值