IO流《字节流、字符流、转换流》

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

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

假设有一个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));
}

常见的字符编码

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

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

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

字符串编解码

//编码:把字符串转换为字节数组
byte[] bytes1 = "你好世界".getBytes();
System.out.println(Arrays.toString(bytes1));

byte[] bytes2 = "你好世界".getBytes("GBK");
System.out.println(Arrays.toString(bytes2));


//解码:把字节数组转换为字符串
String str = new String(bytes1);
System.out.println(str);

String str2 = new String(bytes2,"GBK");
System.out.println(str2);

字符流

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

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

IO流的使用步骤

1.创建流对象(搭桥)
    Reader
    	--FileReader
    	--BufferedReader
    Writer
    	--FileWriter
    	--BufferedWriter
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.write("\r\n");

fw.write("你好世界",0,2);

//释放资源
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();

字符转换流

字符转换流解决乱码问题

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

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

  • 使用InputStreamReader读取指定编码的文本文件

  • FileInputStream fis = new FileInputStream("C:\\Users\\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\\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\\Desktop\\a.txt");
    InputStreamReader isr=new InputStreamReader(fis,"GBK");
    
    //使用OutputStreamWriter流,指定编码UTF-8写入b.txt文件
    FileOutputStream fos=new FileOutputStream("C:\\Users\\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\\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\\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用来读对象和写对象。
    ObjectOutputStream序列化流: 写对象
    ObjectInputStream反序列化流:读对象
    
    注意:被序列化和反序列化的对象,必须实现一个接口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;

    标准的输入输出流【了解】

    System.in: 标准的输入流,读取键盘录入的数据
    System.out: 标准的输出流,往控制台输出

    Properties类

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

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

public Object setProperty(String key, String value)  
	添加键和值,如果键重复,旧值会被覆盖. 类似Map的put()方法
public String getProperty(String key) 
    据键获取值. 类似Map的get()方法
public Set<String> stringPropertyNames()
    获取键的集合. 类似Map的keySet()

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("使用次数已到");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值