字符流和独特流
字符流
1.所有字符流都是处理流封装字节流.
2.基本字符流:可以设置字符编码,解决乱码问题.还可以实现内容追加.
2.1:基本字符输入流:Reader->InputStreamReader
eg:public static void main(String[] args) throws IOException {
//声明流对象
InputStreamReader isr=null;
try {
//1.创建流对象
isr=new InputStreamReader(new FileInputStream("d:\\从前有座灵剑山.txt"),"utf-8");
/*2.用流来读取内容*/
//声明一个数
char[] c=new char[100];
//声明一个变量存读取的长度
int len;
//边读取边输出,返回读取的长度,读取的内容存在数组中了
while ((len=isr.read(c))!=-1) {
//将读取的内容转换字符串输出
String s1=new String(c, 0, len);
System.out.println(s1);
}
System.out.println("读取成功!");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (isr!=null) {
isr.close();
}
}
}
2.2:基本字符输出流:Writer->OutputStreamWriter
eg:public static void main(String[] args) throws IOException {
//声明流对象
OutputStreamWriter osw=null;
try {
//1.创建流对象,可以实现追加内容,设置编码
osw=new OutputStreamWriter(new FileOutputStream("aa\\a2.txt",true), "utf-8");
//2.用流对象向文件中写入内容
osw.write("我是千锋人");
osw.append("我爱千锋");
System.out.println("写入成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//关流
if (osw!=null) {
osw.close();
}
}
}
3.富二代字符流:FileReader,FileWriter,特点:使用方便,不没设置字符编码.
eg:public static void main(String[] args) throws IOException {
//创建流对象
FileReader fr=null;
FileWriter fw=null;
try {
//1.创建流对象
fr=new FileReader("d:\\从前有座灵剑山.txt");
fw=new FileWriter("aa\\a3.txt");
/*2.用流对象调用方法边读取边写入*/
//准备一个数组
char[] c=new char[100];
//声明变量存读取的长度
int len;
//返回读取的长度,读取的内容存到数组中
while ((len=fr.read(c))!=-1) {
//将读取写入到文件中
fw.write(c,0,len);
//刷新
fw.flush();
}
System.out.println("拷贝成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//关流
if (fr!=null) {
fr.close();
}
if (fw!=null) {
fw.close();
}
}
}
4.字符缓冲流
4.1:字符缓冲输出流:BufferedWriter
public static void main(String[] args) throws IOException {
//声明流对象
BufferedWriter bw=null;
try {
//1.创建流对象
//bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("aa\\a4.txt",true), "utf-8"));
bw=new BufferedWriter(new FileWriter("aa\\a4.txt",true));
/*2.用流来向文件中写入内容*/
bw.write("我是\n中国人");
//换行,有两种方式,一种:\n换行,newLine()换行
bw.newLine();
//刷新
bw.flush();
//接着写入
bw.append("我爱中国");
//换行
bw.newLine();
//刷新
bw.flush();
System.out.println("写入成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//关流
if (bw!=null) {
bw.close();
}
}
}
4.2:字符缓冲输入流:BufferedReader
eg:public static void main(String[] args) throws IOException {
//声明流
BufferedReader br=null;
try {
//1.创建流对象
//br=new BufferedReader(new InputStreamReader(new FileInputStream("aa\\a4.txt"), "utf-8"));
br=new BufferedReader(new FileReader("aa\\a4.txt"));
//2.用流对象一行一行的读取内容,前提写入文件中内容要有换行
//声明一个变量存每次读取的内容
String content;
while ((content=br.readLine())!=null) {
//读取一行输出一行
System.out.println(content);
}
System.out.println("读取成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (br!=null) {
br.close();
}
}
}
1.字节流的总结:
2.字符流的总结:
独特流
1.内存流:ByteArrayOutputStream,内存流效率高.内存流关闭无效.
eg:public static void main(String[] args) throws IOException {
//1.创建流对象
ByteArrayOutputStream baos=new ByteArrayOutputStream();
//2.用流对象向内存中写入内容
baos.write("abdefefefeefefefeffef我是中国人,我爱中国.写个50个字符试试,试试就试试.我爱学习,学习爱我.我想静静,静静是谁".getBytes());
System.out.println("内容写入成功");
//3.关流
baos.close();
//第一种:获得内存输出流中数据toByteArray()
byte[] content=baos.toByteArray();
String s1=new String(content);
System.out.println("第一种:"+s1);
//第二种:获得内存输出流中数据toString()
String s2=baos.toString();
System.out.println("第二种:"+s2);
//第三种:获得内存输出流中数据,将数据写入到文件中writeTo()
baos.writeTo(new FileOutputStream("aa"+File.separator+"a1.txt"));
System.out.println("第三种获得数据写入文件成功");
/*第四种:用内存读取流来读取内存中数据*/
//创建流对象
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
//准备一个数组
byte[] b=new byte[1024];
//用流对象调用方法读取数据,返回读取的长度,读取的内容存在数组中
int len;
while ((len=bais.read(b))!=-1) {
//将读取的内容转换字符串输出
String s4=new String(b, 0, len);
System.out.println(s4);
}
System.out.println("第四种读取完毕");
//关流
bais.close();
}
2.打印流:
2.1:字节打印流:PrintStream
eg:public static void main(String[] args) {
//声明流对象
PrintStream ps1=null;
try {
//1.创建流对象
ps1=new PrintStream("aa"+File.separator+"a2.txt");
//2.用流对象向文件中写入内容
ps1.append("第一阶段Java注重规范和语法");
ps1.print("第二阶段Java注重项目综合能力及调试bug能力");
ps1.println("第三阶段Java注重企业级开发,框架使用及团队开发");
ps1.write("第四阶段Java注重分布式和微服务开发,注重项目性能".getBytes());
ps1.printf("%.2f", 3.1415926);
System.out.println("写入成功!");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (ps1!=null) {
ps1.close();
}
}
}
2.2:字符打印流:
eg:public static void main(String[] args) {
//声明流对象
PrintWriter pw=null;
try {
//1.创建流对象
pw=new PrintWriter("aa"+File.separator+"a3.txt");
//2.用流对象向文件中写入内容
pw.append("第一阶段Java注重规范和语法");
pw.print("第二阶段Java注重项目综合能力及调试bug能力");
pw.println("第三阶段Java注重企业级开发,框架使用及团队开发");
pw.write("第四阶段Java注重分布式和微服务开发,注重项目性能");
pw.printf("%.2f", 3.1415926);
pw.printf("%d%%", 50);
System.out.println("写入成功!");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (pw!=null) {
pw.close();
}
}
}
2.3:输出重定向(重新定义一个方向输出):将原来在控制台输出的内容,改变方向,写入到 文件中.
eg:public static void main(String[] args) throws IOException {
//声明一个存原来打印输出流对象
PrintStream p1=System.out;
//输出重定向,输出到文件中
System.setOut(new PrintStream("aa"+File.separator+"a4.txt"));
//输出内容
System.out.append("别无我有");
System.out.print("别有我优");
System.out.println("无所畏惧");
System.out.write("别优我精".getBytes());
System.out.printf("%.3f", 3.141592631415927);
//输出重定向,输出到控制台
System.setOut(p1);
System.out.println("今天中午乌云散去了");
System.out.println("控制台,我又回来了");
}
2.4:输入重定向(重新定义一个方向来接收数据):将原来从控制台接收的数据,改变方向, 从文件中接收数据.
eg:public static void main(String[] args) throws FileNotFoundException {
//声明一个变量存标准输入流
InputStream is=System.in;
//输入重定向,在文件中接收数据
System.setIn(new FileInputStream("aa"+File.separator+"a5.txt"));
//创建Scanner类的对象,输入一个输入流作为参数,调用方法从键盘上接收数据
Scanner input=new Scanner(System.in);
System.out.println("请输入姓名:");
String sname=input.next();
System.out.println("请输入爱好:");
String shobby=input.next();
System.out.println("接收姓名为:"+sname+",爱好为:"+shobby);
//输入重定向,在控制台接收数据
Scanner input2=new Scanner(is);
System.out.println("请输入一句话:");
String word=input2.next();
System.out.println("接收话为:"+word);
}
3.对象流:用来程序间交换数据.
3.1:序列化:将程序(内存)中对象存到磁盘的文件中,叫序列化.
持久化:将内存中短暂存储的数据存长久存储的磁盘上叫持久化.
反序列化:将磁盘上文件中对象读取到程序(内存)中,叫反序列化.
3.2:对象输出流:ObjectOutputStream
注意:对象输出流向文件中写入对象的过程,其实就是序列化.
eg:public static void main(String[] args) throws IOException {
//声明流对象
ObjectOutputStream oos=null;
try {
//1.创建流对象
oos=new ObjectOutputStream(new FileOutputStream("aa"+File.separator+"a6"+File.separator+"a11.txt"));
/*2.用流向文件中写入对象*/
//第一种:写入字符串对象
//String word1="先死后活,死去活来";
//将字符串对象写入文件中
//oos.writeObject(word1);
//第二种:写入自定义的对象
//Student stu1=new Student("赵天慧", 18,"girl");
//将自定义对象写入文件中
//oos.writeObject(stu1);
//第三种:写入多个对象存到集合中,再将集合写入到文件中
//创建一个集合
List<Student> stuList=new ArrayList();
stuList.add(new Student("张三", 11, "man"));
stuList.add(new Student("李四", 21, "man"));
stuList.add(new Student("王五", 31, "man"));
//将对象集合写入文件中
oos.writeObject(stuList);
System.out.println("写入成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (oos!=null) {
oos.close();
}
}
}
3.3:对象输入流:ObjectInputStream
注意:对象输入流将文件中数据读取到程序中过程,其实就反序列化.
eg:public static void main(String[] args) throws IOException {
//声明流对象
ObjectInputStream ois=null;
try {
//1.创建流对象
ois=new ObjectInputStream(new FileInputStream("aa"+File.separator+"a6"+File.separator+"a11.txt"));
/*2.用流来读取文件中对象*/
//第一种:读取一个字符串对象
//Object word2=ois.readObject();
//System.out.println("读取的内容为:"+word2);
//第二种:读取写入的自定义的对象
//Student stu2=(Student) ois.readObject();
//System.out.println(stu2);
//第三种:读取,写入多个对象存到集合中,再将集合写入到文件中
List<Student> stulist2=(List<Student>) ois.readObject();
for (Student stu : stulist2) {
System.out.println(stu);
}
System.out.println("读取完毕");
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (ois!=null) {
ois.close();
}
}
}
3.4:对象输入流读取的方法与对象输出流写入的方法类型要一致,
否则会报错EOFException.(write数据类型()和read数据类型()这两个方法的数据类型要一致)
3.5:只有实现序列化接口java.io.Serializable接口的类的对象,才能(序列化)用对象输 出流写入到文件中.
3.6:版本号错误:local class incompatible: stream classdesc serialVersionUID =
-1243946572963888417, local class serialVersionUID = 3821573340049539149
操作:先将学生类的一个对象进行序列化(用对象输出流存到文件中),再修改学生类,再将现在的学生类反序 列化取数据,就报版本号错误.
原因:学生类只实现序列化接口,但是没有因定化序列化版本号,这样学生类每修改一次就会重新产生一个新 的序列化版本号,如果你用原来序列化版本号对应类的对象存的数据,用新的序列化版本号就取不出数 据.
解决:给每个序列化类固定版本号.
3.7:如果序列化类中属性不想实现序列化,就用static或transient来修饰就可以
3.8:如果想用对象流存多个对象到文件中,可以先将多个对象存在集合中,再把集合存到 文件中.
4.随机流(RandomAccessFile):可读取文件中内容,也可以向文件中写入内容.操作的字节.
断点续传案例:
eg:public static void main(String[] args) throws IOException {
//声明流对象
RandomAccessFile r=null;
RandomAccessFile w=null;
try {
//1.创建流对象
r=new RandomAccessFile("D:"+File.separator+"1.20181126"+File.separator+"4.上课视频"+File.separator+"28.4对象流.mp4", "r");
w=new RandomAccessFile("aa"+File.separator+"a6"+File.separator+"a13.mp4", "rw");
//2.获得断点的位置
Long position=w.length();
System.out.println("断点位置:"+position);
//设置流的初始的读写位置
r.seek(position);
w.seek(position);
/*3.用流实现文件拷贝*/
//准备一个数组
byte[] b=new byte[100];
//声明一个变量存读取的长度
int len;
while ((len=r.read(b))!=-1) {
//每读取一次就写入一次
w.write(b, 0, len);
}
System.out.println("复制成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
//4.关流
if (r!=null) {
r.close();
}
if (w!=null) {
w.close();
}
}
}
5.Properties类:properties配置文件类,按key-value存取值
eg:public static void main(String[] args) throws Exception {
//创建配置对象
Properties p1=new Properties();
//用配置对象调用方法加载配置文件
p1.load(new InputStreamReader(new FileInputStream("src"+File.separator+"jdbc.properties"), "utf-8"));
//用配置对象调用方法获得配置文件中值,通过Key得到value
System.out.println("驱动字符串:"+p1.getProperty("driverUrl"));
System.out.println("连接字符串:"+p1.getProperty("url"));
System.out.println("用户名:"+p1.getProperty("username"));
System.out.println("密码:"+p1.getProperty("password"));
//动态向配置文件对象中写入值,值存在p1对象中
p1.setProperty("stuName", "吴鹏程");
//用配置对象调用方法获得配置文件中值
System.out.println("学生姓名:"+p1.getProperty("stuName"));
}
6.(扩展)jdbc结合流存文件和二进制数据到数据库的表中
6.1:存文本文件到数据库的表中:longText
eg:public static void main(String[] args) throws Exception {
//声明连接对象,执行对象,结果集对象
Connection conn=null;
PreparedStatement state=null;
ResultSet rs=null;
//声明一个变量存要赶往数据库的文本文件
File f1=new File("aa"+File.separator+"从前有座灵剑山.txt");
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
//3.准备Sql语句,?表示占位符,占位符从1开始计数的
String sql="insert into t_book(bookName,bookContent) values(?,?)";
System.out.println("***"+sql);
//4.创建预编译执行对象,将sql语句编译好
state=conn.prepareStatement(sql);
//向sql语句中占位符的位置上传参数,第一个参数是占位符的位置,第二个参数是要传的参数
state.setString(1, f1.getName());
state.setCharacterStream(2, new InputStreamReader(new FileInputStream(f1)), (int)f1.length());
//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
int result=state.executeUpdate();
//6.处理结果
if (result>0) {
System.out.println("插入图书信息成功");
}else {
System.out.println("插入图书信息失败");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//7.关闭对象,释放资源,先开后关
if (rs!=null) {
rs.close();
}
if (state!=null) {
state.close();
}
if (conn!=null) {
conn.close();
}
}
}
6.2:读取数据库的表中的文本文件:
eg:public static void main(String[] args) throws Exception {
//声明连接对象,执行对象,结果集对象
Connection conn=null;
PreparedStatement state=null;
ResultSet rs=null;
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
//3.准备Sql语句,?表示占位符,占位符从1开始计数的
String sql="select bookName,bookContent from t_book";
System.out.println("***"+sql);
//4.创建预编译执行对象,将sql语句编译好
state=conn.prepareStatement(sql);
//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
rs=state.executeQuery();
//6.处理结果
while (rs.next()) {
//获得当前行数据指定列的数据
String bookName=rs.getString("bookName");
//用结果集对象调用字符流的方法得到图书内容
Reader r= rs.getCharacterStream("bookContent");
//声明一个字符写入流
Writer w=new OutputStreamWriter(new FileOutputStream("bb"+File.separator+bookName));
//声明一个数组
char[] c=new char[100];
//用流来读取图书内容,边读取边写入
//声明一个变量存每次读取的长度
int len;
while ((len=r.read(c))!=-1) {
//每读取一次就写入一次
w.write(c,0,len);
}
}
System.out.println("读取成功!");
} catch (Exception e) {
e.printStackTrace();
}finally {
//7.关闭对象,释放资源,先开后关
if (rs!=null) {
rs.close();
}
if (state!=null) {
state.close();
}
if (conn!=null) {
conn.close();
}
}
}
6.3:存二进制数据到数据库的表中:longBlob
eg:public static void main(String[] args) throws Exception {
//声明连接对象,执行对象,结果集对象
Connection conn=null;
PreparedStatement state=null;
ResultSet rs=null;
//声明一个变量存要插往数据库的二进制文件
File f1=new File("aa"+File.separator+"b.jpg");
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
//3.准备Sql语句,?表示占位符,占位符从1开始计数的
String sql="insert into t_image(imgName,imgContent) values(?,?)";
System.out.println("***"+sql);
//4.创建预编译执行对象,将sql语句编译好
state=conn.prepareStatement(sql);
//向sql语句中占位符的位置上传参数,第一个参数是占位符的位置,第二个参数是要传的参数
state.setString(1, f1.getName());
//图片参数类型是二进制类型
state.setBinaryStream(2, new FileInputStream(f1), (int)f1.length());
//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
int result=state.executeUpdate();
//6.处理结果
if (result>0) {
System.out.println("插入图片信息成功");
}else {
System.out.println("插入图片信息失败");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//7.关闭对象,释放资源,先开后关
if (rs!=null) {
rs.close();
}
if (state!=null) {
state.close();
}
if (conn!=null) {
conn.close();
}
}
}
6.4:读取数据库的表中的二进制数据:
eg:public static void main(String[] args) throws Exception {
//声明连接对象,执行对象,结果集对象
Connection conn=null;
PreparedStatement state=null;
ResultSet rs=null;
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
//3.准备Sql语句,?表示占位符,占位符从1开始计数的
String sql="select imgName,imgContent from t_image";
System.out.println("***"+sql);
//4.创建预编译执行对象,将sql语句编译好
state=conn.prepareStatement(sql);
//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
rs=state.executeQuery();
//6.处理结果
while (rs.next()) {
//获得当前行数据指定列的数据
String imgName=rs.getString("imgName");
//用结果集对象调用二进制流的方法得到图片内容
InputStream r= rs.getBinaryStream("imgContent");
//声明一个字符写入流
OutputStream w=new FileOutputStream("bb"+File.separator+imgName);
//声明一个数组
byte[] b=new byte[100];
//用流来读取图片内容,边读取边写入
//声明一个变量存每次读取的长度
int len;
while ((len=r.read(b))!=-1) {
//每读取一次就写入一次
w.write(b,0,len);
}
}
System.out.println("读取成功!");
} catch (Exception e) {
e.printStackTrace();
}finally {
//7.关闭对象,释放资源,先开后关
if (rs!=null) {
rs.close();
}
if (state!=null) {
state.close();
}
if (conn!=null) {
conn.close();
}
}
}
7.装饰者模式:
作用:封装原有类,使其功能更强大.
要实现装饰者模式,注意以下几点内容:
a.装饰者类要实现真实类同样的接口 或继承同样父类.
b.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入)
c.装饰类对象在主类中接受请求,将请求发送给真实的对象(相当于已经将引用传递到了 装饰类的真实对象)
d.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样 的方法,装饰对象可 以添 加一定操作在调用真实对象的方法,或者先调用真实 对象的方法,再添加自己的方法)
独特流的总结:
上一篇: File和字节流