javaSE--进阶十二(IO流,序列化,Properties类)

字节流读取文本文件的问题

当文本文件中存在汉字和字母的时候,由于汉字和字母占用的字节数不一样,再读取的时候就可能产生乱码的问题。

假设有一个a.txt文件

a你好bc

使用下面的FileInputStream读取文件中的字节,把字节转成字符串就有乱码问题。

FileInputStream fis=new FileInputStream("myModule12\\a.txt");
//一次读取多个字节
byte[] bs=new byte[2];
int len; //记录每次读取的字节个数
while ((len=fis.read(bs))!=-1){
    //把字节数组转换为一个字符串
    System.out.println(new String(bs,0,len));
}

字符流

Java的API中,为了解决前面的乱码问题,专门提供了类流用来对文本文件进行操作。Reader和Writer

Reader: 字符输入流(读取字符)
	-- FileReader
	-- BufferedReader
    
Writer: 字符输出流(写入字符)
    -- FileWriter
    -- BufferedWriter

IO流的使用步骤

1.创建流对象(搭桥)
    Reader
    Writer
2./写数据(过桥)
    read
    write
3.释放资源(过河拆桥)
    close

字符流读取数据

  • 一次读取一个字符
//字符输入流
FileReader fr=new FileReader("myModule12\\a.txt");

//循环读取,一次读一个字符
int b; //记录每次读取的字符
while ((b=fr.read())!=-1){
    System.out.print((char) b);
}

//释放资源
fr.close();
  • 一次读取多个字符
//创建输入流对象
FileReader fr=new FileReader("myModule12\\a.txt");

//读取数据: 一次读取多个字符
char[] chs=new char[1024];
int len; //记录每次读取的字符个数
while ((len=fr.read(chs))!=-1){
    //把字符数组的一部分,转换为字符串
    String str=new String(chs,0,len);
    System.out.println(str);
}

//释放资源
fr.close();

字符流写入数据

//创建输出流对象FileWriter
FileWriter fw=new FileWriter("myModule12\\b.txt");

//写一个字符
fw.write(97); //写97对应的是 字符‘a’

//写多个字符
char[] chs={'h','e','l','l','o'};
fw.write(chs); 

//写一个字符数组的一部分
fw.write(chs,0,3);

//写一个字符串
fw.write("你好世界");

//释放资源
fw.close();

字符流复制文件

//源文件:a.txt ,使用FileReader进行读取
FileReader fr=new FileReader("myModule12\\a.txt");
//目标文件:b.txt,使用FileWriter进行写入
FileWriter fw=new FileWriter("myModule12\\b.txt");

//一边读,一遍写
char[] chs=new char[1024];
int len; //记录每次读取的字符个数
while ((len=fr.read(chs))!=-1){
    //把读取到的有效字符,写入到目标文件
    fw.write(chs,0,len);
}

//释放资源
fw.close();
fr.close();

字符缓冲流提高读写效率

BufferedReader和BufferedWriter是一个包装流,它的读和写依赖于Reader和Writer,在内部有一个缓冲区数组,可以提高读写的效率。

//源文件:a.txt ,使用FileReader进行读取
//FileReader fr=new FileReader("myModule12\\a.txt");
BufferedReader br=new BufferedReader(new FileReader("myModule12\\a.txt"));

//目标文件:b.txt,使用FileWriter进行写入
//FileWriter fw=new FileWriter("myModule12\\b.txt");
BufferedWriter bw=new BufferedWriter(new FileWriter("myModule12\\b.txt"));

//一边读,一遍写
char[] chs=new char[1024];
int len; //记录每次读取的字符个数
while ((len=br.read(chs))!=-1){
    //把读取到的有效字符,写入到目标文件
    bw.write(chs,0,len);
}

//释放资源
bw.close();
br.close();
  • 使用BufferedReader和BufferedWriter缓冲流读取写数据,一次读写一行
BufferedReader 有一个读取一个行的方法  readLine()
    
BufferedWriter 有一个写换行符的方法  newLine(); //具有跨平台性
	Win: \r\n
	Linux: \r
	Mac:  \n
//源文件:a.txt ,使用FileReader进行读取
BufferedReader br=new BufferedReader(new FileReader("myModule12\\a.txt"));
//目标文件:b.txt,使用FileWriter进行写入
BufferedWriter bw=new BufferedWriter(new FileWriter("myModule12\\b.txt"));

//读一行,写一行
String line; //每次读取的行
while ((line=br.readLine())!=null){
    //把读取的每一行,写入到目标文件
    bw.write(line);
    //bw.write("\r\n");  //Win: \r\n  Linux: \r Mac \n
    bw.newLine(); //写一个换行符,具有跨平台性,
}

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

close和flush的区别

flush: 把流中缓冲的数据刷新到文件中
close: 先自动刷新,再释放资源。

文件续写

//字符流,参数true表示可以续写
FileWriter fw=new FileWriter("myModule12\\a.txt",true);
fw.write("world");
fw.close();

//字节流,参数true表示可以续写
FileOutputStream fos=new FileOutputStream("myModule12\\a.txt",true);
fos.write("world".getBytes());
fos.close();

字符转换流

常见的字符编码

ASCII: 美国信息交换码表,包含一些字母、数字、标点符号
	一个字符占1个字节

GBK: 中国人的码表,兼容ASCII编码,还包含汉字、日韩文字
	一字母占1个字节
	一个汉字占2个字节

UTf-8:万国码,包含各个国家的文字
	一字母占1个字节
	一个汉字占3个字节
	
注意:当读取数据写如数据的文件编码不一致,就会产生乱码问题。

字符转换流解决乱码问题

Java的API中提供的字符流FileReader和FileWriter默认是按照UTF-8编码进行读和写的。

