---------------------- 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培训、期待与您交流! ----------------------