字符流
使用字节输入流去读包含中文的文件
/*
使用字节输入流读取含有中文的文件
文件的编码GBK:一个中文占用2个字节
文件的编码UTF-8:一个中文占用3个字节
*/
public class Demo01FileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("day15\\c.txt");//你好
int len = 0;
while ((len = fis.read())!=-1){
System.out.print((char)len);//ä½ å¥½ 一次读取一个字节(1/3个中文),把中文的1/3转换为字符,乱码
}
fis.close();
}
}
字符输入流
java.io.Reader:字符输入流
用于读取字符流的抽象类。
是所有字符输入流最顶层的父类,里边定义了所有字符输入流共性的成员方法,所有的字符输入流都可以使用
共性的成员方法:
- public void close() :关闭此流并释放与此流相关联的任何系统资源。
- public int read(): 从输入流读取一个字符。
- public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
java.io.FileReader:文件字符输入流 extends InputStreamReader(转换流) extends Reader
作用:
把文件以字符的方式读取到内存中
构造方法:
FileReader(File file)
FileReader(String fileName)
参数:传递要读取的数据源
File file:数据源是一个文件
String fileName:数据源是一个文件路径
/*
使用字符输入流读取文件的步骤(重点):
1.创建FileReader对象,构造方法中绑定要读取的数据源
2.使用FileReader对象中的方法read,以字符的方式读取文件
3.释放资源
String类的构造方法:
String(char[] value) 把字符数组转换为字符串
String(char[] value, int offset, int count) 把字符数组的一部分转换为字符串
int offset:数组的开始索引
int count:转换个数
*/
public class Demo02Reader {
public static void main(String[] args) throws IOException {
//1.创建FileReader对象,构造方法中绑定要读取的数据源
FileReader fr = new FileReader("day15\\c.txt");
//2.使用FileReader对象中的方法read,以字符的方式读取文件
//public int read() 一次读取一个字符并返回
/*int len = 0;
while ((len = fr.read())!=-1){
System.out.print((char)len);
}*/
//public int read(char[] cbuf)使用字符数组缓冲一次读取多个字符
char[] chars = new char[1024];
int len = 0;
while ((len =fr.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
//3.释放资源
fr.close();
}
}
字符输出流
java.io.Writer:字符输出流
写入字符流的抽象类。
是所有字符输出流最顶层的父类,里边定义字符输出流共性的成员方法,所有的字符输出流都可以使用
共性的成员方法:
- public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
- public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。
- public void write(int c) :写出一个字符。
- public void write(char[] cbuf):将cbuf.length字符从指定的字符数组写出此输出流。
- public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
- public void write(String str) :写出一个字符串。
- void write(String str, int off, int len) 写入字符串的某一部分。
java.io.FileWriter:文件字符输出流 extends OutputStreamWriter(转换流) extends Writer
作用: 把内存中的字符,写入到文件中
构造方法:
FileWriter(File file)
FileWriter(String fileName)
参数:写入数据的目的地
File file:目的地是一个文件
String fileName:目的地是一个文件路径
构造方法的作用:
1.创建FileWriter对象
2.会根据构造方法中传递的文件|文件的路径,创建一个新的空白的文件
3.会把FileWriter对象,指向空白的文件
/*
使用字符输出流基本步骤(重点):
1.创建FileWriter对象,构造方法中绑定写入数据的目的地
2.使用FileWriter对象中的方法write,把数据写入到内存缓冲区中(字符-->字节)
3.使用FileWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中
4.释放资源(会先调用flush方法,把内存缓冲区中的数据刷新到文件中)
*/
public class Demo01Writer {
public static void main(String[] args) throws IOException {
//1.创建FileWriter对象,构造方法中绑定写入数据的目的地
FileWriter fw = new FileWriter("day15\\d.txt");
//2.使用FileWriter对象中的方法write,把数据写入到内存缓冲区中(字符-->字节)
//- public void write(int c) :写出一个字符。
fw.write(100);
//3.使用FileWriter对象中的方法flush,把内存缓冲区中的数据刷新到文件中
//fw.flush();
//4.释放资源(会先调用flush方法,把内存缓冲区中的数据刷新到文件中)
fw.close();
}
}
关闭和刷新的区别
/*
关闭和刷新的区别
- flush :刷新缓冲区,把内存缓冲区中的数据刷新到文件中,刷新完后,流对象可以继续使用。
- close :关闭流,释放系统资源。关闭前会刷新缓冲区。把内存缓冲区中的数据刷新到文件中,流关闭之后就不能在使用了
问题:
1.程序执行完毕e.txt中有什么? ABC
2.程序的执行会抛出异常吗? 会
*/
public class Demo02Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("day15\\e.txt");
fw.write(65);//A
fw.write(66);//B
fw.flush();//把内存缓冲区中的数据刷新到文件中,刷新完后,流对象可以继续使用
fw.write(67);//C
fw.close();//把内存缓冲区中的数据刷新到文件中,流关闭之后就不能在使用了
fw.write(68);//D 抛出异常 IOException: Stream closed
}
}
字符输出流写数据的其他方法
/*
字符输出流写数据的其他方法:
- public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。
- public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。
- public void write(String str) :写出一个字符串。
- void write(String str, int off, int len) 写入字符串的某一部分。
*/
public class Demo03Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("day15\\f.txt");
//- public void write(char[] cbuf) 写字符数组中的多个字符
char[] chars = {'a','b','c','1','2','3','中','国'};
fw.write(chars);//abc123中国
/*
- public abstract void write(char[] b, int off, int len) 写字符数组的一部分
int off:数组的开始索引
int len:写的个数
*/
fw.write(chars,6,2);//中国
//- public void write(String str) :写出一个字符串。
fw.write("我是一个中国人,我骄傲!");
//- void write(String str, int off, int len) 写入字符串的某一部分。
fw.write("我是一个中国人,我骄傲!",0,7);
fw.close();
}
}
字符输出流的续写和换行
/*
字符输出流的续写和换行
1.续写(追加写):使用两个参数的构造方法
FileWriter(File file, boolean append)
FileWriter(String fileName, boolean append)
参数:
File file,String fileName:写入数据的目的地
boolean append:续写开关
true:可以续写,使用构造方法创建对象,不会覆盖之前的文件,会往文件的末尾继续写数据
false:不可以续写,使用构造方法创建对象,会创建一个新的空白文件,覆盖之前的文件,在新的文件中写数据
2.换行:使用换行符号
windows:\r\n
linux: /n
mac: /r 从Mac OS X开始与linux统一
*/
public class Demo04Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("day15\\g.txt",true);
for (int i = 1; i <= 10; i++) {
fw.write("hello"+i+"\r\n");
}
fw.close();
}
}
IO资源的处理
jdk7前异常处理
/*
JDK7前异常处理:使用try...catch...finally处理异常
格式:
try{
可能产生异常的代码
}catch(定义一个异常变量,接收异常对象){
异常的处理逻辑
}finally{
一定会执行的代码,一般用于资源释放
}
添加语句的快捷键: ctrl+alt+t
*/
public class Demo01JDK7Before {
public static void main(String[] args) {
/*
把fis.close();放在finally中:无论是否有异常,都 释放资源
Cannot resolve symbol 'fis':提高变量的作用域
Variable 'fis' might not have been initialized:变量fis没有一个初始化的值
*/
FileInputStream fis= null;
try {
//使用FileInputStream读取文件
fis = new FileInputStream("day15\\1.txt");
int len = 0;
while ((len = fis.read())!=-1){
System.out.println((char)len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//增加一个非空判断,防止空指针异常,流对象的值是null,就不需要关闭
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
JDK7后异常处理(重点)
/*
JDK7后异常处理:使用try...catch处理异常
格式:
try(
//定义流对象,只能定义流对象
AAA aaa = new AAA(读);
BBB bbb = new BBB(写);
){
//可能产生异常的代码
aaa.read();
bbb.write();
}catch(定会一个异常变量,接收异常对象){
异常的处理逻辑
}
在try的后边增加一个(),在()中定义了流对象
那么这些流对象的作用域,就在try中有效,执行完try中的代码,会自动帮助我们把流对象释放
省略了finally
*/
public class Demo02JDK7After {
public static void main(String[] args) {
try(
FileInputStream fis = new FileInputStream("day15\\a.txt");
FileOutputStream fos = new FileOutputStream("day15\\copya.txt");
){
//一读一写复制文件
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
Properties集合(重点)
Properties集合的基本使用
/*
java.util.Properties集合 extends Hashtable<k,v>集合
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。
Properties集合是一个唯一和IO流相结合的集合
我们可以使用Properties集合中的方法store,把集合中的临时数据,持久化到硬盘中存储(内存-->硬盘)
我们可以使用Properties集合中的方法load,把硬盘中保存键值对的文件,读取到内存中使用(硬盘-->内存)
属性列表中每个键及其对应值都是一个字符串。
Properties集合是一个双列集合,可以不用写泛型,默认key和value都是String类型
*/
public class Demo01Properties {
public static void main(String[] args) {
show01();
}
/*
Properties集合的基本使用:使用Properties集合存储数据,遍历Properties集合
Properties集合健和值默认都是String类型,有一些和String相关的特有方法
Object setProperty(String key, String value) 往Properties集合中添加元素,相当于Map集合中的put方法
String getProperty(String key) 根据key获取value,相当于Map集合中的get(key)方法
Set<String> stringPropertyNames() 返回此属性列表中的键集,相当于Map集合中的keySet方法
*/
private static void show01() {
//创建Properties集合对象
Properties prop = new Properties();
//使用Properties集合中的方法setProperty往集合中添加键值对
prop.setProperty("迪丽热巴","168");
prop.setProperty("古力娜扎","165");
prop.setProperty("赵丽颖","160");
prop.setProperty("唐嫣","172");
//使用Properties集合中的方法stringPropertyNames,获取集合中所有的键,把键存储到一个Set集合中
Set<String> set = prop.stringPropertyNames();
//遍历Set集合,获取Properties集合中的每一个key
for (String key : set) {
//使用Properties集合中的方法getProperty,根据key获取value值
String value = prop.getProperty(key);
System.out.println(key+"\t"+value);
}
}
}
Properties集合中的store方法
/*
我们可以使用Properties集合中的方法store,把集合中的临时数据,持久化到硬盘中存储(内存-->硬盘)
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
方法的参数:
OutputStream out:字节输出流,不能写中文,可以传递OutputStream任意子类对象
Writer writer:字符输出流,可以写中文,可以传递Writer任意子类对象
String comments:注释,解释说明我们保持的文件是做什么的,一般都传递""
不能写中文,默认使用Unicode编码,会出现乱码
使用步骤:
1.创建Properties集合对象,往集合中添加数据
2.使用Properties集合中的方法store,把集合中的临时数据,持久化到硬盘中存储
*/
private static void show02() throws IOException {
//1.创建Properties集合对象,往集合中添加数据
Properties prop = new Properties();
prop.setProperty("迪丽热巴","168");
prop.setProperty("古力娜扎","165");
prop.setProperty("赵丽颖","160");
prop.setProperty("唐嫣","172");
//2.使用Properties集合中的方法store,把集合中的临时数据,持久化到硬盘中存储
/*FileOutputStream fos = new FileOutputStream("day15\\prop1.txt");
prop.store(fos,"save data");
fos.close();*/
prop.store(new FileOutputStream("day15\\prop1.txt"),"save data");
prop.store(new FileWriter("day15\\prop2.txt"),"save data");
//使用的存储键值对的文件,叫配置文件,结尾一般都使用properties
prop.store(new FileWriter("day15\\prop.properties"),"save data");
}
Properties集合中的load方法
/*
我们可以使用Properties集合中的方法load,把硬盘中保存键值对的文件,读取到内存中使用(硬盘-->内存)
void load(InputStream inStream) 字节输入流,不能读取含有中文的文件
void load(Reader reader) 字符输入流,可以读取含有中文的文件
使用步骤:
1.创建Properties集合对象
2.使用Properties集合对象中的方法load,把硬盘中保存键值对的文件,读取到内存中使用
3.遍历Properties集合
注意:
1.在Properties集合的配置文件中,可以使用#进行注释,被注释的键值对不会被读取
2.在Properties集合的配置文件中,健和值之间可以使用=,空格,冒号等一些符号作为键与值的分割符号
3.在Properties集合的配置文件中,健和值默认都是字符串类型,不需要添加引号,否则会画蛇添足
*/
private static void show03() throws IOException {
//1.创建Properties集合对象
Properties prop = new Properties();
//2.使用Properties集合对象中的方法load,把硬盘中保存键值对的文件,读取到内存中使用
//prop.load(new FileInputStream("day15\\prop.properties"));
prop.load(new FileReader("day15\\prop.properties"));
//3.遍历Properties集合
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key+"\t"+value);
}
}
ResourceBundle工具类(重点)
前面我们了解了Properties工具类,它能够读取资源文件,当资源文件是以.properties结尾的文件时,
我们可以使用JDK提供的另外一个工具类ResourceBundle来对文件进行读取,使得操作更加简单。
ResourceBundle类对象的创建
/*
java.util.ResourceBundle:工具类
作用:
可以简化使用Properties集合中load方法读取文件
ResourceBundle它是一个抽象类,无法直接创建对象,我们可以使用静态方法获取ResourceBundle的子类对象
static ResourceBundle getBundle(String baseName)
参数:
String baseName:传递以.properties文件的名称 prop.properties==>prop
注意:
.properties文件必须放在当前模块的src下边
*/
public class Demo01ResourceBundle {
public static void main(String[] args) {
//getBundle方法返回的是ResourceBundle的子类对象 ResourceBundle(父类) 变量 = PropertyResourceBundle(子类对象)
//多态
ResourceBundle prop = ResourceBundle.getBundle("prop");
System.out.println(prop);//java.util.PropertyResourceBundle@74a14482
}
}
ResourceBundle类中的getString方法
/*
ResourceBundle类中提供了一个方法getString,用于读取配置文件
String getString(String key) 根据key读取配置文件中的value值
注意:
使用ResourceBundle读取配置文件的时候,key不能是中文,不支持,会抛出异常
使用ResourceBundle读取配置文件的时候,value可以使用中文,但是读取出来会出现乱码
*/
public class Demo02ResourceBundle {
public static void main(String[] args) {
//获取ResourceBundle对象
ResourceBundle bundle = ResourceBundle.getBundle("prop");
//使用ResourceBundle对象中的方法getString,根据key获取value值
String v1 = bundle.getString("tangyan");
System.out.println("v1:"+v1);
System.out.println("----------------------------------");
ResourceBundle bundle2 = ResourceBundle.getBundle("data");
String username = bundle2.getString("username");
System.out.println(username);
String password = bundle2.getString("password");
System.out.println(password);
}
}
打印流
/*
java.io.PrintStream:字节打印流 extends OutputStream
特点:
1.PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintStream流中有两个特有的方法:print,println
2.与其他输出流不同,PrintStream 永远不会抛出 IOException,可能会抛出其他异常
3.PrintStream打印流,只负责打印(输出),不能读取
构造方法:
PrintStream(File file) 打印流的目的地是一个文件
PrintStream(OutputStream out)打印流的目的地是一个字节输出流
PrintStream(String fileName) 打印流的目的地是是一个文件的路径
成员方法:
1.继承自父类OutputStream的共性成员方法:write方法写数据,查看的时候,会查询编码表
- public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
- public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
- public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
- public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
- public abstract void write(int b) :将指定的字节输出流。
2.自己特有的方法:print,println写的数据,原样输出
void print(Object obj) 可以写任意类型的数据,不换行
void println(Object x) 可以写任意类型的数据,换行
*/
基本使用
/*
使用步骤(重点):
1.创建PrintStream对象,构造方法中绑定要输出的目的地
2.使用PrintStream对象中的方法write,print,println,把数据写入到文件中
3.释放资源
*/
public class Demo01PrintStream {
public static void main(String[] args) throws FileNotFoundException {
//System.out.println(97);//a
//1.创建PrintStream对象,构造方法中绑定要输出的目的地
PrintStream ps = new PrintStream("day15\\1.txt");
//2.使用PrintStream对象中的方法write,print,println,把数据写入到文件中
//继承自父类OutputStream的共性成员方法:write方法写数据,查看的时候,会查询编码表
ps.write(97);//a
//自己特有的方法:print,println写的数据,原样输出
ps.println(97);//97
ps.println('@');//97
ps.println(true);//97
ps.println(1.1);//97
ps.println("aaa");//97
//3.释放资源
ps.close();
}
}
修改输出语句的目的地为打印流的目的地
/*
使用System类中的方法setOut可以修改输出语句的目的地
static void setOut(PrintStream out) 参数传递打印流对象,把输出语句的目的地由控制台改成打印流的目的地
*/
public class Demo02PrintStream {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("输出语句的目的地是在控制台输出!");
//创建打印流对象
PrintStream ps = new PrintStream("day15\\2.txt");
System.setOut(ps);//把输出语句的目的地由控制台改成打印流的目的地
System.out.println("输出语句的内容写到PrintStream的目的地2.txt中");
}
}
总结
字符流和字节流的区别
1.字节流读取的和写入都是字节;字符流读取的和写入的都是字符
2.所有的数据(文本,音乐,视频,图片…),都是以字节的方式存储的,使用字节流可以读写任意的文件
3.使用字节流读取的文件中包含中文,如果一次读取一个字节(1/2GBK,1/3UTF-8个中文),使用起来不方便
4.使用字符流读取含有中文文本文件,一次读取一个字符(中文,英文,数字,符号…),使用起来很方便
什么时候使用字符流:读写文本文件(使用记事本打开能看懂)
什么时候使用字节流:读写非文本文件(图片,视频,音频…)