Java从入门到放弃22—数据输入输出流/内存操作流/打印流/序列化流/随机访问流/Properties/SequenceInputStream
01 DataInputStream/DataOutputStream
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据.DataInputStream 对于多线程访问不一定是安全的线程安全是可选的,它由此类方法的使用者负责。数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。基本功能和文件输入输出流(FileInputStream/FileOutputStream用于读取诸如图像数据之类的原始字节流)大致一样,但是可以读写基本数据类型
构造方法:
DataInputStream(InputStream in) //使用指定的底层 InputStream 创建一个 DataInputStream。
DataOutputStream(OutputStream out) //创建一个新的数据输出流,将数据写入指定基础输出流。
02 内存操作流
内存操作流:此流不关联文件,不直接读写文件,只在内存中操作数据。
操作字节数组ByteArrayInputStream/ByteArrayOutputStream
ByteArrayOutputStream 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
此流无需关闭
构造方法:
ByteArrayOutputStream() //创建一个新的 byte 数组输出流。
ByteArrayOutputStream(int size) //创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。
常用方法:
byte[] toByteArray() 创建一个新分配的 byte 数组。取出这个内存操作流所维护的缓冲区
String toString() 使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
关闭 ByteArrayInputStream 无效。
此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
构造方法:
ByteArrayInputStream(byte[] buf) //创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
ByteArrayInputStream(byte[] buf, int offset, int length) //创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组
常用方法:
int read() 从此输入流中读取下一个数据字节。
int read(byte[] b, int off, int len) 将最多 len 个数据字节从此输入流读入 byte 数组。
操作字符数组CharArrayWriter/CharArrayReader
CharArrayWriter 此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。
注:在此类上调用 close() 无效,并且在关闭该流后可以调用此类中的各个方法,而不会产生任何IOException。
构造方法:
CharArrayWriter() //创建一个新的 CharArrayWriter。
CharArrayWriter(int initialSize) //创建一个具有指定初始大小的新 CharArrayWriter。
常用方法:
int size() //返回缓冲区的当前大小。
char[] toCharArray() //返回输入数据的副本。
String toString() //将输入数据转换为字符串。
CharArrayReader 此类实现一个可用作字符输入流的字符缓冲区。
构造方法:
CharArrayReader(char[] buf) //根据指定的 char 数组创建一个 CharArrayReader。
CharArrayReader(char[] buf, int offset, int length) //根据指定的 char 数组创建一个 CharArrayReader。
操作字符串
StringWriter一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。
关闭 StringWriter 无效。此类中的方法在关闭该流后仍可被调用,而不会产生任何 IOException。
构造方法:
StringWriter() //使用默认初始字符串缓冲区大小创建一个新字符串 writer。
StringWriter(int initialSize) //使用指定初始字符串缓冲区大小创建一个新字符串 writer。
常用方法:
StringBuffer getBuffer() 返回该字符串缓冲区本身。
String toString() 以字符串的形式返回该缓冲区的当前值。
StringReader 其源为一个字符串的字符流。
构造方法:
StringReader(String s) //创建一个新字符串 reader。
常用方法:
int read() 读取单个字符。
int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
long skip(long ns) 跳过流中指定数量的字符
03 打印流
标准输入输出流概述和输出语句的本质
标准输入输出流概述
在System这个类中存在两个静态的成员变量:
public static final InputStream in: 标准输入流, 对应的设备是键盘
public static final PrintStream out: 标准输出流 , 对应的设备就是显示器
System.in的类型是InputStream.
System.out的类型是PrintStream.它是OutputStream的孙子类FilterOutputStream 的子类.
PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,可调用其中一个 println 方法,或写入一个换行符或字节 ('\n')。
PrintWriter
向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream(标准输出流) 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。
与 PrintStream 类不同,如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。这些方法使用平台自有的行分隔符概念,而不是换行符。
构造方法:
PrintWriter(File file)
使用指定文件创建不具有自动行刷新的新 PrintWriter。
PrintWriter(File file, String csn)
创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。
PrintWriter(OutputStream out)
根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。
PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。
PrintWriter(String fileName)
创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
PrintWriter(String fileName, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。
PrintWriter(Writer out)
创建不带自动行刷新的新 PrintWriter。
PrintWriter(Writer out, boolean autoFlush)
创建新 PrintWriter
常用方法:
void println() 通过写入行分隔符字符串终止当前行
//案例:使用 PrintWriter 跟一个输入流配合,完成一个文本文件的复制
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader("Test.java"));
PrintWriter printWriter = new PrintWriter(new FileOutputStream("test.txt"), true);
String line=null;
while ((line=bfr.readLine())!=null){
printWriter.println(line);//读一行写一行
}
bfr.close();
printWriter.close();
}
}
04 二种方式实现键盘录入
A:Scanner scanner = new Scanner(System.in);
B:BufferedReader的readLine方法。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
注:System.in是一个标准的输入流,关联的是键盘设备
System.out是一个标准的输出流,关联的是屏幕
//B方式
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入数据");
String s = bfr.readLine();
if("886".equals(s)){ //自定义一个结束标记
break;
}
System.out.println(s);
}
}
}
05 随机访问流RandomAccessFile
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。需要特别指出的是,如果流已被关闭,则可能抛出 IOException。
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。
RandomAccessFile可以操作任意数据类型的数据。
构造方法:
RandomAccessFile(File file, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
RandomAccessFile(String name, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
常用方法:
long getFilePointer() 返回此文件中的当前偏移量。
void seek(long pos) 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
String readLine() 从此文件读取文本的下一行。
void writeUTF(String str) 使用 modified UTF-8 编码以与机器无关的方式将一个字符串写入该文件。
06 序列化流和反序列化流
序列化流的概述
所谓的序列化:就是把对象通过流的方式存储到文件中.注意:此对象要重写Serializable 接口才能被序列化
反序列化:就是把文件中存储的对象以流的方式还原成对象
序列化流: ObjectOutputStream
反序列化流: ObjectInputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。ObjectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。使用标准机制按需加载类。
构造方法:
ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。
ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream
特殊方法:
void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
Object readObject() 从 ObjectInputStream 读取对象。
注意事项:
1.一个类可以被序列化的前提是需要这个类实现Serializable接口,就需要给这个类添加一个标记.
2.在完成序列化以后,序列化文件中还存在一个标记,然后在进行反序列化的时候,会验证这个标记和序列化前的标记是否一致,因此需要定义一个UID
(private static final long serialVersionUID = 5455576216538966789L;)
3.使用transient关键字声明可以阻止成员变量的序列化
07 Properties
Properties 类表示了一个持久的属性集。属性列表中每个键及其对应值都是一个字符串。
Properties 可保存在流中或从流中加载。
Properties父类是HashTable,擅用父类方法。
构造方法:
Properties() 创建一个无默认值的空属性列表。
Properties(Properties defaults) 创建一个带有指定默认值的空属性列表。
常用方法:
public Object setProperty(String key,String value)添加键值对
public String getProperty(String key)通过键获取值
public Set<String> stringPropertyNames()返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
public void load(Reader reader)读取键值对数据把数据存储到Properties中
public void store(Writer writer, String comments)把Properties集合中的键值对数据写入到文件中, comments注释
//演示load和store方法
public class Test {
public static void main(String[] args) throws IOException {
Properties properties1 = new Properties();
properties1.setProperty("No.1", "John");
properties1.setProperty("No.2", "Snow");
//将属性集合中的键值对数据,存到文本文件中
properties1.store(new FileWriter("username.properties"),null);
Properties properties2 = new Properties();
//把文件中的键值对数据,读取到双列集合中
properties2.load(new FileInputStream("username.properties"));
Set<Map.Entry<Object, Object>> entries = properties2.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(key+"|"+value);
}
}
}
08 SequenceInputStream
SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
构造方法:
SequenceInputStream(InputStream s1, InputStream s2)//通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
SequenceInputStream(Enumeration<? extends InputStream> e) 通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
注:Enumeration<? extends InputStream> e为实现 Enumeration 接口的对象,它生成一系列元素,一次生成一个。连续调用 nextElement 方法将返回一系列的连续元素。
Enumeration<E> elements ()返回此vector向量的组件的枚举。
//第一种构造方法
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream in1 = new FileInputStream("test1.txt");
FileInputStream in2 = new FileInputStream("test2.txt");
FileOutputStream outputStream = new FileOutputStream("all.txt");
SequenceInputStream allIn = new SequenceInputStream(in1, in2);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = allIn.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
allIn.close();
outputStream.close();
}
}
//第二种构造方法
public class Test {
public static void main(String[] args) throws IOException {
//SequenceInputStream(Enumeration < ? extends InputStream > e)
//通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
FileInputStream in1 = new FileInputStream("test1.txt");
FileInputStream in2 = new FileInputStream("test2.txt");
FileInputStream in3 = new FileInputStream("test3.txt");
FileOutputStream outputStream = new FileOutputStream("all.txt");
Vector<FileInputStream> vector = new Vector<>();
vector.add(in1);
vector.add(in2);
vector.add(in3);
Enumeration<FileInputStream> enumeration = vector.elements();
SequenceInputStream allIn = new SequenceInputStream(enumeration);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = allIn.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
allIn.close();
outputStream.close();
}
}