IO流中特殊操作流
概述:
IO流中的特殊操作流,顾名思义就是有其特殊的作用;
标准输入输出流
概述:
标准输入输出流它们的作用是用于从键盘录入和打印输出;即我们通常使用的Scanner类
和System.out.println()
,那我们为什么要去学习它呢?只是为了了解Scanner和输出语句的底层结构;
引入:
System类中有两个静态成员变量:
public static final InputStream in;
: 标准输入流。通常用于键盘录入;public static final PrintStream out;
:标准输出流。通常用于打印输出;
标准输入流(InputStream)
概述:
其与Scanner类似,都是用来接收用户的输入;
代码示例一:
public class Demo01 {
public static void main(String[] args) throws IOException {
// 创建输入流
InputStream in = System.in;
// 具体操作
int len;
while ((len = in.read()) != -1) {
System.out.print((char)len);
}
}
}
// 注意:这种方式,该流是关闭不了的,会让你一直输入
/*
现在的功能只能输入简单的数字和英文,却不能输入中文,如果输入中文呢?那就需要用字符流,可是标准输入流是字节流,很容易想到,需要使用转换流将字节流转为字符流;
*/
代码示例二:
public class Demo02 {
public static void main(String[] args) throws IOException {
// 创建输入流对象
Reader reader = new InputStreamReader(System.in);
// 具体操作
char[] chars = new char[1024];
int len = -1;
if ((len = reader.read(chars)) != -1) {
System.out.println(new String(chars, 0, len));
}
// 释放资源
reader.close();
}
}
/*
那么可不可以直接实现读取一行,而不是通过字符数组的形式来读取呢?
答:可以,一次读取一行是字符缓冲流的特有功能,所以需要使用字符缓冲流;而字符缓冲流的构造方法需要传入字符流对象,而我们的System.in是字节对象,所以这里依旧需要使用我们的字符转换流;
*/
代码示例三:
public class Demo03 {
public static void main(String[] args) throws IOException {
// 创建输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 具体操作
System.out.println("请输入内容:");
String line = br.readLine();
System.out.println(line);
System.out.println("请输入一个整数:");
Integer num = Integer.parseInt(br.readLine());
System.out.println(num);
// 关闭资源
br.close();
}
}
总结:
我们通过IO流的方式完成了和Scanner类似的功能,但是却很繁琐,所以我们平时使用依旧是用Scanner类,这里的标准输入流只作为一种了解;
标准输出流(PrintStream)
概述:
我们的输出语句System.out.println()
本质就是标准输出流,这里也是做一个了解;
代码示例:
public class Demo04 {
public static void main(String[] args) {
// 创建输出流对象
PrintStream ps = System.out;
// 可以打印各种数据
ps.println(13);
ps.println(true);
ps.println(13.14);
ps.println("你好,中国!");
ps.println(13L);
ps.println('a');
}
}
总结:
在这里,我们的System.out
本身就是一个对象,我们将其赋值给了ps
变量,由ps
去调用方法,那我们省去这一步就会变成:System.out.println(13);
,所以标准输出语句的本质就是我们的标准输出流;
打印流
概述:
打印流顾名思义就是用来打印数据的,而打印流只负责打印数据,不负责数据的读取;这一点和我们的标准输出流类似;
分类:
字节打印流:PrintStream
字符打印流:PirntWriter
特点:
- 只负责打印输出数据,不负责读取数据;
- 永远不会抛出IOException异常;
- 有自己特有的功能;
字节打印流
概述:
字节打印流继承自FilterOutputStream
而FilterOutputStream
继承自OutputStream
,也就是我们的标准输出流,所以拥有OutputStream
中的所有输出方法;
使用继承自父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出;可以改变输出语句的目的地public static void setOut(PrintStream out)
来重新分配“标准”输出流;
构造方法:
PrintStream(String fileName) // 使用指定的文件名创建新的字节打印流对象
PrintStream(OutputStream out) // 使用标准输出流来创建新的字节打印流对象
代码示例:
public class Demo05 {
public static void main(String[] args) throws FileNotFoundException {
// 创建打印路流对象
// 通过字节打印流直接将数据写入到文件中
PrintStream ps = new PrintStream("IO\\a.txt");
// 具体操作
ps.write(97);
ps.println("hello world!");
// 通过传入标准输出流对象来创建字节打印流对象
// 与标准输出流中的功能相同
PrintStream ps1 = new PrintStream(System.out);
ps1.println("hello world!");
}
}
字符打印流
构造方法:
PrintWriter(String fileName) // 使用指定的文件名创建一个字符打印流对象,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush) // 创建一个字符打印流对象;
/*
out:字符输出流
autoFlush: 一个布尔值,如果为真,则println,printf,或format方法将刷新输出缓冲区
*/
代码示例:
public class Demo06 {
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter("IO\\c.txt");
// 具体操作
pw.write("你好,中国!");
pw.write("abcdefg", 0, 3);
pw.close(); // 这里不对流进行关闭,也是可以写进文件中的
String path = "IO\\d.txt";
PrintWriter pw1 = new PrintWriter(new FileWriter(path), true);
pw1.write("你好,中国!");
pw1.println("This is a string");
pw1.close();
}
}
利用字符打印流来复制文本文件:
public class Demo07 {
public static void main(String[] args) throws IOException {
// 创建源文件路径
String source = "IO\\Demo01.java";
// 创建目标文件路径
String target = "IO\\copy.java";
// 创建输入流对象
BufferedReader br = new BufferedReader(new FileReader(source));
// 创建输出流对象
PrintWriter pw = new PrintWriter(new FileWriter(target), true);
// 具体操作
String line;
while ((line = br.readLine()) != null) {
pw.println(line); // 直写入一行后换行
// 如果缓冲字符流或文件字符流,还需要调用换行方法和刷新方法
}
// 释放资源
pw.close();
br.close();
}
}
总结:
利用字符打印流来进行复制文件,只是少了两步,性能上也并么有提高很多,开发中还是经常用FileWriter
和BufferedWriter
来复制文本文件;打印流只是作为一个了解!
对象序列化流
什么叫做对象的序列化?
-
对象的序列化就是将对象保存到硬盘中或在网络中传输对象;
-
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息;
-
字节序列写到文件之后,相当于文件中持久保存了一个对象的信息;
那我们简而言之为:将我们的对象进行一个持久化操作,让我们的对象数据存储到硬盘中或存取到数据库中去;
对象序列化流(ObjectOutputStream)
概述:
将Java对象的原始数据类型和图形写入OutputStream
; 可以通过使用流的文件来实现对象的持久存储。可以使用ObjectInputStream
读取(重构)对象;如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象 ;
构造方法:
ObjectOutputStream(OutputStream out) // 根据给定的字节输出流对象来创建对象序列化流对象
序列化方法:
void writeObject(Object obj) // 将指定的对象写入序列化流对象中
注意事项:
- 一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口;
- Serializable是一个标记接口,实现该接口,不需要重写任何方法;
代码示例: 实现将集合对象写入到文件中
-
学生类:
import java.io.Serializable; // 想要实现对象的序列化,那么该对象就需要实现Serializable接口 public class Student implements Serializable { private String sid; private String name; private Character gender; private String address; public Student() { } public Student(String sid, String name, Character gender, String address) { this.sid = sid; this.name = name; this.gender = gender; this.address = address; } public String getSid() { return sid; } public void setSid(String sid) { this.sid = sid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Character getGender() { return gender; } public void setGender(Character gender) { this.gender = gender; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Student{" + "sid='" + sid + '\'' + ", name='" + name + '\'' + ", gender=" + gender + ", address='" + address + '\'' + '}'; } }
-
将序列化对象写入到文件中:
public class Demo04 { public static void main(String[] args) throws IOException { // 创建目标文件路径 String path = "IO\\d.txt"; // 创建序列化对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path)); // 创建学生对象 Student s1 = new Student("001","张三",'男',"江苏省南京市"); Student s2 = new Student("002", "李四", '男', "安徽省合肥市"); Student s3 = new Student("003", "王五", '男', "江苏省南京市"); // 创建集合对象 ArrayList<Student> list = new ArrayList<>(); list.add(s1); list.add(s2); list.add(s3); oos.writeObject(list); // 释放资源 oos.close(); } }
对象反序列化流(ObjectInputStream)
概述:
将序列化的对象进行反序列化操作;
构造方法:
ObjectInputStream(InputStream in) // 根据给定的字节输入流对象来创建反序列化流对象
反序列化方法:
Object readObject() // 从反序列化对象中读取一个对象
代码示例: 从文件中读取被序列化的对象
public class Demo03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建源文件路径
String path = "IO\\d.txt";
// 创建流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
// 具体操作
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student s : list) {
System.out.println(s);
}
// 释放资源
ois.close();
}
}
Properties
概述:
Properties类继承自HashTable类,HashTable中对于集合元素操作的方法,Properties中都有,除此之外还有对流操作的特殊方法;
Properties作为Map集合
作为map集合:
public class Demo04 {
public static void main(String[] args) {
// Properties中没有泛型约束,所以可以存放任意类型的数据,但是key保持唯一
Properties p = new Properties();
// 存储元素
p.put("001", "张三");
p.put("002", "李四");
p.put("003", "王五");
// 遍历集合
Set<Object> keys = p.keySet();
for (Object key : keys) {
System.out.println(key + " : " + p.get(key));
}
Set<Map.Entry<Object, Object>> entries = p.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
特有方法: 其特殊方法都是用来处理字符串的;
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) | 设置集合的键和值,都是String类型,底层调用 Hashtable方法 put |
String getProperty(String key) | 使用此属性列表中指定的键搜索属性 |
Set stringPropertyNames() | 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |
public class Demo05 {
public static void main(String[] args) {
Properties p = new Properties();
p.put("001", "张三");
p.put("002", "李四");
p.put("003", "王五");
String property = p.getProperty("001");
System.out.println(property);
p.setProperty("001", "赵六");
System.out.println(p);
Set<String> strings = p.stringPropertyNames();
for (String s : strings) {
System.out.println(s + " : " + p.get(s));
}
}
}
Properties与IO流的结合
常用方法:
方法名 | 说明 |
---|---|
void load(InputStream inStream) | 从字节输入流中读取属性列表(键和元素对) |
void load(Reader reader) | 从字符输入流中读取属性列表(键和元素对) |
void store(OutputStream out, String comments) | 将此属性列表写入此Properties集合中,以适合于使用load(InputStream)方法的格式写入输出字节流 |
void store(Writer writer, String comments) | 将此属性列表写入此Properties集合中,以适合使用 load(Reader)方法的格式写入输出字符流 |
代码示例:
/**
* 1.在项目根目录下创建Student.txt文件,文件内容如下,学生姓名和年龄是以”键值对”形式存在 * 的.
* 2.利用所学的Properties类的相关知识,将文件内容读取到项目中,判断”键值对”中是否有刘方的 * 数据,如果有,将其对应的年龄改为18岁.
* 3.利用Properties类的相关知识把修改后的最新数据写入到newstu.txt文件中.
* Student.txt文件内容:
* 刘伊=18岁
* 王含=20岁
* 李风风=17岁
* 刘方=16岁
* 马红红=20岁
* 丁磊=18岁
* 方影=21岁
* 姚华华=20岁
*/
public class Demo06 {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
BufferedReader br = new BufferedReader(new FileReader("IO\\Student.txt"));
p.load(br);
Set<Object> keys = p.keySet();
if (keys.contains("刘方")) {
p.setProperty("刘方", "18岁");
}
BufferedWriter bw = new BufferedWriter(new FileWriter("IO\\newstu.txt"));
p.store(bw, null);
bw.close();
br.close();
}
}
来源:CSDN
作者:Daily_Code
链接:https://blog.csdn.net/Yi__Ying/article/details/104447134