JAVA中的IO流(一)
IO流的介绍
I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。这里的输入/输出都是相对的,所以我们一定要明确站位,我们编程中所讲到的输入/输出都是以“内存”的角度看来看的 ~ ~
输入(Input):读取外部数据(磁盘,光盘等存储设备的数据)到程序中;
输出(Output):将程序(内存)数据输出到磁盘,光盘等存储设备中。
JAVA程序中对于数据的输入/输出操作以“流(stream)”的形式进行。
流的分类:
- 按操作数据单位不同分为 : 字节流(8 bit,适合图片,视频等分为本数据);字符流(16 bite,适合文本数据)。
- 按数据流的流向不同分为: 输入流,输出流。
- 按数据流的角色不同分为:节点流(在一个特定的节点读写数据,如FileReader),处理流(对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写,如BufferedReader)。
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutPutStream | Writer |
java.io包下面提供了各种流类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
绿框里面的是“节点流”,其下方的都是“处理流”!其中,深蓝色框中的是我们需要重点掌握的~~
FileReader / FileWriter
这两个类主要用来处理字符流~~
参考代码:
@Test
public void testFileReader1() throws IOException {
FileReader fileReader = null;
try {
//1.实例化file类的对象,指明要操作的文件
File file = new File("src\\test.txt");
//2.提供数据流
fileReader = new FileReader(file);
//3.数据的读入。read();
// 返回读入的一个字符,如果到达文件末尾,返回-1。
int data = fileReader.read();
while(data != -1){
System.out.println((char)data);
data = fileReader.read();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面代码在第三步数据读入那块使用的read()的无参方法,一个字符一个字符的读,下面的参考代码使用的read(char[ ])的重载方法。
参考代码:
public void testFileReader2() throws IOException {
FileReader fileReader = null;
try {
//1.实例化file类的对象,指明要操作的文件
File file = new File("src\\test.txt");
//2.提供数据流
fileReader = new FileReader(file);
//3.数据的读入。read(char[] cbuf);
// 返回读入到char[] cubf 数组中的字符的个数,如果到达文件末尾,返回-1。
char[] cbuf = new char[5];
int len; //用来判断是否读到文件末尾了。
while( (len = fileReader.read(cbuf))!= -1){
for (int i=0;i<len;i++){
System.out.print(cbuf[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
//4.流的关闭操作
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
从内存中写出数据到硬盘文件里。输出操作对应的File不存在,就会自动创建此文件;如果该文件存在时:
如果使用的流构造器是FileWriter(file,true)/FileWriter(file),则是对源文件进行覆盖写入;
如果使用的流构造器是FileWriter(file,true),不会对原文件覆盖,而是在原文件的基础上进行添加!
参考代码:
@Test
public void testFileWriter() throws IOException {
FileWriter fileWriter = null;
try {
//1.提供File类对象,指明需要写出到的文件
File file = new File("test2.txt");
//2.提供FileWriter类的对象,用于数据的写出
fileWriter = new FileWriter(file);
//3.执行写出操作
fileWriter.write("T have a dream!\n");
fileWriter.write("我有一个梦想!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流资源的关闭
fileWriter.close();
}
}
我们可以通过FileReaderhe和FileWriter实现两个文件之间的复制操作!
参考代码:
@Test
public void testFileReaderFileWriter() {
FileReader fileReader = null;
FileWriter fileWriter = null;
try {
//1.创建File类的对象,指明读入和写出文件
File srcFile = new File("src\\test.txt");
File destFile = new File("E:\\JAVA数据结构\\test2.txt");
//不能使用字符流来处理图片等字节数据
// File srcFile = new File("src\\IU.jpg");
// File destFile = new File("src\\IU1.jpg");
//2.创建输入流和输出流的对象
fileReader = new FileReader(srcFile);
fileWriter = new FileWriter(destFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len; //记录每次读入到cbuf数组中的字符的个数
while((len = fileReader.read(cbuf)) != -1){
//每次写出len个字符
fileWriter.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//4.关闭流资源(注意先后顺序!)
if (fileWriter != null){
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fileReader != null){
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream / FileOutputStream
对于非文本数据的传输,我们需要使用字节流来进行操作,其主要方法跟字节流操作是异曲同工~~
参考代码:
@Test
public void test_FileInputStream_FileOutputStream() throws IOException {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//1.创建File类的对象,指明读入和写出文件
File srcFile = new File("src\\IU.jpg");
File destFile = new File("src\\IU2.jpg");
//2.创建输入流和输出流的对象
fileInputStream = new FileInputStream(srcFile);
fileOutputStream = new FileOutputStream(destFile);
//3.数据的读入和写出操作
byte[] buffer = new byte[5];
int len;//记录每次读取的字节的个数
while((len = fileInputStream.read(buffer)) != -1){
fileOutputStream.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源(注意先后顺序!)
if (fileInputStream != null){
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader / BufferedWriter
我们知道,如果直接让文件或程序跟内存进行交互,效率是十分低下的,而通过缓冲流进行交互,能够大大提高效率,缓冲流的主要作用就是提高了效率。
BufferedReader和BufferedWriter主要是用于文本数据的传输~~
参考代码:
@Test
public void testBufferedReader_BufferedWriter(){
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try {
//1.创建File类的对象,指明读入和写出文件
File srcFile = new File("src\\test.txt");
File destFile = new File("src\\test3.txt");
//2.创建输入输出流(两步走——先造节点流,再建缓冲流)
FileReader fileReader = new FileReader(srcFile);
FileWriter fileWriter = new FileWriter(destFile);
bufferedReader = new BufferedReader(fileReader);
bufferedWriter = new BufferedWriter(fileWriter);
//3.数据的读入和写出操作
//方式一:
// char[] buffer = new char[1024];
// int len;
// while((len = bufferedReader.read(buffer)) != -1){
// bufferedWriter.write(buffer,0,len);
// }
//方式二:使用String
String data;
while((data = bufferedReader.readLine()) != null){
bufferedWriter.write(data); //要注意data中不包含换行符,纯单行输出,要自己加换行符
bufferedWriter.newLine();//手动加换行符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//4.关闭流资源(注意先后顺序!)
//要求:先关闭外层的流,在关闭内层的流!
try {
if (bufferedWriter != null){
bufferedWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bufferedReader != null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
下面我们通过两个代码看一下使用字节流和使用缓冲流在非文本数据传输下的速度差异~~
字节流参考代码:
public void copyFile(String srcPath,String destPath){
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//1.创建File类的对象,指明读入和写出文件
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//2.创建输入流和输出流的对象
fileInputStream = new FileInputStream(srcFile);
fileOutputStream = new FileOutputStream(destFile);
//3.数据的读入和写出操作
byte[] buffer = new byte[1024];
/*
这个地方1024的取值是有考究的~~
*/
int len;//记录每次读取的字节的个数
while((len = fileInputStream.read(buffer)) != -1){
fileOutputStream.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源(注意先后顺序!)
if (fileInputStream != null){
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testCopyFile(){
long start = System.currentTimeMillis();
String srcpath = "E:\\JAVA数据结构\\src\\AAA.mp4";
String destPath = "E:\\JAVA数据结构\\src\\BBB.mp4";
copyFile(srcpath,destPath);
long end = System.currentTimeMillis();
System.out.println("AAA视频复制为BBB视频操作花费的具体时间为:"+(end - start)+"ms!");
}
运行结果:
缓冲流参考代码:
public void copyFileWithBuffer(String srcPath,String destPath){
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
//1.创建File类的对象,指明读入和写出文件
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//2.创建输入输出流(两步走——先造节点流,再建缓冲流)
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//3.数据的读入和写出操作
byte[] buffer = new byte[1024];
int len;
while((len = bufferedInputStream.read(buffer)) != -1){
bufferedOutputStream.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//4.关闭流资源(注意先后顺序!)
//要求:先关闭外层的流,在关闭内层的流!
try {
if (bufferedOutputStream != null){
bufferedOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bufferedInputStream != null){
bufferedInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void TestCopyFileWithBuffer(){
long start = System.currentTimeMillis();
String srcpath = "E:\\JAVA数据结构\\src\\AAA.mp4";
String destPath = "E:\\JAVA数据结构\\src\\CCC.mp4";
copyFileWithBuffer(srcpath,destPath);
long end = System.currentTimeMillis();
System.out.println("AAA视频复制为CCC视频操作花费的具体时间为:"+(end - start)+"ms!");
}
运行结果:
InputStreamReader / OutputStreamWriter
转换流:提供了字符流和字节流之间的转换。
InputStreamReader :将InputStream转换成Reader(字节输入流----->字符输入流),相当于一种解码过程。
OutputStreamWriter :将Writer转换成OutputStream(字符输出流----->字节输出流),相当于一种编码过程。
尤其当字节流中的数据都是字符时,转成字符流操作更高效率;而且更多时候,我们使用转换流来处理文件乱码问题,其实质就是类似实现编码和解码功能。
参考代码:
//异常处理还是要使用try-catch-finally语句,此处为了看清逻辑故简洁处理!
@Test
public void test_InputStreamReader() throws IOException {
FileInputStream fileInputStream = new FileInputStream("src\\test.txt");
//参数2指明了字符集,具体使用哪个字符集,取决于test.txt保存时使用的字符集。
//InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); 此处所使用的是默认字符集
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");
char[] cbuf = new char[1024];
int len;
while((len = inputStreamReader.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.println(str);
}
inputStreamReader.close();
}
参考代码:
@Test
/*
综合使用InputStreamReader和OutputStreamWriter
*/
public void test() throws IOException {
File file1 = new File("src\\test.txt");
File file2 = new File("src\\test_GBK.txt"); //会出现乱码现象
FileInputStream fileInputStream = new FileInputStream(file1);
FileOutputStream fileOutputStream = new FileOutputStream(file2);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"gbk");
char[] cbuf = new char[20];
int len;
while((len = inputStreamReader.read(cbuf)) != -1){
outputStreamWriter.write(cbuf,0,len);
}
inputStreamReader.close();
outputStreamWriter.close();
}
运行结果:
DataInputStream / DataOutputStream
数据流:为了方便的操作JAVA语言的基本数据类型和String类的数据,可以使用数据流。
参考代码:
//异常处理还是要使用try-catch-finally语句,此处为了看清逻辑故简洁处理!
@Test
//将内存中的基本数据类型变量和字符串写入到文件中
public void test1() throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("src//test.txt");
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
dataOutputStream.writeUTF("HAHA!Welcom!");
dataOutputStream.flush();//刷新操作
dataOutputStream.writeInt(20);
dataOutputStream.flush();
dataOutputStream.writeBoolean(true);
dataOutputStream.flush();
dataOutputStream.close();
}
@Test
//将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中!
public void test2() throws IOException {
FileInputStream fileInputStream = new FileInputStream("src\\test.txt");
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
//读取的顺序一定要和写入的顺序要一致对应,否则报错!
String name = dataInputStream.readUTF();
int age = dataInputStream.readInt();
boolean isMale = dataInputStream.readBoolean();
System.out.println("name: "+ name);
System.out.println("age: "+ age);
System.out.println("isMale:"+ isMale);
dataInputStream.close();
}
运行结果:
ObjectInputStream / ObjectOutputStream
对象流:将对象的基本数据和图形实现持久存储。
ObjectOutputStream实际是在对流进行序列化操作,ObjectInputStream实际是在对流进行反序列化操作,要实现序列化,必须实现Serializable接口,否则是无法进行序列化和反序列化的,如果对象中的属性加了transient和static关键字的话,则该属性不会被序列化。
参考代码:
import java.io.Serializable;
// 为测试对象流创建一个对象
public class Student implements Serializable{
private static final long serialVersionUID = 6271405124073931152L;
private String name;
private int age;
private transient String info1;
private static String info2;
public Student() {
}
public Student(String name, int age, String info1, String info2) {
super();
this.name = name;
this.age = age;
this.info1 = info1;
this.info2 = info2;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getInfo1() {
return info1;
}
public void setInfo1(String info1) {
this.info1 = info1;
}
public static String getInfo2() {
return info2;
}
public static void setInfo2(String info2) {
Student.info2 = info2;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", info1=" + info1 + "]" + ", info2=" + info2 + "]";
}
}
@Test
public void t1() throws Exception{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("H:\\javaio\\objecttest.txt"));
oos.writeInt(10);
oos.writeObject(new String("测试1"));
oos.close();
}
@Test
public void t2() throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("H:\\javaio\\objecttest.txt"));
int readint = ois.readInt();
Object obj = ois.readObject();
System.out.println(readint);
System.out.println(obj);
ois.close();
}
@Test
public void t4() throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("H:\\javaio\\objecttest.txt"));
Student stu = (Student) ois.readObject();
System.out.println(stu);
ois.close();
}
未完待续……