【字节流、字符流、Properties】
第一章 字符流
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
1.1字符输入流【Reader】
字符输入流Reader类的概述
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
字符输入流Reader类的常用方法
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取一个字符。public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
1.2FileReader类
FileReader类的概述
java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileReader类的构造方法
FileReader(File file)
: 创建一个新的 FileReader ,给定要读取的File对象。FileReader(String fileName)
: 创建一个新的 FileReader ,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径。类似于FileInputStream 。
- 构造举例,代码如下:
public class FileReaderConstructor throws IOException{
public static void main(String[] args) {
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
}
}
FileReader类读取数据
- 读取字符:
read
方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1
,循环读取,代码使用演示:
public class FRRead {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileReader fr = new FileReader("read.txt");
// 定义变量,保存数据
int b ;
// 循环读取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fr.close();
}
}
输出结果:
黑
马
程
序
员
小贴士:虽然读取了一个字符,但是会自动提升为int类型。
- 使用字符数组读取:
read(char[] cbuf)
,每次读取多个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回-1
,代码使用演示:
public class FRRead {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileReader fr = new FileReader("read.txt");
// 定义变量,保存有效字符个数
int len ;
// 定义字符数组,作为装字符数据的容器
char[] cbuf = new char[2];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(new String(cbuf));
}
// 关闭资源
fr.close();
}
}
输出结果:
黑马
程序
员序
获取有效的字符改进,代码使用演示:
public class FISRead {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileReader fr = new FileReader("read.txt");
// 定义变量,保存有效字符个数
int len ;
// 定义字符数组,作为装字符数据的容器
char[] cbuf = new char[2];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(new String(cbuf,0,len));
}
// 关闭资源
fr.close();
}
}
输出结果:
黑马
程序
员
1.3字符输出流【Writer】
字符输出流Writer类的概述
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
字符输出流Writer类的常用方法
public abstract void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public abstract void flush()
:刷新此输出流并强制任何缓冲的输出字符被写出。public void write(int c)
:写出一个字符。public void write(char[] cbuf)
:将 b.length字符从指定的字符数组写出此输出流。public abstract void write(char[] b, int off, int len)
:从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。public void write(String str)
:写出一个字符串。public void write(String str,int off,int len)
:写出一个字符串的一部分。
1.4FileWriter类
FileWriter类的概述
java.io.FileWriter
类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileWriter类的构造方法
FileWriter(File file)
: 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName)
: 创建一个新的 FileWriter,给定要读取的文件的名称。FileWriter(File file,boolean append)
: 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName,boolean append)
: 创建一个新的 FileWriter,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。
- 构造举例,代码如下:
public class FileWriterConstructor {
public static void main(String[] args) throws IOException {
// 使用File对象创建流对象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
}
}
FileWriter类写出数据
写出字符:write(int b)
方法,每次可以写出一个字符数据,代码使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据
fw.write(97); // 写出第1个字符
fw.write('b'); // 写出第2个字符
fw.write('C'); // 写出第3个字符
fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字。
/*
【注意】关闭资源时,与FileOutputStream不同。
如果不关闭,数据只是保存到缓冲区,并未保存到文件。
*/
// fw.close();
}
}
输出结果:
abC田
小贴士:
- 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出。
- 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中。
- 写出字符数组 :
write(char[] cbuf)
和write(char[] cbuf, int off, int len)
,每次可以写出字符数组中的数据,用法类似FileOutputStream,代码使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 字符串转换为字节数组
char[] chars = "黑马程序员".toCharArray();
// 写出字符数组
fw.write(chars); // 黑马程序员
// 写出从索引2开始,2个字节。索引2是'程',两个字节,也就是'程序'。
fw.write(b,2,2); // 程序
// 关闭资源
fos.close();
}
}
- 写出字符串:
write(String str)
和write(String str, int off, int len)
,每次可以写出字符串中的数据,更为方便,代码使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 字符串
String msg = "黑马程序员";
// 写出字符数组
fw.write(msg); //黑马程序员
// 写出从索引2开始,2个字节。索引2是'程',两个字节,也就是'程序'。
fw.write(msg,2,2); // 程序
// 关闭资源
fos.close();
}
}
- 续写和换行:操作类似于FileOutputStream。
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象,可以续写数据
FileWriter fw = new FileWriter("fw.txt",true);
// 写出字符串
fw.write("黑马");
// 写出换行
fw.write("\r\n");
// 写出字符串
fw.write("程序员");
// 关闭资源
fw.close();
}
}
输出结果:
黑马
程序员
小贴士:字符流,只能操作文本文件,不能操作图片,视频等非文本文件。
当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流
关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush
方法了。
flush
:刷新缓冲区,流对象可以继续使用。close
:关闭流,释放系统资源。关闭前会刷新缓冲区。
代码使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据,通过flush
fw.write('刷'); // 写出第1个字符
fw.flush();
fw.write('新'); // 继续写出第2个字符,写出成功
fw.flush();
// 写出数据,通过close
fw.write('关'); // 写出第1个字符
fw.close();
fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
fw.close();
}
}
小贴士:即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
第二章 IO资源的处理
2.1JDK7前处理
之前的入门练习,我们一直把异常抛出,而实际开发中并不能这样处理,建议使用try...catch...finally
代码块,处理异常部分,代码使用演示:
public class HandleException1 {
public static void main(String[] args) {
// 声明变量
FileWriter fw = null;
try {
//创建流对象
fw = new FileWriter("fw.txt");
// 写出数据
fw.write("黑马程序员"); //黑马程序员
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.2 JDK7的处理
还可以使用JDK7优化后的try-with-resource
语句,该语句确保了每个资源在语句结束时关闭。所谓的资源(resource)是指在程序完成后,必须关闭的对象。
格式:
try (创建流对象语句,如果多个,使用';'隔开) {
// 读写数据
} catch (IOException e) {
e.printStackTrace();
}
代码使用演示:
public class HandleException2 {
public static void main(String[] args) {
// 创建流对象
try ( FileWriter fw = new FileWriter("fw.txt"); ) {
// 写出数据
fw.write("黑马程序员"); //黑马程序员
} catch (IOException e) {
e.printStackTrace();
}
}
}
第三章 属性集
3.1 Properties类
Properties类的概述
java.util.Properties
继承于Hashtable
,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties
方法就是返回一个Properties
对象。
Properties类的构造方法
public Properties()
:创建一个空的属性列表。
Properties类存储方法
public Object setProperty(String key, String value)
: 保存一对属性。public String getProperty(String key)
:使用此属性列表中指定的键搜索属性值。public Set<String> stringPropertyNames()
:所有键的名称的集合。
public class ProDemo {
public static void main(String[] args) throws FileNotFoundException {
// 创建属性集对象
Properties properties = new Properties();
// 添加键值对元素
properties.setProperty("filename", "a.txt");
properties.setProperty("length", "209385038");
properties.setProperty("location", "D:\\a.txt");
// 打印属性集对象
System.out.println(properties);
// 通过键,获取属性值
System.out.println(properties.getProperty("filename"));
System.out.println(properties.getProperty("length"));
System.out.println(properties.getProperty("location"));
// 遍历属性集,获取所有键的集合
Set<String> strings = properties.stringPropertyNames();
// 打印键值对
for (String key : strings ) {
System.out.println(key+" -- "+properties.getProperty(key));
}
}
}
输出结果:
{filename=a.txt, length=209385038, location=D:\a.txt}
a.txt
209385038
D:\a.txt
filename -- a.txt
length -- 209385038
location -- D:\a.txt
Properties类与流相关的方法
public void load(InputStream inStream)
: 从字节输入流中读取键值对。
参数中使用了字节输入流,通过流对象,可以关联到某文件上,这样就能够加载文本中的数据了。文本数据格式:
filename=a.txt
length=209385038
location=D:\a.txt
加载代码演示:
public class ProDemo2 {
public static void main(String[] args) throws FileNotFoundException {
// 创建属性集对象
Properties pro = new Properties();
// 加载文本中信息到属性集
pro.load(new FileInputStream("read.txt"));
// 遍历集合并打印
Set<String> strings = pro.stringPropertyNames();
for (String key : strings ) {
System.out.println(key+" -- "+pro.getProperty(key));
}
}
}
输出结果:
filename -- a.txt
length -- 209385038
location -- D:\a.txt
小贴士:文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。
第四章 ResourceBundle工具类
ResourceBundle类的介绍
前面我们学习了Properties工具类,它能够读取资源文件,当资源文件是以.properties结尾的文件时,我们可以使用JDK提供的另外一个工具类ResourceBundle来对文件进行读取,使得操作更加简单。
java.util.ResourceBundle它是一个抽象类,我们可以使用它的子类PropertyResourceBundle来读取以.properties结尾的配置文件。
ResourceBundle类对象的创建
在ResourceBundle类中提供了一个静态方法,用于获得它的子类对象(抽象类不能创建对象!)。
// 使用指定的基本名称,默认语言环境和调用者的类加载器获取资源包。
static ResourceBundle getBundle(String baseName);
注意:
①properties配置文件需要放置在类的根路径src下面
②给定参数只需要配置文件的名称,不要扩展名。
public class TestResourceBundle {
public static void main(String[] args) {
// 获得ResourceBundle类的对象(properties文件要放置在src目录下,给定参数只要文件名称,不要扩展名!)
ResourceBundle bundle = ResourceBundle.getBundle("data");// 父类引用指向子类对象(多态)
System.out.println(bundle);
}
}
ResourceBundle读取配置文件操作
ResourceBundle类提供了一个getString(String key)方法用于读取配置文件中指定key的值。
String getString(String key) 从此资源束或其父项之一获取给定密钥的字符串。
代码演示(数据在上图中):
public class TestResourceBundle {
public static void main(String[] args) {
// 获得ResourceBundle类的对象(properties文件要放置在src目录下,给定参数只要文件名称,不要扩展名)
ResourceBundle bundle = ResourceBundle.getBundle("data");
System.out.println(bundle);
// 读取指定key(username)的值
String username = bundle.getString("username");
System.out.println(username); // 张三
// 读取指定key(password)的值
String password = bundle.getString("password");
System.out.println(password); // itheima
}
}
运行结果:
第五章 练习模块
题目一
1. 请定义一个Student类,属性:姓名、性别、年龄、分数
无参、全参构造方法
get/set方法
2. 定义测试类,编写main()方法:
//1.定义一个集合
List stuList = new ArrayList<>();
stuList.add(new Student(“张三”,”男”,20,88);
stuList.add(new Student(“李四”,”女”,19,99);
3. 遍历这个集合,将每个Student对象中的数据按以下格式写到项目根目录下
的student.txt中:
张三,男,20,88
李四,女,19,99
package com.day16;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class Task1_3 {
public static void main(String[] args) throws IOException {
ArrayList<Student> studentArrayList = new ArrayList<>();
studentArrayList.add(new Student("张三","男",20,88));
studentArrayList.add(new Student("李四","女",19,99));
FileWriter fw = new FileWriter("Task1_3.txt");
String stu1 = studentArrayList.get(0).getName()+","+studentArrayList.get(0).getGender()+","+studentArrayList.get(0).getAge()+","+studentArrayList.get(0).getScore();
String stu2 = studentArrayList.get(1).getName()+","+studentArrayList.get(1).getGender()+","+studentArrayList.get(1).getAge()+","+studentArrayList.get(1).getScore();
fw.write(stu1);
fw.write(System.getProperty("line.separator"));//为了程序能在不同操作系统运行
fw.write(stu2);
fw.write(System.getProperty("line.separator"));//为了程序能在不同操作系统运行
fw.flush();//刷新缓存
fw.close();
}
}
class Student {
private String name;
private String gender;
private int age;
private int score;
public Student() {
}
public Student(String name, String gender, int age, int score) {
this.name = name;
this.gender = gender;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
题目二
请编写程序,定义一个Properties对象,存储以下内容:
Properties pro = new Properties();
pro.setProperty(“品名”,”Iphone11 Pro Max”);
pro.setProperty(“颜色”,”暗夜绿”);
pro.setProperty(“存储容量”,”256G”);
pro.setProperty(“价格”,”10899”);
//请将上述内容写入到文件:”test2_1.txt”中
package com.day16;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class Task3_1 {
public static void main(String[] args) {
Properties pro = new Properties();
pro.setProperty("品名","Iphone11 Pro Max");
pro.setProperty("颜色","暗夜绿");
pro.setProperty("存储容量","256G");
pro.setProperty("价格","10899");
try (FileWriter fw = new FileWriter("Task3_1.txt")) {
Set<String> stringSet = pro.stringPropertyNames();
for (String key : stringSet) {
String str = key+"=" + pro.getProperty(key);
fw.write(str);
fw.write(System.lineSeparator());
fw.flush();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
题目三
请编写程序,定义一个Properties对象,将文件”test2_1.txt”的内容读取到Properties对象中,遍历,并打印每个键值对。
package com.day16;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class Task3_2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("Task3_1.txt"));
Properties pro = new Properties();
String line;
while ((line = br.readLine())!=null){
String[] str = line.split("=");
pro.setProperty(str[0],str[1]);
}
Set<String> keySet = pro.stringPropertyNames();
for (String key : keySet) {
System.out.println(key+"="+pro.getProperty(key));
}
br.close();
}
}