初识 Java IO
- java io可以让我们用标准的读写操作来完成对不同设备的读写数据工作.
- java将IO按照方向划分为输入与输出,参照点是我们写的程序.
- 输入:用来读取数据的,是从外界到程序的方向,用于获取数据.
- 输出:用来写出数据的,是从程序到外界的方向,用于发送数据.
IO,即in
和out
,也就是输入和输出,指应用程序和外部设备之间的数据传递,java将IO比喻为“流”,即:stream 它就像生活中的"电流"\"水流"一样,它是以同一个顺序移动的过程,只不过这里流动的是字节(2进制数据),所以在IO中有输入流和输出流之分,我们理解他们是连接程序与另一端的“管道”,用于获取或发送数据到另一端。一般来说关于流的特性有下面几点:
- 先进先出:最先写入输出流的数据最先被输入流读取到。
- 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(
RandomAccessFile
除外) - 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。
IO流主要的分类方式有以下3种:
- 按数据流的方向:输入流、输出流
输入流:把数据从其他设备
上读取到内存
中的流。
输出流:把数据从内存
中写出到其他设备
上的流。 - 按处理数据单位:字节流、字符流
字节流:以字节为单位,读写数据的流。
字符流:以字符为单位,读写数据的流。 - 按功能:节点流、处理流
节点流:也称为低级流,节点流的另一端是明确的,是实际读写数据的流,读写一定是建立在节点流基础上进行的。
处理流:也称为高级流,,处理流不能独立存在,必须连接在其他流上,目的是当数据流经当前流时对数据进行加工处理来简化我们对数据的该操作。
分类之后对应的超类(超类也就是父类的意思)
1、字节流
文件的世界里一切皆为字节:
我们必须明确一点的是,一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
1.1 字节输出流(OutputStream)
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类(父类),其中定义了读取数据的方法.因此将来不管读取的是什么设备(连接该设备的流)都有这些读取的方法,因此我们可以用相同的方法读取不同设备中的数据。
字节输出流的基本共性功能方法:
1、 public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
2、 public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
3、 public void write(byte[] b):将 b.length个字节从指定的字节数组写入此输出流。
4、 public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从off(索引)开始读取一直到len(索引)个字节结束
5、 public abstract void write(int b) :将指定的字节输出流。
文件流
java.io.FileInputStream和FileOutputStream
文件流是一对低级流,继承自InputStream和OutputStream,用于读写文件数据的流,用于连接程序与文件(硬盘)的"管道",负责读写文件数据。
FileOutputStream类(文件输出流)
OutputStream
有很多子类,FileOutputStream(文件输出流)子类就是其中一个。可以将它简单的理解为将数据直接写出到文件中,在文件流创建时,如果该文件不存在则会自动将其创建(前提是该文件所在的目录必须存在!)
- 构造方法(创建对象):
FileOutputStream(String name) —— 【开发常用】推荐
创建一个向具有指定名称的文件中写入数据的文件输出流
FileOutStream(File file)
创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutStream(File file,boolean append)如果第二个参数为true,表示追加模式,不覆盖;false(默认)表示覆盖模式
追加:指定的文件若存在,则原有数据保留,新写入的数据会被顺序的追加到文件中
注:
创建输出流对象的时候,系统会自动去对应位置创建对应文件,而创建输出流对象的时候,文件不存在则会报FileNotFoundException异常,也就是系统找不到指定的文件异常。
注:
flush()
:刷新缓冲区,流对象可以继续使用。close()
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
package demo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 文件输出流
* java.io.FileInputStream和FileOutputStream。它们继承自InputStream和
* OutoutStream是实际用于读写文件流的。
*/
public class Test {
public static void main(String[] args) {
//目的:向文件fos.dat中写入一个字节
/*
文件输出流常用的构造方法:
(1)FileOutoutStream(File file)
(2)FileOutStream(File file,boolean append)
(3)FileOutputStream(String path)
*/
//创建文件输出流
FileOutputStream fos = null;
File file = null;
try {
//(1)
file = new File("./fos.dat");
fos = new FileOutputStream(file);
//(2)
fos = new FileOutputStream(file,true);
fos = new FileOutputStream("./fos.dat",true);
//(3)【推荐使用】
fos = new FileOutputStream("./fos.dat");
/*
void write(int d)
写出一个字节,写出的内容是给定的int值对应的2进制的“低八位”
fos.write(1);
int型整数1的2进制
VVVVVVVV 低八位
00000000 00000000 00000001
fos.dat文件中的内容:
00000001
*/
fos.write(1);
/*
fos.write(2)
int型整数2的2进制
VVVVVVVV 低八位
00000000 00000000 00000010
fos.dat文件中的内容:
00000001 00000010
*/
fos.write(2);
System.out.println("写出完毕!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//释放资源,流资源用完必须释放!!!
fos.close();
System.out.println(file.length());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 写出字节数组
write(byte[] b)【简单理解为块的文件操作】
每次可以写出数组中的数据:
package demo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* 块写的文件操作
* 通过提高每次读写的数据量,减少实际读写的次数,可以提高读写效率。
* 单字节读写是一种随机读写形式。而一组一组字节的读写是块读写形式。
*/
public class Test {
public static void main(String[] args) throws IOException {
//目的:向文件fos.dat中写入
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// String str = "super idol的笑容都没你的甜,";
//创建一个字节数组
byte[] b = new byte[1024*10];//10kb
/*
00000000 1byte 8位2进制称为1字节
1024byte 1kb
1024kb 1mb
1024mb 1gb
*/
// 写出一个换行, 换行符号转成数组写出
// fos.write("\r\n".getBytes());
// 字符串转换为字节数组
// b = str.getBytes("UTF-8");
b = "我不管,反正公主最可爱".getBytes("UTF-8");
// 写出字节数组数据
// fos.write(b);
fos.write(b,0, b.length);
// 释放资源,流资源用完必须释放!!!
fos.close();
}
}
1.2 字节输入流(InputStrea)
java.io.InputStream
抽象类是表示字节输入流的所有类的超类(父类),可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
字节输入流的基本共性功能方法:
1、 public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
2、 public abstract int read(): 从输入流读取数据的一个字节。
3、 public int read(byte[] b): 该方法返回的int值代表的是读取了多少个字节,读到几个返
回几个,读取不到返回-1
FileInputStream类(文件输入流)
FileInputStream(文件输入流)用于从文件中读取字节
- 构造方法(创建对象):
FileInputStream(File file):
通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的 File对
象 file命名。
FileInputStream(String name):通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路
径名name命名。注:
当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出
FileNotFoundException
。
package demo;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 文件输入流
* end 结尾
* read 读
* 文件字节输入流,用于从文件中读取字节
*/
public class Test {
public static void main(String[] args) throws IOException {
//需求:读取文件fos.dat
//1.创建字节输入流对象用于读取
FileInputStream fis = new FileInputStream("fos.dat");
//2.开始读取
/*
int read()
读取一个字节,并一int型返回。返回的整数中读取的字节部分在该整数2进制的最后8位上
如果返回值为整数-1,则表示流读取到了末尾。对于读取文件而言就是EOF(end of file
文件末尾)
第一次调用read():
int d = fis.read();
fos.dat文件内容
00000001 00000011
^^^^^^^^
读取该字节
返回int值时,2进制样子:
00000000 00000000 00000000 00000001
^^^^^^^^
|-----补充24个0(3字节)-----| 读取的字节
返回的int值d就是上述内容
*/
//需求:需要循环读取文件中的所有内容,直至读完
//定义变量,记录读到的数据
int b;
while ((b= fis.read())!= -1){
System.out.println(b);//打印出字节
// System.out.println((char)b);//如果是字母则输出,文字则会乱码
}
//3.释放资源,流资源用完必须释放!!!
fis.close();
}
}
- 练习:
- 块读写的文件复制操作
int read(byte[] data) 一次性从文件中读取给定的字节数组总长度的字节量,并存入到该数组中。 返回值为实际读取到的字节量。若返回值为-1则表示读取到了文件末尾。
块写操作 void write(byte[] data) 一次性将给定的字节数组所有字节写入到文件中
void write(byte[] data,int offset,int len) 一次性将给定的字节数组从下标offset处开始的连续len个字节写入文件String提供方法: byte[] getBytes(String charsetName) 将当前字符串转换为一组字节
参数为字符集的名字,常用的是UTF-8。 其中中文字3字节表示1个,英文1字节表示1个。package demo; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 块读写的文件复制操作 * 通过提高每次读写的数据量,减少实际读写的次数,可以提高读写效率。 * 单字节读写是一种随机读写形式。而一组一组字节的读写是块读写形式。 */ public class Test { public static void main(String[] args) throws IOException { //使用块读写形式完成文件复制 //创建文件输入流读取原文件 FileInputStream fis = new FileInputStream("fos.txt"); //创建文件输出流写复制文件 FileOutputStream fos = new FileOutputStream("fos.dat"); //追加模式 // FileOutputStream fos = new FileOutputStream("wnwb_cp.exe",true); int len;//记录每次实际读取的字节量 byte[] data = new byte[1024*10];//10kb while((len = fis.read(data))!=-1){ fos.write(data,0,len);//读取多少就写多少 } //释放资源(关闭流) fis.close(); fos.close(); } }
高级流
流连接示意图:
![](https://i-blog.csdnimg.cn/blog_migrate/77a7e5324caa27d06433167274fc6808.png)
缓冲流
java.io.BufferedOutputStream和java.io.BufferedInputStream
缓冲流是一对高级流,作用是提高读写数据的效率
缓冲流内部有一个字节数组,默认长度是8K,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送,通过将数据的读写方式转换为块读写来保证读写效率。
- 构造方法:
public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流,注意参数类型为InputStream。
public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流,注意参数类型为OutputStream。
//构造方式一: 创建字节缓冲输入流【但是开发中一般常用下面的格式申明】
FileInputStream fis= new FileInputStream("fos.txt");
BufferedInputStream bis = new BufferedInputStream(fis)
//构造方式二: 创建字节缓冲输出流【但是开发中一般常用下面的格式申明】
BufferedOutputStream bos = new BufferedOutputStream(fis);
//构造方式三: 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("fos.txt"));
///构造方式四: 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("fos.txt"));
- 使用缓冲流完成文件复制操作:
package demo;
import java.io.*;
/**
* 使用缓冲流完成文件复制操作:
* java.io.BufferedInputStream和java.io.BufferedOutputStream
* 缓冲流,是一对高级流,作用是加快读写效率。
* 缓冲流内部有一个字节数组,默认长度是8K,用来存放字节,每次都是将缓存区存满然后发送,
* 而不是一个字节或两个字节这样发送,通过将数据的读写方式转换为块读写来保证读写效率。
*/
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("ppt.pptx");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("ppt_cp.pptx");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int d;
long start = System.currentTimeMillis();
while((d = bis.read())!=-1){//使用缓冲流读取字节
bos.write(d);//使用缓冲流写出字节
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start)+"ms");
bis.close();//关闭流时只需要关闭高级流即可,它会自动关闭它连接的流
bos.close();
}
}
- 【flush()】方法
解决 缓冲输出流 写出数据时的 缓冲区问题!!!!!!!!!!!!!
通过缓冲流写出的数据会被临时存入缓冲流内部的字节数组,直到数组存满数据才会真实写出一次。package demo; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; /** * 缓冲输出流写出数据的缓冲区问题 */ public class Test { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("bos.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); String line = "奥里给!"; byte[] data = line.getBytes(StandardCharsets.UTF_8); bos.write(data); System.out.println("写出完毕!"); /* 缓冲流的flush方法用于强制将缓冲区中已经缓存的数据一次性写出。 注:该方法实际上实在字节输出流的超类OutputStream上定义的,并非只有缓冲 输出流有这个方法。但是实际上只有缓冲输出流的该方法有实际意义,其他的流实现 该方法的目的仅仅是为了在流连接过程中传递flush动作给缓冲输出流。 */ bos.flush();//冲 //关闭流 bos.close(); } }
字节流结束!下一环节 >>>【 对象流 ( 序列化流 ) 】<<<