文章目录
一、操作基本数据类型的流
在我们使用 IO 流中的字符流和字节流实现数据的读取和写入操作时会发现,我们可以操作的其实只有字节、字符以及byte数组,无法操作基本数据类型的数据。
JAVA 提供了操作基本数据类型的流,使用这个流就可以操作基本数据类型的数据了。使用的方式和之前的字节流字符流是一样的,只是提供了一些方法专门读取和写入基础类型的数据。
这里需要注意一点:因为文本不能识别基础数据类型,所以打开文本会乱码。
并且这个流其实我没 get 到点,如果只是作为文本来使用的话不需要使用基础数据类型,文本无法编译。而如果作为数据传输通道完全可以使用集合或者数组来代替。(个人感觉,如果有人有不同的看法欢迎讨论)
- 操作基本数据类型的流
-
DataInputStream 类:可以操作基本数据类型的输入流
-
DataOutputStream 类:可以操作基本数据类型的输出流
- Demo代码示例:
运行结果:public class DataStreamDemo { public static void main(String[] args) throws IOException{ //写入数据 write(); //读取数据 read(); } private static void write() throws IOException { // DataOutputStream(OutputStream out) // 创建数据输出流对象 DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt")); // 写入整数 dos.writeByte(100); dos.writeShort(10000); dos.writeInt(1000000000); dos.writeLong(1000000000000000000L); // 写入小数 dos.writeFloat(10.12F); dos.writeDouble(10.10789D); // 写入字符 dos.writeChar('s'); // 写入字符串 dos.writeChars("今年是2022年"); // 写入Boolean类型 dos.writeBoolean(true); // 释放资源 dos.close(); } private static void read() throws IOException { // DataInputStream(InputStream in) // 创建数据输入流对象 DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt")); // 读数据 // 读取整数 byte b = dis.readByte(); short s = dis.readShort(); int i = dis.readInt(); long l = dis.readLong(); // 读取小数 float f = dis.readFloat(); double d = dis.readDouble(); // 读取字符 char c = dis.readChar(); //读取 boolean 值 boolean bo = dis.readBoolean(); // 释放资源 dis.close(); System.out.println("byte:"+b); System.out.println("short:"+s); System.out.println("int:"+i); System.out.println("long:"+l); System.out.println("float:"+f); System.out.println("double:"+d); System.out.println("char:"+c); System.out.println("boolean:"+bo); } }
- Demo代码示例:
-
二、内存操作流(处理临时文件的流)
内存操作流一般用于处理临时信息,因为临时信息不需要保存,使用后就可以删除。
-
内存操作流 - 操作字节数组
-
ByteArrayOutputStream:输出流
-
ByteArrayInputStream : 输入流
-
Demo代码示例:
public class ByteArrayDemo { public static void main(String[] args) throws IOException { // 写数据 --字节数组输出流:相当于创建了一个临时空间 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 写数据,将数据放到临时空间中 for (int x = 0; x < 10; x++) { baos.write(("HelloWord"+"\t" + x).getBytes()); baos.write("\n".getBytes()); } // 释放资源 // 通过查看源码我们知道这里什么都没做,所以根本需要close() // baos.close(); // 将临时空间转换成byte数组 byte[] bys = baos.toByteArray(); // 读数据: 只能读取byte数组的数据 // ByteArrayInputStream(byte[] buf) ByteArrayInputStream bais = new ByteArrayInputStream(bys); int by = 0; while ((by = bais.read()) != -1) { System.out.print((char) by); } // bais.close(); } }
运行结果:
-
-
-
内存操作流 - 操作字符数组
-
CharArrayReader:输出流
-
CharArrayWrite: 输入流
-
Demo代码示例:
public class CharArrayDemo { public static void main(String[] args) throws IOException { // 写数据 --字节数组输出流:相当于创建了一个临时空间 CharArrayWriter caw = new CharArrayWriter(); // 写数据,将数据放到临时空间中 for (int x = 0; x < 10; x++) { caw.write("HelloWord"+"\t"+ x); caw.write("\n"); } // 释放资源 // 通过查看源码我们知道这里什么都没做,所以根本需要close() // baos.close(); // 将临时空间转换成byte数组 char[] chars = caw.toCharArray(); // 读数据: 只能读取char数组的数据 // CharArrayInputStream(byte[] buf) CharArrayReader car = new CharArrayReader(chars); int by = 0; while ((by = car.read()) != -1) { System.out.print((char) by); } // bais.close(); } }
运行结果:
-
-
三、打印流(不能操作数据源的流)
-
打印流一共分为两种
- 字节打印流:PrintStream
- 字符打印流: PrintWriter
-
打印流的特点:
- 只有输出流,没有输入流,所以打印流只能写入数据不能读取数据。但是可以和其他流搭配使用,以此来实现复制功能。方法是一样的,用打印流代替原本的输出流即可。
- 可以操作任意类型的数据。
- 该流可以直接操作文本文件。
-
打印流独有的方法:
- print() 不会换行,不会自动刷新数据。
- println() 不仅仅自动刷新了数据,还实现了数据的换行。
- Demo代码示例:
运行结果:public class PrintWriterDemo { public static void main(String[] args) throws IOException { // 创建打印流对象 PrintWriter pw = new PrintWriter("pw2.txt"); pw.print(true); pw.print(100); pw.print("hello"); //println()方法,等价于: bw.write(); bw.newLine(); bw.flush();三个方法 pw.println("hello"); pw.println(true); pw.println(100); pw.close(); } }
字符打印流和字节打印流使用方法一样。
四、随机访问流:RandomAccessFile(速度和效率超级快的流)
RandomAccessFile 概述:
RandomAccessFile类并不在 Java.IO 包下,所以严格意义上讲,这个类其实不属于流,该类是Object类的子类。但它融合了InputStream和OutputStream的功能,同时还支持对随机访问文件的读取和写入。
其实这个类和其他流的使用方式和功能都差不多,但是随机访问流和其他流相比更有优先级,比缓冲流还快。
-
构造方法 :
- public RandomAccessFile(String name,String mode);
- 第一个参数是文件路径,第二个参数是操作文件的模式。
模式有四种,我们最常用的一种叫”rw”,这种方式表示我既可以写数据,也可以读取数据
- 第一个参数是文件路径,第二个参数是操作文件的模式。
- public RandomAccessFile(String name,String mode);
-
Demo代码示例:
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
write();//写
read();//读
}
public static void write() throws IOException{
try {
// 创建随机访问流对象
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
// 写入数据
raf.writeInt(100);
raf.writeChar('a');
raf.writeUTF("华夏");
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void read() throws IOException{
try {
// 创建随机访问流对象
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
int i = raf.readInt();
System.out.println(i);
// 该文件指针可以通过 getFilePointer方法读取,并通过 seek 方法设置。
System.out.println("当前文件的指针位置是:" + raf.getFilePointer());
char ch = raf.readChar();
System.out.println(ch);
System.out.println("当前文件的指针位置是:" + raf.getFilePointer());
String s = raf.readUTF();
System.out.println(s);
System.out.println("当前文件的指针位置是:" + raf.getFilePointer());
System.out.println("==========================================");
// 我就要读取a,怎么办呢?
raf.seek(4);
ch = raf.readChar();
System.out.println(ch);
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
文件指针:
在Java开发中用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。
五、合并流(可以将多个数据源一起写入同一个封装地文件中的流)
概述:
SequenceInputStream 类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
通俗点讲就是在实现文件复制功能的时候,可以将多个数据源的数据一起存储到同一个封装地文件中。
- SequenceInputStream 的构造方法
- SequenceInputStream(InputStream s1, InputStream s2)
- SequenceInputStream(Enumeration < ? extends InputStream> e)
-
Demo代码示例:
public class SequenceInputStreamDemo { public static void main(String[] args) throws IOException { //设置多数据源 InputStream s1 = new FileInputStream("aaa.txt"); InputStream s2 = new FileInputStream("bbb.txt"); // 将多个数据源存储进合并流对象中 SequenceInputStream sis = new SequenceInputStream(s1, s2); // 设置文件封装地 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.txt")); // 读写操作 byte[] bys = new byte[1024]; int len = 0; while ((len = sis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); sis.close(); } }
运行结果:
六、序列化流 (操作对象的流)
概述:
序列化流是 JAVA IO 中专门操作对象的流。 有序列化流和反序列化流两种。
- 序列化流 :ObjectOutputStream
- 把对象按照流一样的方式存入文本文件或者在网络中传输。对象 –> 流数据
- 成员方法:public final void writeObject(Object obj) :将对象转换成流数据,并写入序列化流中(文本或者网络等等地方,俗称封装地文件)
- 把对象按照流一样的方式存入文本文件或者在网络中传输。对象 –> 流数据
- 反序列化流:ObjectInputStream
- 把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 –>对象
- 成员方法:readObject():用这个方法就可以将流中的对象重新还原成对象
- 把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 –>对象
既然是对象转换流,那首先整个实体类,咱 new 个对象(程序猿从不缺对象!!!)
- 实体类 Demo 代码示例:
//创建实体类
public class Person implements Serializable {
private String name;//姓名
private int age;//年龄
// 构造1
public Person() {
super();
}
// 构造2
public Person(String name, int age) {
super();
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
- 将对象转换成流数据 Demo 代码示例:
//序列化流写入数据
public class ObjectOutputStreamDemo{
public static void main(String[] args) throws IOException {
// 创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("copy.txt"));
// 创建实体类对象
Person p = new Person("小丸子", 23);
//将对象写入流中
oos.writeObject(p);
// 释放资源
oos.close();
}
}
运行结果:
根据结果可以看不来,这个数据并不能直接使用,呈现乱码状态,因为文本并不能编译 Java 的对象。但是可以看出来对象的路径和对象中存储的部分内容。
- 将流中的对象数据转换回对象 Demo 代码示例:
//反序列化流 读取数据
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException{
// 创建反序列化对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"copy.txt"));
// 将流中的对象重新还原成对象
Object obj = ois.readObject();
// 释放资源
ois.close();
// 输出对象
System.out.println(obj);
}
}
运行结果:
这里需要注意一点:当我们在使用反序列化流转换对象时,需要保证正在反序列化的文件中的对象是没被动过的,这里必须要保证该文件中的对象是被序列化过的,否则报错。
具体的报错信息会根据情况的不同而产生变化,出现此类问题,请联系一下度妈,886。