DataOutputStream和DataInputStream
都属于数据流:可以针对Java基本数据类型的数据进行读写操作
DataOutputStream构造方法
public DataOutputStream(OutputStream out)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
write();
read();
}
//读数据
private static void read() throws FileNotFoundException, IOException {
//读数据
//创建数据输入流对象
DataInputStream dis = new DataInputStream(
new FileInputStream("EDG.txt"));
//读数据
byte b = dis.readByte() ;
int i = dis.readInt() ;
short s = dis.readShort() ;
long l = dis.readLong() ;
char ch = dis.readChar() ;
boolean flag = dis.readBoolean() ;
float f = dis.readFloat() ;
double d = dis.readDouble() ;
//释放资源
dis.close() ;
System.out.println(b);
System.out.println(i);
System.out.println(s);
System.out.println(l);
System.out.println(ch);
System.out.println(flag);
System.out.println(f);
System.out.println(d);
}
//写数据
private static void write() throws FileNotFoundException, IOException {
//创建数据输出流对象
DataOutputStream dos = new DataOutputStream(new FileOutputStream(
"dos.txt"));
//写数据
dos.writeByte(100) ;
dos.writeInt(1000) ;
dos.writeShort(120) ;
dos.writeLong(1000000L);
dos.writeChar('A') ;
dos.writeBoolean(true) ;
dos.writeFloat(12.34F) ;
dos.writeDouble(12.56) ;
//释放资源
dos.close() ;
}
}
ByteArrayInputStream和ByteArrayOutStream(重点)
内存操作流:针对内存的数据进行操作的,程序一结束,这些内存中的数据就消失掉了!
特点:针对小文件进行操作!(聊天室项目中使用它进行发送文件)
ByteArrayOutputStream:
public ByteArrayOutputStream():创建默认的缓冲区大小的内存操作输出流(单位是字节)
成员方法:
public byte[] toByteArray()创建一个新分配的 byte数组(将内存操作输出流对象转换成字节数组)
void reset():重置内存操作输出流
ByteArrayInputStream:内存操作输入流:
public ByteArrayInputStream(byte[] buf):参数数一个字节数组(缓冲数组)
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayStreamDemo {
public static void main(String[] args) throws IOException {
//创建内存操作输出流对象
ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
//写数据
for(int x = 0 ; x <5 ; x ++){
baos.write(("hello"+x).getBytes()) ;
}
/**
* 内存操作流:查看其释放流对象的源码:
* public void close() throws IOException {}
* 并没有具体的关闭流对象,所以此流对象可以不关闭
*/
//关闭资源
// baos.close() ;
//将内存操作输出流对象转换成字节数组
//public byte[] toByteArray()创建一个新分配的 byte 数组(将内存操作输出流对象转换成字节数组)
byte[] buffer = baos.toByteArray() ;
//创建内存操作输入流对象
ByteArrayInputStream bais = new ByteArrayInputStream(buffer) ;
//一次读取一个字节
int by = 0 ;
while((by=bais.read())!=-1){
System.out.print((char)by);
}
//关闭
// bais.close() ;
}
}
打印流:
字节打印流:PrintStream
字符打印流:PrintWriter
打印流特点:
1)在复制文件的,打印流不能操作数据源,只能操作目的地的数据(只能输出数据)
2)打印流可以有自动刷新的功能
3)打印流可以直接针对文本文件进行操作:
什么情况下是直接可以针对文本文件进行操作?
查API的时候,看流中构造方法,只要构造方法的参数有File类或者是String类型,都可以针对文本文件进行操作
FileInputStream
FileOutputStream
FileReader
FileWriter
PrintWriter:
构造方法:
public PrintWriter(String fileName)
import java.io.IOException;
import java.io.PrintWriter;
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符打印流对象
PrintWriter pw = new PrintWriter("pw.txt") ;
//写数据
pw.write("hello") ;
pw.write("world") ;
pw.write("Java") ;
//刷新
pw.flush() ;
//释放资源
pw.close() ;
}
}
PrintWriter:有自动刷新功能:
public PrintWriter(Writer out,booleanautoFlush)
第二个参数指定为true,则启动自动刷新
PrintWriter pw = new PrintWriter(newFileWriter("pw.txt"),true) ;
加入自动刷新功能并且在写数据的时候,使用println():换行
println("hello")
相当于:
pw.write("") ;
pw.newLine() ;
pw.flush() ;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class PrintWriterDemo2 {
public static void main(String[] args) throws IOException {
//创建字符打印流对象
PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true) ;//启动自动刷新功能
//写数据
/* pw.write("hello") ;
pw.write("world") ;
pw.write("java") ;*/
//使用println
//public void println(String x):打印字符串,并且终止该行
pw.println("hello") ;
pw.println("world") ;
pw.println("java") ;
//关闭流资源
pw.close() ;
}
}
复制文件
需求:将当前项目下的DataStreamDemo.java中的内容复制到当前项目下Copy.java文件中
数据源:DataStreamDemo.java---->BufferedReader---->读数据--->readLine()
目的地:Copy.java------>BufferedWriter---->写数据
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
/*//1)封装数据源
BufferedReader br = new BufferedReader(new FileReader("DataStreamDemo.java")) ;
//2)封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java")) ;
//使用BufferedReader中的特有功能读写操作
String line = null ;
while((line=br.readLine())!=null){
//写数据
bw.write(line) ;
//换行
bw.newLine() ;
//刷新流
bw.flush() ;
}
//释放资源
bw.close() ;
br.close() ;*/
//改进
// 1)封装数据源
BufferedReader br = new BufferedReader(new FileReader("DataStreamDemo.java")) ;
2)封装目的地
//创建字符打印流对象,并且启动自动刷新功能
PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true) ;
//读写操作
String line = null ;
while((line=br.readLine())!=null){
//写数据
pw.println(line) ;
}
//关闭资源
pw.close() ;
br.close() ;
}
}
键盘录入的两种方式
1)Scanner类
Scanner sc = new Scanner(System.in) ;
2)使用IO流的形式进行录入数据
BufferedReader br = new BufferedReader(newInputStreamReader(System.in)) ;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class SystemInDemo {
public static void main(String[] args) throws IOException {
//创建一个字节输入流对象
/*InputStream is = System.in ; //标准输入流
//要一次读取一行数据使用BufferedReader的readLine()
//BufferedReader字符缓冲输入流只能针对字符流进行操作
//将当前is对象转换字符流,使用字符转换输入流
InputStreamReader isr = new InputStreamReader(is) ;
//在创建BufferedReader对象
BufferedReader br = new BufferedReader(isr) ;*/
//另一种录入数据的方式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//录入数据
System.out.println("请输入一个字符串:");
String line = br.readLine() ;
System.out.println("您录入的字符串是:"+line);
System.out.println("请输入一个整数数据:");
String s = br.readLine() ;
int a = Integer.parseInt(s) ;//long l = Long.pareLong(s) ;
System.out.println("您输入的整数是:"+a);
}
}
标准输入和输出流
System类中有两个字段:
in:----->InputStream is = System.in ;
out----->PrintStream ps = System.out ;
System.out.println();
import java.io.PrintStream;
public class SystemOutDemo {
public static void main(String[] args) {
//经常使用输出语句
System.out.println("helloworld") ;
System.out.println("helloworld") ;
//字节打印流
PrintStream ps = System.out ;
//字节打印流调用PrintStream类中的方法
// ps.print() ;这个方法不存在
ps.println("javaweb") ;//打印一个字符串数据并且终止当前行
}
}
使用BufferedReader完成了录入数据:
使该流封装字符转换输入流,然后使用字符转换输入流封装字节流
按照上述方式,将BufferedWriter层层封装标准输出流,将数据打印控制台
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
public class SystemOutDemo2 {
public static void main(String[] args) {
/*PrintStream ps = System.out ;
//写入一个分隔符:newLine()是BufferedWriter类中的方法
// BufferedWriter bw = new BufferedWriter(ps) ;
//将字节打印流转换成字符流
OutputStreamWriter osw = new OutputStreamWriter(ps) ;
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(osw) ;*/
BufferedWriter bw = null ;
try {
bw = new BufferedWriter(new OutputStreamWriter(
System.out));
//写数据
bw.write("hello") ;
bw.newLine() ;
bw.write("world") ;
bw.newLine() ;
bw.write("Javaweb") ;
bw.newLine() ;
//刷新
bw.flush() ;
} catch (IOException e) {
e.printStackTrace();
}finally{
//对流对象进行判断
if( bw!=null){
try {
bw.close() ;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5 java.io
RandomAccessFile:随机访问流:此类的实例支持对随机访问文件的读取和写入
不是实际意义上的流,因为它继承自Object类
常用的构造方法:
ublic RandomAccessFile(String name, Stringmode)
参数一:指定该文件的路径
参数二:指定的一种模式:常用的模式:"rw",这种模式是可以读也可以写
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
write();
read();
}
//读数据
private static void read() throws FileNotFoundException, IOException {
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw") ;
读数据
//public long getFilePointer():返回此文件中的当前偏移量。 文件开头的偏移量(以字节为单位
byte b = raf.readByte() ;
System.out.println(b);
System.out.println("getFilePointer:"+raf.getFilePointer());
char ch = raf.readChar() ;
System.out.println(ch);
String str = raf.readUTF() ;
System.out.println(str);
//关闭资源
raf.close() ;
}
//写数据
private static void write() throws FileNotFoundException, IOException {
//创建随机访问流对象
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw") ;
//写数据
raf.writeByte(100) ;
raf.writeChar('a') ;
raf.writeUTF("中国") ;
//关闭资源
raf.close() ;
}
}
SequenceInputStream:合并流(读数据):表示其他输入流的逻辑串联
合并流在复制文件的时候,只能操作数据源,不能操作目的地
之前的操作:
a.txt-->b.txt
c.txt--->d.txt
现在有合并流(将两个文件中的内容复制到另一个文件中)
a.txt+b.txt--->c.txt文件中
构造方法:
public SequenceInputStream(InputStreams1,InputStream s2)
需求:将DataStreamDemo.java和ByteArrayStreamDemo.java两个java文件中的内容复制到
Copy.java文件中
1)数据源:DataStreamDemo.java和ByteArrayStreamDemo.java----->SequenceInputStream----->分别读取第一个和第二个java文件
2)目的地:Copy.java----->BufferedOutputStream---->写数据
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStreampublic class SequenceInputStreamDemo {
public static void main(String[] args) throws IOException {
//分别封装这个两个java文件
InputStream s1 = new FileInputStream("DataStreamDemo.java") ;
InputStream s2 = new FileInputStream("ByteArrayStreamDemo.java") ;
//创建合并流对象
SequenceInputStream sis = new SequenceInputStream(s1, s2) ;
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("Copy.java"));
//一次一个字节数组
byte[] bys = new byte[1024] ;
int len = 0 ;
while((len = sis.read(bys))!=-1){
//写数据
bos.write(bys, 0, len) ;
bos.flush() ;
}
// 释放资源
sis.close() ;
bos.close() ;
}
}
SequenceInputStream的另一种构造方法:复制多个文件
public SequenceInputStream(Enumeration<?extends InputStream> e)
Vector集合中的特有功能:
public Enumeration<E> elements()
之前的操作:
a.txt--->b.txt
c.txt--->d.txt
e.txt--->f.txt
* 现在:a.txt+b.txt+e.txt---->f.txt
需求:将DataStreamDemo.java,ByteArrayStreamDemo.java,以及CopyFileDemo.java将这三个文件中的内容复制到当前项目下:Copy.java文件中
分析:数据源:DataStreamDemo.java,ByteArrayStreamDemo.java,以及CopyFileDemo.java--->SequenceInputStream--->读数据
目的地:Copy.java----->BufferedOutStream---->写数据
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vectopublic class SequenceInputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建一个Vector集合,泛型数据类型<InputStream>
Vector<InputStream> v = new Vector<InputStream>() ;
//封装者三个java文件
InputStream s1 = new FileInputStream("DataStreamDemo.java") ;
InputStream s2 = new FileInputStream("ByteArrayStreamDemo.java") ;
InputStream s3 = new FileInputStream("CopyFileDemo.java") ;
//添加到集合中
v.add(s1) ;
v.add(s2) ;
v.add(s3) ;
//调用特有功能:
//public Enumeration<E> elements()
Enumeration<InputStream> en = v.elements() ;
//创建合并刘对象
SequenceInputStream sis = new SequenceInputStream(en) ;
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("Copy.java"));
//一次读取一个字节数组
byte[] bys = new byte[1024] ;
int len = 0 ;
while((len=sis.read(bys))!=-1){
//写数据
bos.write(bys, 0, len) ;
bos.flush() ;
}
//释放资源
bos.close() ;
sis.close() ;
}
}
7
序列化流:将对象像流的方式或者网络传输中的数据写数据.对象---->流数据:ObjectOutputStream
反序列化:将流数据或者网络传输中的流数据读取出来.流数据---->还原成对象:ObjectInputStream
ObjectOutputStream中的成员方法:
public final void writeObject(Object obj):将obj对象写入到当前的序列化流中
ObjectInputStream中的成员方法:
public final Object readObject():从当前反序列化流中读取一个对象
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo {
public static void main(String[] args) throws Exception {
write() ;
read();
}
//读数据
private static void read() throws IOException, FileNotFoundException,
ClassNotFoundException {
//反序列化:将当前流数据--->对象
//创建一个反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"oos.txt"));
//使用反序列化:将流数据--->对象
Object obj = ois.readObject() ;
//关闭资源
ois.close() ;
System.out.println(obj);
}
//序列化
private static void write() throws IOException {
//创建一个对象
Person p = new Person("高圆圆", 27) ;
//创建一个序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
"oos.txt"));
//写数据
// writeObject(Object obj)
oos.writeObject(p) ;
//释放资源
oos.close() ;
}
}
报异常了:NotSerializableException(没有实现序列化接口的异常)
Serializeable:序列化接口
类通过实现java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化,如果自定义一个类没有实现这个接口,就不能使用
序列化或者是反序列化!如果一个接口中没有字段,没有构造方法,没有成员方法,叫做标记接口
更改了Pereson类中的一个成员变量,重新去反序列化:出现异常:
stream classdesc serialVersionUID =-1389484787812115752,
local class serialVersionUID = -8105095612190351088
如果一个类实现了标记接口:Serializable,那么对应的该类加载的时候,会产生一个ID
Person.class------->id ,假设id=100
成员变量:name和age---->对应一个固定id= 100
后面重新改动了Person类的成员,Person.class---->id = 200 ;name,age-------->id = 200 ;
序列化和反序列化版本号不一致,会出现InvalidClassException
解决这个异常两种方案:
1)要么改动当前某个类中的数据之后,然后重新序列化和反序列化
这种做法不符实实际要求,在实际开发中,可能直接读数据:将流数据--->还原成对象
2)发现黄色警告线,点击它:生成一个固定ID
注意事项:
比如一个类中有很多成员变量,并不想让一些成员变量被序列化,Java提供了一个关键字:
transient:不用被序列化的时候用它修饰
序列化和反序列化考点:
1)将对象--->流数据或者流数据--->对象,该对象所在的类要实现一个标记接口:serializable 多线程有一个关键字:同步机制(synchronized)
2)序列化和反序列化生产的版本Id不一致的时候,会出现异常,所以使用生产随机ID或者固定ID解决
3)transient:修饰的变量不会被序列化...
//如果启用序列化功能,那么必须实现一个接口:Serializable
public class Person implements Serializable{
privatestatic final long serialVersionUID = 1L;
/**
* default Servial ID
*/
生成一个ID
Properties:属性集合类,该类继承自Hashtable<K,V>,该类属于Map集合
Properties 类表示了一个持久的属性集。
Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串(一般情况:它用作配置文件去使用,MySQL或者Oracle中用它做配置文件)
构造方法:
public Properties():创建一个空属性列表
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) {
//创建属性集合类对象
// Properties<String,String> prop = new Properties<String,String>() ;
Properties prop = new Properties() ;
//既然是Map集合怎么添加元素?
prop.put("RNG", "666") ;
prop.put("EDG", "233") ;
prop.put("LGD", "334") ;
//遍历集合
//获取所有的键的集合
Set<Object> keySet = prop.keySet() ;
//增强for遍历
for(Object key :keySet){
Object value = prop.get(key) ;
System.out.println(key+"="+value);
}
}
}
属性集合类:Properties有自己的遍历和添加元素的功能
给属性列表中添加元素:
public Object setProperty(String key,Stringvalue)
public Set<String>stringPropertyNames():获取当前属性列表中所有的键的集合,键值都是String类型
public String getProperty(String key)用指定的键在此属性列表中搜索属性值
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo2 {
public static void main(String[] args) {
//创建属性集合类对象
Properties prop = new Properties() ;
//添加元素
//public Object setProperty(String key,String value)
prop.setProperty("RNG", "666") ;
prop.setProperty("EDG", "233") ;
prop.setProperty("LGD", "334") ;
//遍历属性列表:public Set<String> stringPropertyNames()
Set<String> keySet = prop.stringPropertyNames() ;
for(String key:keySet){
//通过键搜索值
//public String getProperty(String key)
String value = prop.getProperty(key) ;
System.out.println(key+"="+value);
}
}
}
Properties 可保存在流中或从流中加载。
将文件中的数据加载到属性集合中:public void load(Reader reader)
将属性集合中的数据保存到文件中:public void store(Writer writer,String comments)
第二个参数:comments:对当前属性列表的描述
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
myStore();
myLoad() ;
}
//将文件中的数据加载到属性集合中
private static void myLoad() throws IOException {
//public void load(Reader reader)
//创建属性集合类对象
Properties prop = new Properties() ;
= //创建字符输入流对象
FileReader fr = new FileReader("name.txt") ;
//调用方法
prop.load(fr) ;
//释放资源
fr.close() ;
//显示输出
System.out.println(prop);
}
private static void myStore() throws IOException {
//创建属性集合类对象
Properties prop = new Properties();
//给属性集合中添加数据
prop.setProperty("RNG", "666") ;
prop.setProperty("EDG", "233") ;
prop.setProperty("LGD", "334") ;
//将属性列表中的数据保存到文件中
// public void store(Writer writer,String comments)
//创建字符输出流
FileWriter fw = new FileWriter("name.txt") ;
//调用方法
prop.store(fw, "names content") ;
//释放资源
fw.close() ;
}
}
课堂练习
有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”
分析:
1)将user.txt文件中的内容加载到属性集合类中
2)遍历属性列表:获取所有的键的集合:stringPropertyNames(Stringkey );
判断:如果"lisi"这个键中key值相等
修改:setProperty(key,"100");
3)重新将属性集合中的数据写到user.txt中
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;
import java.util.Set;
public class PropertiesTest {
public static void main(String[] args) throws IOException {
//创建属性集合类对象
Properties prop = new Properties() ;
//创建字符输入流对象
Reader r = new FileReader("user.txt") ;
//加载到属性集合中
prop.load(r) ;
//关闭流资源
r.close() ;
//遍历属性列表
Set<String> keySet = prop.stringPropertyNames() ;
for(String key:keySet){
//判断
if("lisi".equals(key)){
//修改
prop.setProperty(key, "100") ;
}
}
//创建字符输出流丢向
Writer w = new FileWriter("user.txt") ;
//调用功能
prop.store(w, "content") ;
//释放资源
w.close() ;
}
}