为了读写其他编码的文件,Java的API又提供了InputStreamReader和OutputStreamWriter两个流,可以指定编码进行读和写。

  • 使用InputStreamReader读取指定编码的文本文件
FileInputStream fis = new FileInputStream("C:\\Users\\it\\Desktop\\a.txt");
//把FileInputStream读取的字节数,按照GBK编码进行转换
InputStreamReader isr=new InputStreamReader(fis,"GBK");

//一次读取多个字符
char[] chs=new char[1024];
int len; //记录每次读取的字符个数
while ((len=isr.read(chs))!=-1){
    //把数组转好为字符串
    String str=new String(chs,0,len);
    System.out.println(str);
}

isr.close();
  • 使用OutputStreamWriter写入指定编码的文件
FileOutputStream fos = new FileOutputStream("C:\\Users\\it\\Desktop\\b.txt");
//把FileOutputStream + 编码表 转换为 OutputStreamWriter
OutputStreamWriter osw=new OutputStreamWriter(fos,"GBK");

//写数据
osw.write("hello你好");

char[] chs={'h','e','l','l','o'};
osw.write(chs);

//释放资源
osw.close();
  • 把a.txt(GBK编码)文件中的字符,写入到b.txt(UTF-8)文件中。
//使用InputStreamReader流,指定编码GBK读取a.txt文件
FileInputStream fis = new FileInputStream("C:\\Users\\it\\Desktop\\a.txt");
InputStreamReader isr=new InputStreamReader(fis,"GBK");

//使用OutputStreamWriter流,指定编码UTF-8写入b.txt文件
FileOutputStream fos=new FileOutputStream("C:\\Users\\it\\Desktop\\b.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");

//读写数据
char[] chs=new char[1024];
int len; //记录每次读取到的字符个数
while ((len=isr.read(chs))!=-1){
    osw.write(chs,0,len);
}

//释放资源
osw.close();
isr.close();

使用缓冲流进行包装

//使用InputStreamReader流,指定编码GBK读取a.txt文件
FileInputStream fis = new FileInputStream("C:\\Users\\it\\Desktop\\a.txt");
InputStreamReader isr=new InputStreamReader(fis,"GBK");
BufferedReader br=new BufferedReader(isr);

//使用OutputStreamWriter流,指定编码UTF-8写入b.txt文件
FileOutputStream fos=new FileOutputStream("C:\\Users\\it\\Desktop\\b.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");
BufferedWriter bw=new BufferedWriter(osw);

//读写一行数据
String line;
while((line=br.readLine())!=null){
    bw.write(line);
    bw.newLine(); //换行
}

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

对象流(序列化流)

Java的API提供了ObjectInputStream和ObjectOutputStream用来读对象和写对象。

序列化:写对象
反序列化:读对象

注意:被序列化和反序列化的对象,必须实现一个接口Serializable(这个接口仅仅起到一个标记的作用)
//创建序列化流(对象输出流)
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("myModule12\\a.txt"));
GirlFriend gf=new GirlFriend("翠花",18,165,100);
//写对象
oos.writeObject(gf);

//反序列化流(对象输入流)
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("myModule12\\a.txt"));
Object obj = ois.readObject();
System.out.println(obj); 

序列号冲突问题

问题:
	每次编译源代码都会自动生成一个序列号,如果修改了源代码序列化和反序列化的序列号就会不一致。这个时候会导		致序列号冲突。

解决办法:
	在源代码中,写一个固定的序列号,固定写法
	private static final long serialVersionUID = -68497944707523234L;

Properties类

Properties是Map的子类,是一个双列集合,键和值都是字符串类型。Map集合的方法它都能使用。

但是推荐是Properties自己特有的方法,对集合进行操作。

public Object setProperty(String key, String value)  
	添加键和值,如果键重复,旧值会被覆盖
public String getProperty(String key) 
    据键获取值
public Set<String> stringPropertyNames()
    获取键的集合
Properties pro=new Properties();

//使用Properties集合的特有方法,存储键-值
pro.setProperty("张三","18");
pro.setProperty("李四","20");
pro.setProperty("王五","19");
pro.setProperty("王五","22");

//通过键,获取值
String obj = pro.getProperty("李四");
System.out.println(obj);

//遍历
Set<String> keys = pro.stringPropertyNames();
for (String key : keys) {
    String vlaue = pro.getProperty(key);
    System.out.println(key+"..."+vlaue);
}

Properties提供了两个和IO流相关的方法,用来把键值对存储到文件和读取键值对到集合。

public void store(OutputStream out, String comments) 
    把集合中的键和值存储到文件中
public void load(Reader reader)
    把文件中的键和值读取到集合中
Properties pro=new Properties();
pro.setProperty("zhangsan","20");
pro.setProperty("lis","28");
pro.setProperty("wangwu","21");

//把集合中的键和值,写到文件中
pro.store(new FileWriter("myModule12\\a.txt"),null);

//读取文件中的键和值读取到集合
pro.load(new FileReader("myModule12\\a.txt"));
System.out.println(pro);

Properties集合一般和软件的配置文件一起使用,把软件的相关配置写成一个文件,在文件中键值对的形式来保存配置信息。

Properties pro=new Properties();
// 1.读取配合文件中键对应的值
pro.load(new FileReader("myModule12\\a.txt"));
// 2.把值转换为整数,判断整数是否>0,说明还有使用次数
String count = pro.getProperty("count");
int value = Integer.parseInt(count);
if(value>0){
    System.out.println("欢迎使用");
    //每次使用之后,需要修改配置文件的值,-1
    value--;
    pro.setProperty("count",value+"");
    //把集合中的键和值写到文件中
    pro.store(new FileWriter("myModule12\\a.txt"),null);
}else{
    System.out.println("使用次数已到,请登录www.baidu.com");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值