1.序列流
什么是序列流 * 序列流可以把多个字节输入流整合成一个, * 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.
类 SequenceInputStream
java.lang.Object
——java.io.InputStream
————java.io.SequenceInputStream
所有已实现的接口:
Closeable
public class SequenceInputStream extends InputStream SequenceInputStream 表示其他输入流的逻辑串联。 它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾, 接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
public SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream
(将按顺序读取这两个参数,先读取 s1,然后读取 s2),
以提供从此 SequenceInputStream 读取的字节。
public SequenceInputStream(Enumeration<? extends InputStream> e) 通过记住参数来初始化新创建的 SequenceInputStream, 该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。 将按顺序读取由该枚举生成的输入流,以提供从此 SequenceInputStream 读取的字节。 在用尽枚举中的每个输入流之后,将通过调用该流的 close 方法将其关闭。 参数: e - 输入流的一个枚举。
序列流之应用——歌曲串烧
demo1
public class a {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileInputStream fis1 = new FileInputStream("a.txt");//创建字节输入流关联a.txt
FileOutputStream fos1 = new FileOutputStream("c.txt");//创建字节输出流关联c.txt
//FileOutputStream在创建对象时,如果不存在,会创建一个
//如果存在,则会把文件清空.而不是在写的时候清空
int b1;
while((b1 = fis1.read()) != -1) {//不断的在a.txt上读取字节
fos1.write(b1); //将读到的字节写到c.txt上
}
fis1.close();//关闭字节输入流
FileInputStream fis2 = new FileInputStream("b.txt");
int b2;
while((b2 = fis2.read()) != -1) {
fos1.write(b2);
}
fis2.close();
fos1.close();
//SequenceInputStream改善上述
FileInputStream fis3 = new FileInputStream("a.txt");
FileInputStream fis4 = new FileInputStream("b.txt");
SequenceInputStream sis = new SequenceInputStream(fis3, fis4);
FileOutputStream fos3 = new FileOutputStream("c.txt");
int b;
while((b = sis.read()) != -1) {
fos3.write(b);
}
sis.close();//sis在关闭的时候,会将构造方法中传入的流对象也都关闭
fos3.close();
//SequenceInputStream整个多个流
FileInputStream fis5 = new FileInputStream("a.txt");
FileInputStream fis6 = new FileInputStream("b.txt");
FileInputStream fis7 = new FileInputStream("c.txt");
Vector<FileInputStream> v = new Vector<>();//创建集合对象
v.add(fis5);//将流对象存储进来
v.add(fis6);
v.add(fis7);
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis5 = new SequenceInputStream(en); //将枚举中的输入流整合成一个
FileOutputStream fos5 = new FileOutputStream("d.txt");
int b5;
while((b5 = sis5.read()) != -1) {
fos5.write(b5);
}
sis5.close();
fos5.close();
}
}
2.内存输出流
什么是内存输出流
* 该输出流可以向内存中写数据, 把内存当作一个缓冲区, 写出之后可以一次性获取出所有数据
因为FileInputStream读取中文的时候会出现乱码·~~
解决方案
* 1,字符流读取
* 2,ByteArrayOutputStream-内存输出流
使用方式
* 创建对象: new ByteArrayOutputStream()
* 写出数据: write(int), write(byte[])
* 获取数据: toByteArray()
类 ByteArrayOutputStream
java.lang.Object
——java.io.OutputStream
————java.io.ByteArrayOutputStream
所有已实现的接口:
Closeable, Flushable
public class ByteArrayOutputStream extends OutputStream
此类实现了一个输出流,其中的数据被写入一个 byte 数组。
缓冲区会随着数据的不断写入而自动增长。
可使用 toByteArray() 和 toString() 获取数据。
关闭 ByteArrayOutputStream 无效。
此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
public ByteArrayOutputStream() 创建一个新的 byte 数组输出流。缓冲区的容量最初是 32 字节,如有必要可增加其大小。 public ByteArrayOutputStream(int size) 创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。 public void write(int b) 将指定的字节写入此 byte 数组输出流。
public byte[] toByteArray() 创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中。
public class b {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("utf.txt");
byte[] arr = new byte[3];
int len;
while((len = fis.read(arr)) != -1) {
System.out.println(new String(arr,0,len));
}
fis.close();
FileInputStream fis1 = new FileInputStream("utf.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();//么有关联,不用释放
//在内存中创建了可以增长的内存数组
int b;
while((b = fis1.read()) != -1) {
baos.write(b); //将读取到的数据逐个写到内存中
}
byte[] arr1 = baos.toByteArray();//将缓冲区的数据全部获取出来,并赋值给arr数组
System.out.println(new String(arr1));
System.out.println(baos.toString());
//将缓冲区的内容转换为了字符串;在输出语句中可以省略,调用他的toString方法,使用平台默认的字符集
//在不使用码表的情况
fis1.close();
//baos不用关闭,关闭无效,没有关联文件
}
}
内存输出流的一个练习
定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
public class c{
/**
* @param args
* 分析:
* 1,reda(byte[] b)是字节输入流的方法,创建FileInputStream,关联a.txt
* 2,创建内存输出流,将读到的数据写到内存输出流中
* 3,创建字节数组,长度为5
* 4,将内存输出流的数据全部转换为字符串打印
* 5,关闭输入流
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1,reda(byte[] b)是字节输入流的方法,创建FileInputStream,关联a.txt
FileInputStream fis = new FileInputStream("a.txt");
//2,创建内存输出流,将读到的数据写到内存输出流中
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//3,创建字节数组,长度为5
byte[] arr = new byte[5];
int len;
while((len = fis.read(arr)) != -1) {
baos.write(arr, 0, len);
//System.out.println(new String(arr,0,len));会出现乱码
}
//4,将内存输出流的数据全部转换为字符串打印
System.out.println(baos); //即使没有调用,底层也会默认帮我们调用toString()方法
//5,关闭输入流
fis.close();
}
}
3.对象操作流
什么是对象操作流
* 该流可以将一个对象写出, 或者读取一个对象到程序中. 也就是执行了序列化和反序列化的操作.
类 ObjectOutputStream
java.lang.Object ——java.io.OutputStream ————java.io.ObjectOutputStream 所有已实现的接口: Closeable, DataOutput, Flushable, ObjectOutput, ObjectStreamConstants
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants
public ObjectOutputStream(OutputStream out) throws IOException 创建写入指定 OutputStream 的 ObjectOutputStream。
public final void writeObject(Object obj) throws IOException
将指定的对象写入 ObjectOutputStream。
对象的类、类的签名,以及类及其所有超类型的非瞬态和非静态字段的值都将被写入
public class d {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
Person p1 = new Person("张三", 23);
Person p2 = new Person("李四", 24);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e.txt"));
oos.writeObject(p1);
oos.writeObject(p2);
oos.close();
//java.io.NotSerializableException: bean.Person
//Person类要实现Serializable接口
//乱码,没问题,只要能读出来
}
}
Person类
* 注意
* 要写出的对象必须实现Serializable接口才能被序列化
* id号的使用,不用必须加id号
package bean;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
//多了一个id号,出错时会显示id号,不加也没问特
private String name;
private int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.age = age;
this.name = name;
// TODO Auto-generated constructor stub
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
类 ObjectInputStream
java.lang.Object
——java.io.InputStream
————java.io.ObjectInputStream
所有已实现的接口:
Closeable, DataInput, ObjectInput, ObjectStreamConstants
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
public final Object readObject() throws IOException, ClassNotFoundException
从 ObjectInputStream 读取对象。对象的类、类的签名和类及所有其超类型的非瞬态和非静态字段的值都将被读取。
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e.txt"));
Person p1 = (Person) ois.readObject();
Person p2 = (Person) ois.readObject();
//Person p3 = (Person) ois.readObject();//当文件读取到了末尾时出现EOFException
System.out.println(p1);//ok
System.out.println(p2);
//System.out.println(p3);
ois.close();
用ArrayList完善,将集合对象一次读写
public class e {
/**
* @param args
* @throws IOException
* @throws FileNotFoundException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
Person p1 = new Person("张三", 23);
Person p2 = new Person("李四", 24);
Person p3 = new Person("王五", 25);
Person p4 = new Person("赵六", 26);
ArrayList<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e.txt"));
oos.writeObject(list);//把整个集合对象一次写出
oos.close();
ObjectInputStream ois1 = new ObjectInputStream(new FileInputStream("e.txt"));
ArrayList<Person> list1 = (ArrayList<Person>) ois1.readObject();
//将集合对象一次读取
for (Person person : list1) {
System.out.println(person);
}
ois1.close();
}
}
4.打印流
什么是打印流
* 该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式
* System.out就是一个PrintStream, 其默认向控制台输出信息
类 PrintStream
java.lang.Object
——java.io.OutputStream
————java.io.FilterOutputStream
——————java.io.PrintStream
所有已实现的接口:
Closeable, Flushable, Appendable
直接已知子类:
LogStream
public class PrintStream extends FilterOutputStream implements Appendable, Closeable
PrintStream 永远不会抛出 IOException;
PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。
在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
类 PrintWriter
java.lang.Object
——java.io.Writer
————java.io.PrintWriter
所有已实现的接口:
Closeable, Flushable, Appendable
public class PrintWriter extends Writer
向文本输出流打印对象的格式化表示形式。
此类实现在 PrintStream
中的所有 print 方法。
此类中的方法不会抛出 I/O 异常,
public PrintWriter(Writer out,boolean autoFlush)
创建新 PrintWriter。
参数:
out - 字符输出流
autoFlush - boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区
如果没有启用自动刷新,则需要手工调用flush()方法才能完成刷新。
public PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。
此构造方法创建必要的中间 OutputStreamWriter,后者使用默认字符编码将字符转换为字节。
参数:
out - 输出流
autoFlush - boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区
public void flush() 刷新该流的缓冲。 在没有刷新前,你写入的数据并没有真正写入文件,只是保存在内存中。刷新后才会写入文件, 如果程序中没有调用刷新方法,当程序执行完时会自动刷新,也就是只有到数据全部执行完才会一次性写入, 大数据量时对运行效率有影响。
当我们不使用自动刷新时,也没调用close()方法时,数据没有被写入,即内存没有刷新 然后调用flush()刷新后,数据被写入 或调用close(),数据也会被写入 而使用自动刷新后,不用close(),不用flush(0数据也会被写入
public class f {
/**
* PrintStream和PrintWriter分别是打印的字节流和字符流
* 只操作数据数据目的的
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
System.out.println("abc");
PrintStream ps = System.out;//获取标注输出流
ps.println(98); //底层通过Integer.toString()将97转换成字符串"97"并打印
ps.write(97); //查找码表,找到对应的a并打印
Person p1 = new Person("张三", 23);
ps.println(p1); //默认调用p1的toString方法
Person p2 = null;//打印引用数据类型,如果是null,就打印null,如果不是null就打印对象的toString方法
ps.println(p2);
ps.close();
PrintWriter pw = new PrintWriter(new FileOutputStream("f.txt"),true);
//PrintWriter pw = new PrintWriter(new File("f.txt"));
pw.println(97); //自动刷出功能只针对的是println方法.没什么用
pw.write(97);
pw.print(97);
pw.println(97);
//pw.flush();
//pw.close();//关不关对结果没影响
/*97
a9797*/
}
}
5.标准输入输出流
什么是标准输入输出流
* System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据
* System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
修改标准输入输出流
* 修改输入流: System.setIn(InputStream)
* 修改输出流: System.setOut(PrintStream)
基本使用
public static void main(String[] args) throws IOException {
System.out.println("只读第一个字节");
InputStream is = System.in;
int x = is.read();//只读第一个字节
System.out.println(x);
//is.close();//输入流只有一个.没有关联文件就不用关,
//然后会自动读取下一个字节
InputStream is2 = System.in;
int y = is2.read();
System.out.println(y); }
修改标准输入输出流
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("a.txt")); //改变标准输入流
System.setOut(new PrintStream("b.txt"));//改变标注输出流
InputStream is = System.in; //获取标准的键盘输入流,默认指向键盘,改变后指向文件
PrintStream ps = System.out;//获取标准输出流,默认指向的是控制台,改变后就指向文件
int b;
while((b = is.read()) != -1) {
ps.write(b);
}
//System.out.println(); //也是一个输出流,不用关,因为没有和硬盘上的文件产生关联的管道
is.close();
ps.close();
}
修改标准输入输出流-拷贝图片
public class g {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//修改标准输入输出流拷贝图片
System.setIn(new FileInputStream("IO图片.png")); //改变标准输入流
System.setOut(new PrintStream("copy.png")); //改变标准输出流
InputStream is = System.in; //获取标准输入流
PrintStream ps = System.out;//获取标准输出流
int len;
byte[] arr = new byte[1024 * 8];
while((len = is.read(arr)) != -1) {
ps.write(arr, 0, len);
}
is.close();
ps.close();
}
}
6.随机访问流
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
支持对随机访问文件的读取和写入 元数据,右键,属性,详细信息
类 RandomAccessFile
java.lang.Object
——java.io.RandomAccessFile
所有已实现的接口:
Closeable, DataInput, DataOutput
public class RandomAccessFile extends Objectimplements DataOutput, DataInput, Closeable
此类的实例支持对随机访问文件的读取和写入。
public RandomAccessFile(String name, String mode) throws FileNotFoundException
创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
public RandomAccessFile(File file,String mode) throws FileNotFoundException
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
将创建一个新的 FileDescriptor 对象来表示此文件的连接。
mode 参数指定用以打开文件的访问模式。允许的值及其含意为:
"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
public int read() throws IOException 从此文件中读取一个数据字节。 以整数形式返回此字节,范围在 0 到 255 (0x00-0x0ff)。 如果尚无输入可用,将阻塞此方法。 尽管 RandomAccessFile 不是 InputStream 的子类, 但此方法的行为与 InputStream 的 InputStream.read() 方法完全一样。 返回: 下一个数据字节,如果已到达文件的末尾,则返回 -1。
public void write(int b) throws IOException
向此文件写入指定的字节。从当前文件指针开始写入
public void seek(long pos) throws IOException
设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
偏移量的设置可能会超出文件末尾。
偏移量的设置超出文件末尾不会改变文件的长度。
只有在偏移量的设置超出文件末尾的情况下对文件进行写入才会更改其长度。
参数:
pos - 从文件开头以字节为单位测量的偏移量位置,在该位置设置文件指针。
抛出:
IOException - 如果 pos 小于 0 或者发生 I/O 错误。
public class i {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("a.txt", "rw");
raf.write(97);//写后指针往后移动
int x = raf.read();//-1
System.out.println(x);
raf.seek(0);
int y = raf.read();//-1
System.out.println(y);//97
raf.seek(5);//在指定位置设置指针
raf.write(98);//a b
raf.close();
}
}
7.数据输入输出流
什么是数据输入输出流
* DataInputStream, DataOutputStream可以按照基本数据类型大小读写数据
* 例如按Long大小写出一个数字, 写出时该数据占8字节. 读取的时候也可以按照Long类型读取, 一次读取8个字节.
类 DataInputStream
java.lang.Object
——java.io.InputStream
————java.io.FilterInputStream
——————java.io.DataInputStream
所有已实现的接口:
Closeable, DataInput
public class DataInputStream extends FilterInputStream implements DataInput
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型
类 DataOutputStream
先不用此数据流,数据会丢失
public class j {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("h.txt");
/*
fos.write(97);
fos.write(98);
fos.write(99);//abc*/
fos.write(997);//
/**
* 00000000 00000000 00000011 11100101 int类型997
* 前三个8位砍掉11100101变为229
* 00000000 00000000 00000000 11100101 int类型229
* */
fos.write(998);
fos.write(999);
fos.close();
FileInputStream fis = new FileInputStream("h.txt");
int x = fis.read();
int y = fis.read();
int z = fis.read();
System.out.println(x);//229
System.out.println(y);
System.out.println(z);
fis.close();
/*229
230
231*/
}}
public class j {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("h.txt");
DataOutputStream dos = new DataOutputStream(new FileOutputStream("h.txt"));
dos.writeInt(997);
dos.writeInt(998);
dos.writeInt(999);//乱码,没关系,可以读出来
dos.close();//这个注释后,下面不能读出,今天把代码整理了下,有ok了
DataInputStream dis = new DataInputStream(new FileInputStream("h.txt"));
int x = dis.readInt();
int y = dis.readInt();
int z = dis.readInt();
System.out.println(x);
System.out.println(y);
System.out.println(z);//可以完整读出了
dis.close();
}
}
8.类 Properties
java.lang.Object
——java.util.Dictionary<K,V>
————java.util.Hashtable<Object,Object>
——————java.util.Properties
所有已实现的接口:
Serializable, Cloneable, Map<Object,Object>
直接已知子类: Provider
public class Properties extends Hashtable<Object,Object>
Properties类表示了一个持久的属性集。
Properties 可保存在流中或从流中加载。(这个还不知道怎么用)
属性列表中每个键及其对应值都是一个字符串。
因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。
但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。
相反,应该使用 setProperty 方法。
案例演示
* Properties作为Map集合的使用
Properties prop = new Properties();
prop.put("abc", 123);
System.out.println(prop);//{abc=123}
public Object setProperty(String key, String value) 调用 Hashtable 的方法 put。 强制要求为属性的键和值使用字符串。返回值是 Hashtable 调用 put 的结果。 public String getProperty(String key) 用指定的键在此属性列表中搜索属性。 如果在此属性列表中未找到该键,则接着递归检查默认属性列表及其默认值。如果未找到属性,则此方法返回 null。 public Enumeration<?> propertyNames() 返回属性列表中所有键的枚举,如果在主属性列表中未找到同名的键,则包括默认属性列表中不同的键。
案例演示
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties prop = new Properties();
prop.setProperty("name", "张三");
prop.setProperty("tel", "189*****");
//{tel=18912345678, name=张三}
System.out.println(prop);
Enumeration<String> en = (Enumeration<String>) prop.propertyNames();
while(en.hasMoreElements()) {
String key = en.nextElement();//获取Properties中的每一个键
String value = prop.getProperty(key);//根据键获取值
System.out.println(key + "="+ value);
}
/*name=张三
tel=189******/
}
public void load(InputStream inStream) throws IOException
从输入流中读取属性列表(键和元素对)。
输入流按 load(Reader) 中所指定的、简单的面向行的格式,
此方法返回后,指定的流仍保持打开状态。
public void load(Reader reader) throws IOException
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
public void store(OutputStream out, String comments) throws IOException
以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,
将此 Properties 表中的属性列表(键和元素对)写入输出流。
public void store(Writer writer,String comments) throws IOException
以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
一般用于配置文件config.properties
#时间
qq=123***
tel=189***
username=wha***
public class k {
/**
* @param args
* @throws IOException
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties prop = new Properties();
prop.load(new FileInputStream("config.properties"));//将文件上的键值对读取到集合中
prop.setProperty("tel", "189123**6");
prop.store(new FileOutputStream("config.properties"), null);
//第二个参数是对列表参数的描述,可以给值,也可以给null
System.out.println(prop);
//{qq=123***, tel=189123**6, username=wha***}
}
}