一、数据输入输出流
数据输入流:DataInputStream
数据输入流允许应用程序从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。DataInputStream的构造方法参数是一个InputStream的对象。DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责。
数据输出流:DataOutputStream
数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。DataOutputStream的参数是一个OutputStream的对象。
数据输入输出流的特点:可以对基本类型进行读写。
代码演示:
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
//数据输入输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("test.txt"));
DataInputStream dis = new DataInputStream(new FileInputStream("test.txt"));
//写基本类型
dos.write(1);
dos.writeByte(97);
dos.writeBoolean(false);
dos.writeChar('您');
dos.writeUTF("Hello Java");
//读基本类型
int i = dis.read();
int i1 = dis.read();
boolean b = dis.readBoolean();
char c = dis.readChar();
String s = dis.readUTF();
System.out.println(i);
System.out.println(i1);
System.out.println(b);
System.out.println(c);
System.out.println(s);
}
}
二、内存操作流
操作字节数组
ByteArrayOutputStream: 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。 关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
ByteArrayInputStream: ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。 关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
操作字符数组
CharArrayWriter: 此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。 在此类上调用 close() 无效,并且在关闭该流后可以调用此类中的各个方法,而不会产生任何 IOException。
CharArrayReader: 此类实现一个可用作字符输入流的字符缓冲区。
操作字符串
StringWriter: 一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。 关闭 StringWriter 无效。此类中的方法在关闭该流后仍可被调用,而不会产生任何 IOException。
StringReader: 一个字符串,其源是一个字符串。
代码演示:
import java.io.*;
public class Test1 {
public static void main(String[] args) throws IOException {
//内存操作流
//操作字节数组
byte[] bytes = new byte[]{65,66,67,68,69};
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
bos.write(bytes);
int len = 0;
while ((len = bis.read()) != -1){
System.out.println((char)len);
}
System.out.println("-----------------");
//操作字符数组
CharArrayWriter cw = new CharArrayWriter();
cw.write('我');
cw.write('你');
char[] chars = cw.toCharArray();
CharArrayReader cr = new CharArrayReader(chars);
int len1 = 0;
while ((len1 = cr.read()) != -1){
System.out.println((char) len1);
}
System.out.println("-----------------");
//操作字符串
StringWriter sw = new StringWriter();
sw.write("今天你好吗");
String string = sw.toString();
StringReader sr = new StringReader(string);
int len2 = 0;
while ((len2 = sr.read()) != -1){
System.out.println((char) len2);
}
}
}
三、打印流
字节打印流
PrintStream: PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。调用print()方法可以打印任意数据类型的数据。
PrintWriter: 向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。
代码演示:
import java.io.*;
public class Test2 {
public static void main(String[] args) throws IOException {
//字节打印流
File file = new File("a.txt");
PrintStream ps = new PrintStream(file);
ps.write("曾以为不会离开的人,如今已在谁的身边给他温暖".getBytes());
ps.write("\r\n".getBytes());
ps.write("曾以为不会离开的人,如今已在谁的身边给他温暖".getBytes());
ps.flush();
//关联屏幕标准输出流,可输出任意类型的数据
ps = System.out;
ps.println("理想今年你几岁");
System.out.println();
ps.close();
//字符打印流
PrintWriter pw = new PrintWriter(new FileOutputStream("textW.txt"),true);
pw.write("你还怕大雨吗");
pw.print(1);
pw.flush();
pw.close();
}
}
四、随机访问流
RandomAccessFile: 此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。
特点:能读能写,FileAccessFile不属于流,是Object的子类,但它融合了InputStream和OutputStream的功能,支出对文件的读取和写入。
构造方法:
RandomAccessFile(File file, String mode): 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
RandomAccessFile(String name, String mode): 创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
mode 参数指定用以打开文件的访问模式。
允许的值及其含意为:
“r” 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
“rw” 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
“rws” 打开以便读取和写入,对于 “rw”,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd” 打开以便读取和写入,对于 “rw”,还要求对文件内容的每个更新都同步写入到底层存储设备
两个特殊方法:
getFilePointer(): 获取文件指针,
seek(): 将文件设置到当前指针。
代码演示:
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class Test3 {
public static void main(String[] args) throws IOException {
File file = new File("raf.txt");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
//写数据
raf.writeInt(24);
raf.writeChar('里');
raf.writeUTF("上海自来水来自海上");
RandomAccessFile raf1 = new RandomAccessFile(file, "rw");
//读数据,数据类型顺序和写的一样
int i = raf1.readInt();
long filePointer = raf1.getFilePointer();
char c = raf1.readChar();
String s = raf1.readUTF();
System.out.println(i);
System.out.println(c);
System.out.println(s);
raf1.getFilePointer();
System.out.println(filePointer);
raf1.seek(0);
int i1 = raf1.readInt();
System.out.println(i1);
五、序列化流和反序列化流
对象序列化流 ObjectOutputStream: ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取对象。通过在流中使用文件可以实现对象的持久存储。
注意: 只能将实现 java.io.Serializable 接口的对象写入流中。
对象反序列化流 ObjectInputStream: ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化,就是把文件中存储的对象以流的方式还原成对象。支持 java.io.Serializable接口的对象才能从流读取。
transient 关键字
被 transient 关键字修饰的对象成员变量不会被序列化。
代码演示:
//学生类
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = 6849497901821222054L;
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//序列化,反序列化
import java.io.*;
import java.util.ArrayList;
public class Test4 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObj();//序列化对象
readObj();//反序列化对象
}
private static void readObj() throws IOException, ClassNotFoundException {
ObjectInputStream obi = new ObjectInputStream(new FileInputStream("object.txt"));
Object o = obi.readObject();
ArrayList<Student> list = (ArrayList<Student>) o;
for (Student student : list) {
System.out.println(student.getName()+"=="+student.getAge());
}
}
private static void writeObj() throws IOException {
ArrayList<Student> students = new ArrayList<>();
Student student = new Student("李安", 30);
Student student1 = new Student("李逵", 25);
Student student2 = new Student("张飞", 26);
Student student3= new Student("赵云", 24);
students.add(student);
students.add(student1);
students.add(student2);
students.add(student3);
ObjectOutputStream obs = new ObjectOutputStream(new FileOutputStream("object.txt"));
obs.writeObject(students);
obs.close();
}
}
六、集合Properties
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
特点:
1、Hashtable的子类,map集合中的方法都可以用。
2、该集合没有泛型。键值都是字符串。
3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。
4、有和流技术相结合的方法。
void load(InputStream inStream) | 从输入流读取键值对映射关系 |
---|---|
void load(Reader reader) | 按照行的格式从输入流中读取键值对映射关系 |
void store(OutputStream out, String comments) | 把集合中的键值对数据写入输出流中,comments 是文件注释 |
void stroe(Writer writer, String comments) | 把集合中的键值对数据写入到输出字符中 |
5、Properties 的特殊功能
Object setProperty(String key, String value) | 给集合中添加新的键值对,实际上是调用Hashtable的方法put |
---|---|
String getProperty(String key) | 通过指定的键获取相应的值 |
Set< String > stringPropertyNames() | 获取所有的键对应的Set集合 |
代码演示:
import java.io.*;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Test {
public static void main(String[] args) throws IOException {
//Properties集合
Properties prop = new Properties();
prop.setProperty("张三","25");
prop.setProperty("李四","26");
prop.setProperty("王五","27");
prop.setProperty("张三","28");
//获取集合中的键值数据的几种方式:
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
String value = prop.getProperty((String) key);
System.out.println(key+"=="+value);
}
System.out.println("---------------");
Set<Map.Entry<Object, Object>> entries = prop.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(key+"=="+value);
}
System.out.println("----------------");
//Properties特有的方式:
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key+"=="+value);
}
System.out.println("-----------------");
//Properties和流配合使用
//把集合中的键值数据写到输出流中
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("prop.txt"));
prop.store(writer,null);
writer.close();
//把输入流中的键值数据读取到集合Properties中,
//注意:输入流中的键值之间用“=”连接,不然读取不到数据
InputStreamReader reader = new InputStreamReader(new FileInputStream("prop1.txt"));
prop.load(reader);
reader.close();
//打印导入输入流中的键值数据后的集合
Set<Object> keySet1 = prop.keySet();
for (Object key : keySet1) {
String value = prop.getProperty((String) key);
System.out.println(key+"=="+value);
}
}
}