字节流
一切数据文件(文本 视频 图片)都是以二进制数字的形式存储的,都是一个个的字节,在传输时也是如此。因此字节流可以传输一切数据。在操作流时,无论是什么流对象,实际上底层传输的都是二进制数据。
OutputStream
OutputStream是所有字节输出流的父类,他有5个成员方法。他是一个抽象类,因此使用时应该创建他的子类
FileOutputStream
向文件中写入数据
class FileOutputStream extends OutputStream
构造方法
常用的写入方法
关闭流的方法
例子
/*File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);*/
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write(65);//write(int b) 将指定的字节写入此文件输出流。 文件中存储A
fos.write("你好".getBytes());//write(byte[] b) 将 b.length个字节从指定的字节数组写入此文件输出流。 文件中存储你好
fos.write("你好".getBytes(),0,"你好".getBytes().length/2);//write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。 文件中存储 你
fos.close();
如何追写
上述例子write方法的输出是覆盖。如果要实现追加写则需要在创建fos时使用带append参数的构造器。
当append为ture时,如果已经存在文件则会直接在文件后面追加写。
如何换行
os.write("你好\r\n".getBytes());
os.write("你好\r\n".getBytes());
os.write("你好\r\n".getBytes());
InputStream
所有字节输入流的父类
FileOutputStream
从文件中读取数据
构造方法
读取方法
释放资源方法
例子
read()方法
读取到末尾会返回-1,否则返回读取到的数据
//FileInputStream fis = new FileInputStream(new File("a.txt"));
FileInputStream fis = new FileInputStream("a.txt");
int len = 0;
while((len = fis.read()) != -1){
System.out.print((char)len);
}
fis.close();
read(byte[] b)方法
返回值为读取到的有效字节个数,读到结尾则返回-1
//FileInputStream fis = new FileInputStream(new File("a.txt"));
FileInputStream fis = new FileInputStream("a.txt");
int len = 0;
byte[] bytes = new byte[3];
while((len = fis.read(bytes)) != -1){
System.out.println(new String(bytes,0,len));
}
fis.close();
但是字节流读取中文时,可能会出现问题。如果用GBK或者utf-8等来存储中文(占2个字节 utf-8占3个)。那么很容易造成中文字符被拆开读取,这样就会出现中文字符不能正确读取的情况。此时就要用到字符输入/输出流
字符流
Reader
Reader字符输入流,是一个抽象类,是所有字符输入流的父类
FileReader
文件字符输入流
构造器
读取
与文件字节输入流相比除了一个是以字节为单位,一个是以字符为单位外,完全一致。
//FileReader fr = new FileReader(new File("a.txt"));
FileReader fr = new FileReader("a.txt");
int len;
while((len = fr.read()) != -1){
System.out.print((char)len);
}
fr.close();
Writer
是所有字符输出流的父类。
FileWriter
文件字符输出流。把内存中的字符数据写入到文件中。
构造器
写入
字符输出流与字节输出流的区别之一为,文件字符输出流会先把字符写入内存(转换成字节)然后再写入到文件中(flush方法或close方法)
FileWriter fw = new FileWriter("a.txt");
fw.write('1');
fw.write("234");
fw.write("567",0,2);
fw.write(new char[]{'8','9','0'});
fw.write(new char[]{'a','b','c'},1,2);
//将内存中的数据写入文件,不关闭连接
//fw.flush();
//将内存中的数据写入文件 然后 关闭连接
fw.close();
文件字符输出流与文件字节输出流的追加写和换行完全一致。
追加写:构造器append为true
换行\r\n
异常处理
FileReader fr = null;
try{
fr = new FileReader("a.txt");
int len;
while((len = fr.read()) != -1){
System.out.print((char)len);
}
}catch (IOException e){
System.out.println(e);
}finally {
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
或者
try(FileReader fr = new FileReader("a.txt")){
int len;
while((len = fr.read()) != -1){
System.out.print((char)len);
}
}catch (IOException e){
System.out.println(e);
}
属性集 Properties
Properties是唯一一个和IO流相结合的集合。
可以使用Properties集合中的方法store,把集合中的临时数据持久化到硬盘中存储
可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
属性列中每个键及其对应的值都是一个字符串,properties集合是一个双列集合,key和value默认都是字符串。
操作方法
相当于map的put方法
相当于map的get方法
相当于map的keySet方法
例子
Properties prop = new Properties();
prop.setProperty("1","周一");
prop.setProperty("2","周二");
prop.setProperty("3","周三");
prop.setProperty("4","周四");
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
System.out.println(key+":"+prop.getProperty(key));
}
保存到硬盘
如果用OutputStream则不能写入中文
如果用 Writer则可以写入中文
参数comments为注释,用来解释保存的文件是来干什么的,不能使用中文一般使用空字符串""
例子
Properties prop = new Properties();
prop.setProperty("1","周一");
prop.setProperty("2","周二");
prop.setProperty("3","周三");
prop.setProperty("4","周四");
OutputStream os = new FileOutputStream("b.txt");
prop.store(os,"");
Writer writer = new FileWriter("a.txt");
prop.store(writer,"");
writer.close();
从硬盘读取(键值对文件)
传入Inputstream时,不能读取中文
传入Reader时能读中文
注意:
键值对文件中,键与值的连接符可以使用=和空格或者其他符号
键值对文件中,可以使用#进行注释
键值对文件中,不用加引号
例子
Properties prop = new Properties();
prop.load(new FileReader("a.txt"));
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
System.out.println(key+":"+prop.getProperty(key));
}
缓冲流
无论是字节缓冲流还是字符缓冲流都相当于提供了一个数组缓冲区,然后就可以一次读取多个数据,从而提高效率。
BufferedOutputStream
字节输出缓冲流
根据他的父类可知他继承来的方法
构造方法
size指定缓冲流中缓冲区的大小
例子
FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("你好".getBytes());
//将缓冲区中的数据刷新到磁盘中
//bos.flush();
//将缓冲区中的数据刷新到磁盘中,然后关闭流
bos.close();
对BufferedOutputStream的操作与对FiileOutputStream类的操作完全一致。只有一点不同,之前字节输出流如果不调用close或者flush的话数据也会写入磁盘。但是缓冲流不行。必须要flush或者close
关闭时只需要关闭缓冲流就行,他会自动关闭基本流
BufferedInputStream
字节缓冲输入流
使用方法和FileInputStream相同
例子
FileInputStream fis = new FileInputStream("a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
int len;
while((len = bis.read())!=-1){
System.out.println((char)len);
}
BufferedWriter
字符缓冲输出流
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。
可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
提供了一个newLine()方法,它使用平台自己的系统属性line.separator定义的行分隔符概念。 并非所有平台都使用换行符(’\ n’)来终止行。 因此,调用此方法来终止每个输出行,因此优选直接写入换行符。
使用方法可以参考上面其他的缓冲流得出。
例子
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
for (int i = 0;i < 22;i++){
bw.write("你好");
bw.newLine();
}
bw.close();
BufferedReader
字符缓冲输入流
从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。
可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
通常,由读取器做出的每个读取请求将引起对底层字符或字节流的相应读取请求。 因此,建议将BufferedReader包装在其read()操作可能昂贵的读取器上,例如FileReaders和InputStreamReaders
构造方法
相比于字符输入流多了个
可以读取一行数据(通过终止符: 换行(\n) 回车(\r) 回车换行(\r\n)判断是否为行尾)
这一行数据不包括终止符
如果已经到达流的结尾则返回null
例子
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
String str;
while((str = br.readLine())!=null){
System.out.println(str);
}
转换流
FileReader只能读取idea默认编码格式的文件,否则会乱码
转换流原理
可以读取/写入任意格式的文件
OutPutStreamWriter
写的转换流
OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
构造器
charsetName为使用的字符编码名称,不区分大小写。默认为idea的编码(UTF-8)
例子
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),"GBK");
osw.write("你好");
osw.close();
InputStreamReader
读的转换流
构造器
例子
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "GBK");
char[] chars = new char[10];
int len = 0;
while((len = isr.read(chars)) != -1){
System.out.println(new String(chars));
}
序列化流和反序列化流
ObjectOutouStream
对象序列化流,静态变量不能被序列化 (static)
如果想要一个实例变量不被序列化,则可以使用transient(瞬态变量)关键字
ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
只有支持java.io.Serializable接口的对象才能写入流中。 每个可序列化对象的类被编码,包括类的类名和签名,对象的字段和数组的值以及从初始对象引用的任何其他对象的关闭。
方法writeObject用于将一个对象写入流中。 任何对象,包括字符串和数组,都是用writeObject编写的。 多个对象或原语可以写入流。 必须从对应的ObjectInputstream读取对象,其类型和写入次序相同。
构造器
Student stu = new Student("sea", 21, new int[]{1, 2, 3});
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
oos.writeObject(stu);
oos.close();
ObjectInputStream
对象反序列化流
ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象。
ObjectOutputStream和ObjectInputStream可以分别为与FileOutputStream和FileInputStream一起使用的对象图提供持久性存储的应用程序。 ObjectInputStream用于恢复先前序列化的对象。 其他用途包括使用套接字流在主机之间传递对象,或者在远程通信系统中进行封送和解组参数和参数。
ObjectInputStream确保从流中创建的图中的所有对象的类型与Java虚拟机中存在的类匹配。 根据需要使用标准机制加载类。
只能从流中读取支持java.io.Serializable或java.io.Externalizable接口的对象。
方法readObject用于从流中读取对象。 应使用Java的安全铸造来获得所需的类型。 在Java中,字符串和数组是对象,在序列化过程中被视为对象。 读取时,需要将其转换为预期类型。
构造器
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
Object o = ois.readObject();
System.out.println(o);
ois.close();
、
serialVersionUID
序列化运行时将每个可序列化的类与称为serialVersionUID的版本号相关联,该序列号在反序列化期间用于验证序列化对象的发送者和接收者是否已加载与该序列化兼容的对象的类。 如果接收方加载了一个具有不同于相应发件人类的serialVersionUID的对象的类,则反序列化将导致InvalidClassException 。 一个可序列化的类可以通过声明一个名为"serialVersionUID"的字段来显式地声明它自己的serialVersionUID,该字段必须是静态的,最终的,类型是long :
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; 如果可序列化类没有显式声明serialVersionUID,则序列化运行时将根据Java(TM)对象序列化规范中所述的类的各个方面计算该类的默认serialVersionUID值。 但是, 强烈建议所有可序列化的类都明确声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息非常敏感,这可能会因编译器实现而异,因此可能会在反InvalidClassException化期间导致InvalidClassException的InvalidClassException。 因此,为了保证不同Java编译器实现之间的一致的serialVersionUID值,一个可序列化的类必须声明一个显式的serialVersionUID值。 还强烈建议,显式的serialVersionUID声明在可能的情况下使用private修饰符,因为这种声明仅适用于立即声明的类 - serialVersionUID字段作为继承成员无效。 数组类不能声明一个显式的serialVersionUID,所以它们总是具有默认的计算值,但是对于数组类,放弃了匹配serialVersionUID值的要求。
PrintStream
打印流(字节打印流)
只负责数据的输出,不负责读取。不会抛出IOException
构造器
他多的方法为
void void println(任意类型) //能换行
void void print(任意类型) //不换行
例子
PrintStream ps = new PrintStream("a.txt");
ps.print("1");
ps.print("1");
ps.println(1.1);
ps.println(1.1);
ps.println(1.1);
ps.close();
System.out.println("控制台");
PrintStream ps = new PrintStream("a.txt");
System.setOut(ps);
System.out.println("文件");