说明: 最近学习到java的输入输出流,这里总结一下。其一,希望对于初学者有一定的帮助;其二,也是为了巩固一下自己所学的知识。那么java流是个撒东西?我们用它来做什么?下面我都会尽量的清楚。
准备工作 1.: 流是什么?为什么要用流?
- 流是什么?
其实流一个很形象的词,现在请你想象这样一副画面:一条巨大河流,里面的滔滔江水正往东流去。其实java里面所讲的流的概念跟现实生活中的河流是极其相似的。计算机里面的所有文件归根结底就是一些字节或者字符的集合,但是这些字节或者字符 并不是没有顺序的,而是按照一定的顺序排列起来的,这种有序列的字节或者字符其实就是流。- 为什么要用流?
之所以要使用流,主要就是为了把所需要的数据资源,从源地址输送到目的地址。
当我们想要把程序内部的数据存储到文件(硬盘)中;或者想把文件里面的数据读到程序内部;或者想实现文件的拷贝;又或者实现java数据的持久化(java数据直接保存到文件中)都将会用到流。
总的来说就是为了实现对文件的操作,所以才使用流。
准备工作 2.: 输入输出流的简单说明
java的输入输出流按照最小的传输单元区分就只有字节流和字符流
而且每种流都是以成对的方式存在的,即输入和输出流。字符流和字节流流下面又分了不一样的流,但是这里只要我们掌握了其中一种流(字节流或者字符流),其他的跟它的使用方法基本相同,所以这里只挑一些常用的仔细介绍一下。
准备工作 3.: File
File创建的对象表示的是一个目录或者文件的路径,而不是文件本身。
例如:File file = new File("E:/yangxi");
这个File里面有很多的方法,可以判断文件或或目录是否存在,判断是文件还是目录等等
准备工作 4.: FileFilter(可以作为了解,不知道也不影响后面的学习)
这是一个文件过滤器,可以选择自己想要的文件的类型。使用的时候创建一个类继承FileFilter并实现里面的accept()方法。然后在获取文件列表的时候将该类的对象传过来就可以实现文件的过滤。
一. 字节流
- 什么是字节流:
以字节为最小的传输单位的输入输出流。一般情况下,我们使用字节流来传输二进制文件(音频,视频,图片…)。所有字节流都继承自InputStream和OutputStream这两个抽象类。
- 分类:
1.直接字节流
*直接操作一个一个的字节,也就是以字节为最小的传输单位,进行数据传输。
你可以脑补一下:抗震救灾的路上,所有的运送物资的官兵每人扛着一袋物资(一个字节),运送到灾区。其实这样运送物资(数据),物资当然是能达到目的地,但是显而易见,真的是很浪费财力,物力,而且效率也很低。有人可能会问,既然这样,我们为什么还要学习直接字节流?我告诉你,宝宝,当然是有必要的,因为后面所要学到的流底层其实还是字节。只是我们不用在一个一个直接操作字节了。学习直接字节流(虽然可能实际开发中不怎么用),但是有助于帮我们掌握流其中的原理。*
- FileInputStream: 直接字节输入流,输入输出是相对程序内部(内存)而言的,当从文件(硬盘)读到程序内部时,采用输入流,继承自InputStream抽象类。
- FileOutStream: 直接字节输出流,同样是相对程序内存而言,当程序内部要将数据输出到文件时,采用输出流,继承自OutputStream抽象类。
// - 使用直接字节输入流读数据:
FileInputStream fiStream = null;
File file = new File("helloWorld.java");//使用相对路径(该文件当前所在的目录)
StringBuffer stringBuffer = new StringBuffer();
try {
fiStream = new FileInputStream(file);
int i = fiStream.read(); //读一个字节 返回字节,如果返回-1 表示读取结束
while (i!=-1) {
char c = (char)i;
stringBuffer.append(c);
i = fiStream.read();
}
System.out.println(stringBuffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fiStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//使用直接字节输出流写数据
FileOutputStream fileOutputStream = null;
String str = "i am append char";//准备需要写入到文件的数据
File file = new File("yangqian.txt");写入文件的路径
try {
fileOutputStream = new FileOutputStream(file);
for (int i = 0; i < str.length(); i++) {
int c = str.charAt(i);//char转int会自动转
fileOutputStream.write(c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2.字节缓冲流
现在让我们继续回想上面灾区运送物资的实例,现在兵哥哥们有了一辆大卡车,他们每次把大卡车装满或者物资没了,只装了半卡车才运送过去。很明显效率这样提高了很多。而我们的字节缓冲流中,就是比直接字节流多了一个缓冲区,就像上面的大卡车,每次等缓冲区装满了或者数据就剩下这么多,并且缓冲流被 close()的时候,才会将数据推送到目的地。
- bufferedInputStream: 字节缓冲输入流 ,输入输出的概念前面已经讲了,这里就不在累赘了
- BufferedOutputStream:字节缓冲输出流
// > - 使用字节缓冲流拷贝文件或目录:
public void copyEveryThing(File fromFile, File toFile) {
FileInputStream fi = null;
FileOutputStream fo = null;
BufferedInputStream fis = null;
BufferedOutputStream fos = null;
if (fromFile.exists()) {
if (fromFile.isFile()) {
try {
toFile.createNewFile();
fi = new FileInputStream(fromFile);
fo = new FileOutputStream(toFile);
fis = new BufferedInputStream(fi);
fos = new BufferedOutputStream(fo);
int input = fis.read();// 返回的是读取的byte;
while (input != -1) {
fos.write(input);
input = fis.read();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
toFile.mkdir();
File[] rootFiles = fromFile.listFiles();
for (File file : rootFiles) {
copyEveryThing(file, new File(toFile.toString() + "/"
+ file.getName()));
}
}
}
}
3.数据流
是用来传递java数据的,数据流只能用来传递java基本数据类型的数据和String类型的数据。同样也分为DataInputStream和DataOutputStream。
下面展示使用数据流读写java数据:
//使用DataOutputStream 写数据到文档
private static void writeObject() {
List< Student> stuLsitsList = new ArrayList<Student>();
Student stu1 = new Student("1001", "王五", 11, 99);
Student stu2 = new Student("1001", "王五", 11, 99);
Student stu3 = new Student("1001", "王五", 11, 99);
Student stu4 = new Student("1001", "王五", 11, 99);
stuLsitsList.add(stu1);
stuLsitsList.add(stu2);
stuLsitsList.add(stu3);
stuLsitsList.add(stu4);
try {
dataOutput = new DataOutputStream(new FileOutputStream("E:/student"));
for (Student student : stuLsitsList) {
dataOutput.writeUTF(student.getStuNo());
dataOutput.writeUTF(student.getStuName());
dataOutput.writeInt(student.getStuAge());
dataOutput.writeDouble(student.getStuScore());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
dataOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//使用DataInputStream 读数据到程序内部
public static void readObject(){
List< Student> getStudents = null;
try {
datainputStream = new DataInputStream(new FileInputStream("E:/student"));
getStudents = new ArrayList<Student>();
//循环读出写在内存里面的student对象里面的属性;当读写完毕抛出异常
while (true) {
String nuString = datainputStream.readUTF();
String nameString = datainputStream.readUTF();
int age = datainputStream.readInt();
double score = datainputStream.readDouble();
Student student = new Student(nuString, nameString, age, score);
getStudents.add(student);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
}finally{
try {
datainputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Iterator<Student> iterator = getStudents.iterator();
while (iterator.hasNext()) {
Student student = (Student) iterator.next();
System.out.println(student);
}
}
4.对象流(序列化流)
同样是用来传输java数据,但是与数据流不同的是,对象流存java的引用类型的数据。也就是说对象流可以存储java任意类型的Object,但是这个对象所对应的类必须实现Serializable(序列化)接口;如果直接将一个集合对象持久化(存到到文档中),集合里面存储的对象也必须实现Serializable接口。
使用方法和数据流是一模一样,但是一定记得,所持久化的对象所对应的类必须实现序列化接口。
二. 字符流
什么是字符流
就是以字符为最小的传输单位传输数据,一般用来传输文档文件,但是需要注意乱码的问题。其实字符流的底层也是字节流,只是由于java的迭代更新,越来越好,java底层程序员为了传递数据更加方便才封装了个字符流给我们用。
所有的字符流都继承自 Reader和Writer两个类。字符流分类
1.直接字符流:
直接传输传输字符,但是与直接字节流不同的是,直接字符流底层使用了字节缓冲区,并不是像直接字节流那样一个一个字节的传输,而是等待字节缓冲区满了,或者数据就剩下一点,并且流被close()的时候,就会讲数据源推送到目的地。
- FileReader:直接字符输入流
- FileWriter:直接字符输出流
简单演示一下,如何使用直接字符输出流;
File toFile = new File("F:/构造方法练习.txt");
String string = "2131asad2131313333333333333333";
FileWriter fieWriter = null;
try {
fieWriter = new FileWriter(toFile);
fieWriter.write(string);
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fieWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2.字符缓冲流
字符缓冲流跟字节缓冲流类似,也是有一个缓冲区,但是这个缓冲区是字符缓冲区,不是直接字符流里面的字节缓冲区。
使用方法跟字节缓冲流是一样的,只是多比字节流多封装了一层。这里不再copy代码了,读者还请自己尝试。
3.转换流(字节流转换为字符流)
我们知道,字节流也是可以传递文档数据的,但是并没有字符流传递文档数据那么爽。 因为字节直接传递的是字节,所以利用字节流传递字符文件,就会出现一些问题;又或者,当我们做项目多人合作时,你获取的就是一个字节流但是又想做字符操作,这个时候就可以使用转换流将字节流转换成字符流。
- InputStreamReader:
- OutputStreamWriter:
简单演示一下使用 字节输入流转换为字符输入流:
// 创建输入流
FileInputStream fis = new FileInputStream("D:/yangxi/test.txt");
InputStreamReader is = new InputStreamReader(fis);
BufferedReader bis = new BufferedReader(is);
// 从输入流读取数据
while (bis.ready()) {
int c = bis.read();
System.out.print((char)c);
}
// 关闭输入流
bis.close();
is.close();
fis.close();
} catch (IOException e) {
}