IO简介
什么是IO
-
当程序需要读取数据源的数据时,就会通过IO流对象开启一个通向数据源的流,通过这个IO流对象的相关方法可以顺序读取数据源中的数据
-
程序运行需要的数据的获取需和外部系统进行通信,外部系统可能是文件、数据库、其他程序、网络、IO设备等
-
输入(Input):可以让程序从外部系统获取数据(核心含义是“读”,读取外部数据)
-
输出(Output):程序输出数据给外部系统从而可以操作外部系统(核心含义是“写”,将数据写出到外部系统)
-
java.io包给我们提供了相关的API,实现了对所有外部系统的输入输出操作
什么是数据源
常见数据源:文件、数据库、其他程序、内存、网络、IO设备
包括:
1.源设备(为程序提供数据,一般对应输入流)
2.目标设备(程序数据的目的地,一般对应输出流)
什么是流
流是一个抽象的、动态的概念,是一连串连续动态的数据集合
- 按流的方向分:输入流、输出流
- 按处理的数据单元分:字节流(以字节为单位获取数据)、字符流(以字符为单位获取数据)
- 按处理对象不同分:节点流(可以直接从数据源或目的地读写数据)、处理流(不直接连接数据源或目的地,也包装流)
对于输入流来说,通过流将数据源中的数据输送到程序中
对于输出流来说,通过流将程序中的数据输送到目的地的数据源中
Java中四大IO抽象类
InputStream
此抽象类是表示字节输入流的所有类的父类,它是一个抽象类,不可以实例化,数据的读取由它的子类来实现
常用方法:
int read(): 读取一个字节的数据,并将字节的值作为int类型返回(0-255之间的一个值),如果未读出字节则返回-1(返回值为-1表示读取结果)
void close(): 关闭输入流对象,释放相关系统资源
OutputStream
此抽象类是表示字节输出流的所有类的父类,输出流接收输出字节并将这些字节发送到某个目的地
常用方法:
void write(int n): 向目的地中写入一个字节
void close(): 关闭输出流对象,释放相关系统资源
Reader
用于读取的字符流抽象类,数字单位为字符
常用方法:
int read(): 读取一个字符的数据,并将字符的值作为int类型返回(0-65535之间的一个值),如果未读出字符返回-1(返回值为-1表示读取结束)
void close(): 关闭流对象,释放相关系统资源
Writer
用于输出的字符流抽象类,数据单位为字符
常用方法:
void write(int n): 向输出流中写入一个字符
void close(): 关闭输出流对象,释放相关系统资源
IO流入门案例
代码示例:
package mianxiangduixiang;
import java.io.FileInputStream;
public class IO_Text {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//创建字节输入流对象
fis = new FileInputStream("d:/a.txt");
int s1 = fis.read(); //打印输入的一个字符a对应的ascii码值97
int s2 = fis.read();
int s3 = fis.read();
int s4 = fis.read();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
}catch (Exception e){
e.printStackTrace();
}finally {
if (fis!=null){
try {
fis.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
/*结果为:
97
98
99
-1
*/
代码的改进(不用考虑文件里有多少字符,可以通过循环全部输出):
package mianxiangduixiang;
import java.io.FileInputStream;
public class IO_Text_improvement {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//创建字节输入流对象
fis = new FileInputStream("D:/a.txt");
StringBuilder stringbuider = new StringBuilder();
int temp = 0;
while ((temp = fis.read())!=-1){
System.out.println(temp);
stringbuider.append((char)temp); //强制类型转化为char
}
System.out.println(stringbuider.toString());
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fis != null){
fis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
/*运行结果为:
97
98
99
abc
*/
File类的使用
File类的作用
File类是Java提供的针对磁盘中的文件或目录转换对象的包装类,一个File对象可以代表一个文件或目录,File对象可以实现获取文件和目录属性等功能,可以实现对文件和目录的创建,删除等功能
File类操作目录与文件的常用方法
-
针对文件操作的方法
createNewFile() //创建新文件
delete() //直接从磁盘上删除
exists() //查询磁盘中的文件是否存在
getAbsolutePath() //获取绝对路径
getPath() //获取文件名,相当于调用了一个toString方法
isFile() //判断是否是文件
length() //查看文件中的字节数
isHidden() //测试文件是不是一个隐藏文件
-
针对目录操作的方法
exists() //查询目录是否存在
isDirectory() //判断当前路径是否为目录
mkdir() //创建单级目录
mkdirs() //创建多级目录
getParentFile() //获取当前目录的父级目录
list() //返回一个字符串数组,包含目录中的文件和目录的路径名
listFiles() //返回一个File数组,表示用此抽象路径名表示的目录中的文件
通过File来操作文件的代码示例:
package mianxiangduixiang;
import java.io.File;
public class FileDemo01 {
public static void main(String[] args)throws Exception {
//创建File对象
File file = new File("D:/aa.txt"); /* 我们一旦把这个路径和文件名放到这个file对象中,
那么这个file对象表示的就是这个文件的对象 */
System.out.println(file.createNewFile());
}
}
//createNewFile()的使用
package mianxiangduixiang;
import java.io.File;
public class FileDemo01 {
public static void main(String[] args)throws Exception {
//创建File对象
File file = new File("D:/aa.txt");
System.out.println(file.createNewFile());
System.out.println(file.exists());
}
}
/*运行结果为:
false
true
此前已经创建了a.txt,所有再次创建返回false
true为查询file成功,返回true
createNewFile()的使用和exists()的使用
*/
通过File操作目录的代码示例:
package mianxiangduixiang;
import java.io.File;
public class FileDemo02 {
public static void main(String[] args) {
//创建File对象
File file = new File("d:/a");
System.out.println(file.mkdir());
}
}
//mkdir()的使用
常用流对象
文件字节流
FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像,视频,文本文件),Java也提供FileReader专门读取文本文件;FileOutputStream提供字节的方式写数据到文件中,适合所有类型的文件,Java也提供了FileWriter专门写入文本文件
-
文件字节输入流
代码示例:
package mianxiangduixiang;
import java.io.FileInputStream;
public class FileDemo03 {
public static void main(String[] args) {
FileInputStream fis = null; //创建文件字节输入流对象
try {
fis = new FileInputStream("d:/桌面壁纸01.JPG");
int temp = 0;
while ((temp=fis.read())!=-1){
System.out.println(temp);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fis!=null){
fis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
-
文件字节输出流
代码示例:
package mianxiangduixiang;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class File_Demo04 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("D:/桌面壁纸01.JPG");
//创建文件字节输出流对象
fos = new FileOutputStream("D:/a桌面壁纸.JPG");
int temp=0;
while ((temp=fis.read())!=-1){
fos.write(temp);
}
fos.flush(); //将数据从内存写入到磁盘当中
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
} //读一个字节写一个字节
}
}
通过缓冲区提高读写效率
上述代码通过读一个字节一个字节进行读取也是一个个字节写出,当读写的文件很大时,效率低耗时长
缓冲区:假如你有200斤大米要搬回家,如果用上述方法就相当于一次搬运一粒米,而缓冲区相当于我们定义了一个一定容量的包,可以提高我们搬大米的效率
方法一
通过创建一个指定长度的字节数组作为缓冲区,以此来提高IO流的读写效率,该方式适合读取较大图片时的缓冲区定义。注意:缓冲区的长度一定是2整数幂,一般情况下1024长度较合适(创建一个20斤的包,几次就搬完)
package mianxiangduixiang;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class File_Demo04 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("D:/桌面壁纸01.JPG");
//创建文件字节输出流对象
fos = new FileOutputStream("D:/aa桌面壁纸.JPG");
//创建一个缓冲区,提高读写效率
byte[] buff=new byte[1024]; //数组在实例化时必须提供长度
int temp=0;
while ((temp=fis.read(buff))!=-1){ //将大米放入包里
fos.write(buff,0,temp);
}
while ((temp=fis.read())!=-1){
fos.write(temp);
}
fos.flush(); //将数据从内存写入到磁盘当中
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
} //读一个字节写一个字节
}
}
方法二
通过创建一个字节数组作为缓冲区,数组长度是通过输入流对象的availale()返回当前文件的预估长度来定义的,在读写文件时,是在一次读写操作中完成文件读写操作的,注意:如果文件过大,那么对内存的占用也是比较大的,所有大文件不建议用该方法(创建一个预估200斤的包,一次就可以搬完)
package mianxiangduixiang;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class File_Demo04improvement2 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("D:/桌面壁纸01.JPG");
//创建文件字节输出流对象
fos = new FileOutputStream("D:/123桌面壁纸.JPG");
//创建一个缓冲区,提高读写效率
byte[] buff=new byte[fis.available()];
fis.read(buff);
fos.write(buff);//将数据从内存写入到磁盘当中
fos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
通过字节缓冲流提高读写效率
Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,像是把别的流包装起来,因此缓冲流是一种处理流
当对文件或者其他数据进行频繁的读写操作时,效率低,这时可以用缓冲流提高1效率,缓冲流先将数据缓冲起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地
BufferedInputStream和BufferedOutputStream这两个流是缓冲(以Buffered开头)字节流,通过内部缓存数组来提高操作流的效率
代码示例:
package mianxiangduixiang;
import java.io.*;
public class FileStreamBufferedDemo {
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
fis=new FileInputStream("D:/桌面壁纸01.JPG");
bis=new BufferedInputStream(fis ); //把fis放入,完成流的嵌套(处理流)
fos=new FileOutputStream("D:/bbb.JPG");
bos=new BufferedOutputStream(fos); //把fos放入,完成流的嵌套
int temp=0;
while ((temp=bis.read())!=-1){/*通过缓冲流去读,缓冲流中已经有byte数组,所以不需要用read(byte[] b,int off,int len)
bos.write(temp); 缓冲流中的byte数组长度默认为8192(2的13次方)*/
}
bos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//注意:关闭流顺序按照“后开的先关闭”
if (bis!=null){
bis.close();
}
if (fis!=null){
fis.close();
}
if (bos!=null){
bos.close();
}
if (fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
定义文件拷贝工具类
代码示例:
package mianxiangduixiang;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileCopyTools {
public static void main(String[] args) {
copyFile("D:/桌面壁纸01.JPG","D:/abc.JPG");
}
/**
* 文件拷贝方法
*/
public static void copyFile(String src,String des){
FileInputStream fis=null;
BufferedInputStream bis=null;
FileOutputStream fos=null;
BufferedOutputStream bos=null;
try {
fis = new FileInputStream(src);
bis = new BufferedInputStream(fis); //可以把fis简写代入这一行,同下一行写法
bos = new BufferedOutputStream(new FileOutputStream(des));
int temp=0;
while ((temp = bis.read())!=-1){
bos.flush();
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (bis!=null){
bis.close();
}
if (fis!=null){
fis.close();
}
if (bos!=null){
bos.flush();
}
if (fos!=null){
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
文件字符流
-
文件字符输入流
代码示例:
package IO_Study;
import java.io.File;
import java.io.FileReader;
public class FileReaderDemo {
public static void main(String[] args) {
FileReader frd=null; //先声明,然后在try catch中实例化这个FileReader
try {
//创建文件字符输入流对象
frd = new FileReader("D:/a.txt");
int temp=0;
while ((temp=frd.read())!=-1){
System.out.println(temp); //也可以用System.out.println((char) temp);把内容转化为字符
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (frd!=null){
frd.close();
} //只要是close方法都有可能抛出异常
}catch (Exception e){
e.printStackTrace();
} /* 输出结果为
97
98
99
*/
}
}
}
-
文件字符输出流
代码示例:
如果我们用多个FileWrite来操作同一个文件的话,如果我们没有给定是否追加的指令,它默认为覆盖
package IO_Study;
import java.io.FileWriter;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
FileWriter fw2=null;
try {
//创建字符输出流对象
fw = new FileWriter("aa.txt"); //当没有aa.txt时不用自行创建,FileWriter会帮你创建
fw.write("心如花木,向阳而生"); //需要换行时在生后面加/r/n
fw.flush();
fw2 = new FileWriter("aa.txt");
fw2.write("你好,未来!\r\n");//此时会覆盖,若为fw2.write("你好,未来!\r\n",append:true);则给出了追加指令,不会覆盖
fw2.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (fw!=null){
fw.close();
}
if (fw!=null){
fw2.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用字符流实现文本文件的拷贝处理
注意:char类型的数组长度的定义由自己定义为2的整数幂,不能像字节流中用available()的方法来指定一个大概的长度
package IO_Study;
import java.io.FileReader;
import java.io.FileWriter;
public class FileCopyTools2 {
public static void main(String[] args) {
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader("D:/2.txt"); //字符流创建缓冲区提高效率时创建的是char类型数组
fw=new FileWriter("D;/3.txt");/*代码改为:char[] buffer=new char[1024];
int temp = 0; int temp=0;
while ((temp=fr.read())!=-1){ while((temp=fr.read(buffer))!=-1){
fw.write(temp);
} fw.write(buffer,0,temp);
fw.flush(); }
}catch (Exception e){
e.printStackTrace(); */
}finally {
try {
if (fr!=null){
fr.close();
} //输入流输出流先关闭谁都可以
if (fw!=null);
fw.close();
}catch (Exception e){
e.printStackTrace();
}
}
} //读一个字符写一个字符,效率低
}
字符缓冲流
BufferedReader/BufferedWriter增加了缓存机制,打打提高读写文本的效率
字符输入缓冲流
BufferedReader是针对字符输入流的缓冲对象,提供了更方便的按行读取的方法:readLine();在使用字符流读取文本文件时,我们可以使用该方法以行为单位进行读取。
代码示例:
package IO_Study;
import java.io.BufferedReader;
import java.io.FileReader;
public class BufferedReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
BufferedReader br = null;
try {
fr=new FileReader("D:/a.txt");
br=new BufferedReader(fr); //包装fr
String str="";
while ((str=br.readLine())!=null){ //此时用不等于null判断
System.out.println(str);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (br!=null){
br.close();
}
if (fr!=null){
fr.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
字符输出缓冲流
BufferedWriter是针对字符输出流的缓冲流对象,在字符输出缓冲流中可以使用newLine();方法实现换行处理
代码示例:
package IO_Study;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
public class BufferedWriterDemo {
public static void main(String[] args) {
FileWriter fw=null;
BufferedWriter bw=null;
try {
fw=new FileWriter("D:/电脑上本来没有的文件01");
bw=new BufferedWriter(fw);
bw.write("你好未来!");
bw.write("心如花木");
bw.newLine();
bw.write("向阳而生");
bw.newLine();
bw.write("调用newLine方法后,两部分内容换行");
bw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (bw!=null){
bw.close();
}
if (fw!=null){
fw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
运行结果为:D盘上多出一个文件,文件内容如图所示:
通过字符缓冲流实现文本文件的拷贝
package IO_Study;
import java.io.*;
public class FileCopyTools3 {
public static void main(String[] args) {
copyFile("D:/aa.txt","D:/ab.txt");
}
public static void copyFile(String src,String des){
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new FileReader(src));
bw=new BufferedWriter(new FileWriter(des));
String temp="";
while (((temp=br.readLine())!=null)){
bw.write(temp);
bw.newLine(); //要将读到的行数换行
}
bw.flush(); //输出流的刷新*************
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (br!=null){ //先关闭谁都可以
br.close();
}
if (bw!=null){
bw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
成功将D:/aa.txt的内容复制到D:/ab.txt
通过字符缓冲流为文件中的内容添加行号
代码示例:
package IO_Study;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class LineNumberDemo {
public static void main(String[] args) {
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new FileReader("D:/b.txt"));
bw=new BufferedWriter(new FileWriter("D:/文件内容加行号成功.txt"));
String temp="";
int i=1;
while ((temp= br.readLine())!=null){ //当行读完不为空时继续循环
bw.write(i+","+temp);
bw.newLine();
i++;
}
bw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (br!=null){
br.close();
}
if (bw!=null){
bw.close();
}
} catch (Exception e){
e.printStackTrace();
}
}
}
}
结果可以给文件前面加上行数
转换流
InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流,如下场景:System.in是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符BufferedReader特有的方法readLine(),但是经过观察会发现在创建BufferedReader的构造方法的参数必须是一个reader对象,这时我们的转换流InputStreamReader就派上用场。
而System.out也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的write(String str)方法,所以我们要使用OutputStreamWriter将字节流转化为字符流
通过转换流实现键盘输入屏幕输出
代码示例:
package IO_Study;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class ConvertStream {
public static void main(String[] args) {
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new InputStreamReader(System.in));
bw=new BufferedWriter(new OutputStreamWriter(System.out));
while (true){
bw.write("请输入:");
String input=br.readLine();
if ("exit".equals(input)){
break;
}
bw.write("你输入的是:"+input);
bw.newLine(); //输出第二行时换行
bw.flush();
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (bw!=null){
bw.close();
}
if(br!=null){
br.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
} //有点毛病
通过字节流读取文本文件并添加行号
package IO_Study;
import java.io.*;
public class LineNumberDemo2 {
public static void main(String[] args) {
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new InputStreamReader(new FileInputStream("D:/b.txt")));
bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D/abb.txt")));
String temp="";
int i=1;
while ((temp=br.readLine())!=null){
bw.write(i+","+temp);
bw.newLine();
i++;
}
bw.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (br!=null){
br.close();
}
if (bw!=null){
bw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
} //有点毛病
}
字符输出流
在Java的IO流中专门提供了用于字符输出的流对象PrintWriter,该对象具有自动行刷新缓冲字符输出流,特点是可以按行写出字符串,并且可通过println();方法实现自动换行
代码示例:
package IO_Study;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class SecondDemo {
public static void main(String[] args) {
BufferedReader br=null;
PrintWriter pw=null;
try {
br= new BufferedReader(new InputStreamReader(new FileInputStream("D:aa.txt")));
pw=new PrintWriter("D:aab.txt");
String temp="";
int i=1;
while ((temp=br.readLine())!=null){
pw.println(i+"."+temp);
i++;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (br!=null){
br.close();
}
if (pw!=null){
pw.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
字节数组流
ByteArrayInputStream和ByteArrayOutputStream经常用在需要流和数组之间转化的情况
-
字节数组输出流
说白了,FileInputStream是把文件当做数据源,ByteArrayInputStream则是把内存中的字节数组对象当做数据源
代码示例:
package 字节数组流;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class 字节数组输出流 {
public static void main(String[] args) {
//选择源
byte [] file =null;//不需要源
//选择流 (因为子类有新的方法 所以不能再用父类)
ByteArrayOutputStream output =null;
try {
output = new ByteArrayOutputStream();
//操作
String s ="talk is cheap show me the code";
byte [] n=s.getBytes();//编码
output.write(n, 0, n.length);
output.flush();//刷新
//获取数据
file=output.toByteArray();
System.out.println(new String(file ,0 ,file.length));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {//关闭流
if(null!=output) {
try {
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
-
字节数组输入流
ByteArrayOutputStream流对象是将流中的数据写入到字节数组中
代码示例:
package 字节数组流;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class 字节数组读取流 {
public static void main(String[] args) {
//1.选择源
byte [] a= "talk the cheap show me the code".getBytes();
//2.选择流
InputStream in = null;
in = new ByteArrayInputStream(a);
//3.操作
byte [] flush = new byte [128];
int len =-1;
try {
while((len=in.read(flush))!=-1) {
String str =new String(flush,0,flush.length);
System.out.println(str);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//4.释放资源 为了形式统一,可以不用
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
数据流
数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型
DateInputStream与DataOutputStream提供了可以存取与机器无关的所有Java基础类型数据的方法
-
数据输出流
-
数据输入流
对象流
对象的本质是用来组织和存储数据的,对象本身也是数据。那么能不能将对象存储到硬盘上的文件中呢?能不能将对象通过网络传输到另一个电脑呢?我们可以通过序列化和反序列化来实现这些需求。
Java对象的序列化和反序列化
序列化和反序列化是什么?
当两个进程远程通信时,彼此可以发送各种类型的数据,无论是何种类型的数据都会以二进制序列的形式在网络上传送,比如我们可以通过http协议发送字符串信息;我们也可以在网络上直接发送Java对象,发送方需要把这个Java对象转换为字节序列,才能在网络上传送,接收方则需要把字节序列再恢复Java对象才能正常读取
Java 序列化是指:将对象转化成一个字节序列(二进制数据)的过程
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化
Java 反序列化是指:将一个对象的字节序列恢复成 Java 对象的过程
一个平台中序列化的对象,可以在另一个平台中进行反序列化,因为这个过程是在 JVM 中独立完成的,可以依赖于 Java 的可移植性
涉及到的类
ObjectOutputStream:IO 类,包含序列化对象的方法,writeObject()
ObjectInputStream:IO 类,包含反序列化对象的方法,readObject()
上面两个 IO 流类是高层次的数据库,需要借助文件流进行序列化与反序列化操作。
Serializable ,接口,是一个标志性接口,标识可以在 JVM 中进行序列化,JVM 会为该类自动生成一个序列化版本号。参与序列化与反序列化的类必须实现 Serializable 接口。
serialVersionUID,类属性,序列化版本号,用于给 JVM 区别同名类,没有提供版本号,JVM会默认提供序列化版本号。
transient,关键字,当序列化时,不希望某些属性参与,则可以使用这个关键字标注该属性。
操作基本数据类型
我们前面学到的数据流只能实现对基本数据类型和字符串类型的读写,并不能对Java对象进行读写操作(字符串除外),但是在对象中除了能实现对基本数据类型进行读写操作以外,还可以对Java对象进行读写操作
-
写出基本数据类型
-
读取基本数据类型
操作对象
-
将对象序列化到文件
对象需要实现Serializable接口
public class StudentBean implements Serializable {
······
}
通过ObjectOutputStream的writeObject()方法写入和ObjectInputStream的readObject()方法读取
//存进去
try {
ObjectOutputStream os = new ObjectOutputStream(
new FileOutputStream("D:/student.txt"));
os.writeObject(studentList);
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//读出来
try {
ObjectInputStream is = new ObjectInputStream(
new FileInputStream("D:/student.txt"));
ArrayList<StudentBean> list = new ArrayList<StudentBean>();
list = (ArrayList<StudentBean>) is.readObject();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).toString());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
-
将对象反序列化到内存
随机访问流
RandomAccessFile可以实现两个功能:
- 实现对一个文件做读和写的操作
- 可以访问文件的任意位置,不想其他流只能按先后顺序读取
三个核心方法:
1.RandomAccessFile(String name,String mode)name用来确定文件;mode取r(读)或rw(可读写),通过mode可以确定流对文件的访问权限
2.seek(long a)用来定位流对象读写文件的位置,a确定读写位置距离文件开头的字节数
3.getFilePointer()获得流的当前读写位置
File类在IO中的作用
当以文件作为数据或目标时,除了可以使用字符串作为文件以及位置的指定以外,我们也可以用File类指定
Apache IO包
JDk提供的文件相关的类,但是功能非常的基础,进行复杂操作时需要做大量编程工作。在实际开发中,往往需要你动手编写相关的代码,尤其在遍历目录文件时,非常用到递归,非常繁琐。Apache-commons工具包包提供了IOUtils/FileUtils
FileUtils的常用方法:
- cleanDirectory:清空目录,但不删除目录
- contentEquals:比较两个文件内容是否相同
- copyDirectory:将一个目录内容拷贝到另外一个目录,可以通过FileFilter过滤需要拷贝的文件
- copyFile:将一个文件拷贝到一个新的地址
- copyFileToDirectory:将一个文件拷贝到某个目录
- copyInputStreamToFile:将一个输出流中的内容拷贝到某个文件
- deleteDirectory:删除目录
- deleteQuietly:删除文件
- listFiles:列出指定目录下的所有文件
- openInputSteam:打开指定文件的输入流
- readFileToString:将文件内容作为字符串返回
- readLines:将文件内容按行返回到一个字符串数组中
- size:返回文件或目录的大小
- write:将字符串内容直接写到文件中
- writeByteArrayToFile:将字节数组内容写到文件中
- writeLines:将容器中的元素的toString方法返回的内容依次写入文件中
IOUtils的常用方法:
打开IOUtils的api文档,发现它的方法大部分是重载的
- buffer方法:将传入的流进行包装,变成缓冲流,并可以通过参数指定缓冲大小
- closeQueitly方法:关闭流
- copyLarge方法:将输入流中的内容拷贝到输出流中
- linelterator方法:返回可以迭代每一行内容的迭代器
- contentEquals:比较两个流中的内容是否相同
- copy方法:将输入流中的内容拷贝到输出流中,并可以指定字符编码
- copyLarge方法:将输入流中的内容拷贝到输出流中,适合大于2g内容的拷贝
- readFully方法:将输出流中的所有内容读入到字节数组中
- readLine方法:读入输出流内容的一行
- toBufferedInputStream,toBufferedReader:将输入转为带缓存的输入流
- toByteArray,toCharArray:将输入流的内容转为字节数组、字符数组
- toString:将输入流或数组中的内容转化为字符串
- write方法:向流里面写入内容
- writeLine方法:向流中写入一行内容