IO概述
1.说明流的三种分类方式
流向:输入流、输出流
数据单位:字节流、字符流
流的角色:节点流、处理流
2.写出4个IO流中的抽象基类,4个文件流,4个缓冲流
抽象基类 | 节点流(或文件流) | 缓冲流(处理流的一种) |
InputStream | FileInputStream | BufferedInputStream |
OutputStream | FileOutputStream | BufferedOutputStream |
Reader | FileReader | BufferedReader |
Writer | FileWriter | BufferedWriter |
InputStreamReader :父类是Reader
3.字节流与字符流的区别与使用情境
字节流:处理非文本文件——read(byte[] buffer)/read()
字符流:处理文本文件——read(char[] chuf)/read()
4.使用缓冲流实现a.jpg文件复制为b.jpg文件的操作
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.jpg")));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("b,jpg")));
Byte[] buffer = new Byte[1024];
Int len;
While((len = bis.read(buffer)) != -1){
Bos.read(buffer,0,len);
}
bos.close();
Bis.close();
//此时的异常应该使用try - catch - finally处理
5.转换流是哪两个类,分别的作用是什么?请分别创建两个类的对象
InputStreamReader:将输入的字节流转换为输入的字符流。解码
OutputStreamWriter:将输出的字符流转换为输出的字节流。编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(a.txt),"utf-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(a.txt),"gbk");
1.FileReader/Filewriter的使用:
1.1 FileReader的使用
/*
将day09下的heLlo.txt文件内容读入程序中,并输出到控制台
说明点:
1.read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
2.异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
3.读入的文件一定要存在,否则就会报FiLeNotFoundException.
*/
@Test
publicvoidtestFileReader1(){
FileReaderfileReader=null;
try{
//1.File类的实例化
Filefile1=newFile("hello.txt");
//2.FiLeReader流的实例化
fileReader=newFileReader(file1);
//3.读入的操作
char[]cbuf=newchar[5];
intlen;
while((len=fileReader.read(cbuf))!=-1){
//方式一:
//错误的写法:
//for(inti=0;i<cbuf.length;i++){
//System.out.print(cbuf[i]);
//}
//正确的写法:
//for(inti=0;i<len;i++){
//System.out.print(cbuf[i]);
//}
//方式二:
//错误的写法:对应方式一错误的写法
//Strings=newString(cbuf);
//System.out.print(s);
//正确的写法:
Stringstring=newString(cbuf,0,len);
System.out.print(string);
}
}catch(IOExceptione){
e.printStackTrace();
}finally{
//4.资源的关闭
if(fileReader!=null){
try{
fileReader.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
1.2 Filewriter的使用
/*
从内存中写出数据到硬盘的文件里。
说明:
1.输出操作,对应的File可以不存在的。
2.
FiLe对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
File对应的硬盘中的文件如果存在:
如果流使用的构造器是:FileWriter(file,false)/_FiLeWriter(file):对原有文件的覆盖
如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容
*/
@Test
public void testFileWriter() {
FileWriter fileWriter = null;
try {
//1.提供File类的对象,指明写出到的文件
File file = new File("hello1.txt");
//2.提供FiLewriter的对象,用于数据的写出
fileWriter = new FileWriter(file, true);
//3.写出的操作
fileWriter.write("I have a dream !");
fileWriter.write("You have a dream !".toCharArray());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//4.流资源的关闭
if (fileWriter != null) {
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.3 文本文件的复制:
@Test
public void testFileReaderFileWriter() {
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File desFile = new File("hello2.txt");
//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(desFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int lenth;
while ((lenth = fr.read(cbuf)) != -1) {
fw.write(cbuf, 0, lenth);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.FileInputStream / Fileoutputstream的使用:
* 1.对于文本文件( .txt,.java,.c,.cpp),使用字符流处理
* 2.对于非文本文件(.jpg,.mp3, .mp4,.avi,.doc,.ppt,...),使用字节流处理
/*
实现对图片的复制
*/
@Test
public void FileInputOutputStreamTest() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//
File srcFile = new File("m.jpg");
File desFile = new File("m1.jpg");
//
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(desFile);
//复制的过程
byte[] buffer = new byte[5];
int len;
while ((len = fis.read(buffer))!= -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放流资源
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
【注意】
相对路径在IDEA和Eclipse中使用的区别?
IDEA:
如果使用单元测试方法,相对路径基于当前的Module的。如果使用main()测试,相对路径基于当前Project的。
Eclipse:
单元测试方法还是main(),相对路径都是基于当前Project的。
缓冲流的使用:
1.缓冲流涉及到的类:
* BufferedInputStream
* BufferedOutputStream
* BufferedReader
*Bufferedwriter
2.作用:
作用:提供流的读取、写入的速度
提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb
3.典型代码
3.1使用BufferedInputStream和BufferedOutputStream:处理非文本文件
public class BufferedTest {
@Test
public void BufferedStreamTest() {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File("m.jpg");
File destFile = new File("m2.jpg");
//2.造流
//2.1造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节:读取、写入
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer))!= -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
// fos.close();
// fis.close();
}
}
3.2 使用BufferedReader和Bufferedwriter:处理文本文件
/*
使用BufferedReader和BufferedWriter实现文本文件的复制
*/
@Test
public void testBufferedReaderBufferedWrite(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件和相应的流
br = new BufferedReader(new FileReader(new File("dbcp.txt")));
bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));
//读写操作
//方式一:使用char[]数组;
// char[] cbuf = new char[1024];
// int len;
// while ((len = br.read(cbuf)) != -1){
// bw.write(cbuf,0,len);
// bw.flush();
// }
//方式二:使用String
String data;
while ((data = br.readLine()) != null){
//方法一:
// bw.write(data+"\n");//data中不包含换行符
//方法二:
bw.write(data);//data中不包含换行符
bw.newLine();//提供换行的操作
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if (br != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
转换流的使用
1.转换流涉及到的类:
* 1.转换流:属于字符流
* InputStreamReader:将一个字节的输入流转换为字符的输入流
解码:字节、字节数组--->字符数组、字符串
* OutputStreamWriter:将一个字符的输出流转换为字节的输出流
编码:字符数组、字符串--->字节、字节数组
注意:编码决定解码
2.作用:
提供字节流和字符流之间的转换
3.图示:
4.典型实现:
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("dbcp.txt");
// InputStreamReader isr = new InputStreamReader(fis);
// 参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.print(str);
}
isr.close();
}
5.说明:
文件编码的方式(比如:GBK ),决定了解析时使用的字符集也只能是GBK ) 。
其他流的使用
1.标准的输入输出流:
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
修改默认的输入和输出行为:
System类的setIn(InputStream is) / setout(PrintStream ps)方式重新指定输入和输出的流
2.打印流:
PrintStream 和Printwriter
说明:
提供了一系列重载的print()和println()方法,用于多种数据类型的输出System.out返回的是PrintStream的实例
3.数据流:
DataInputstream 和 DataoutputStream
作用:用于读取或写出基本数据类型的变量或字符鞫
对象流的使用
- 对象流:objectInputStream和0bjectOutputStream
- 作用:
ObjectOutputStream:内存中的对象--->存储中的文件、通过网络传输出去(序列化)
ObjectInputStream:存储中的文件、通过网络接收过来--->内存中的对象(反序列化)
- 对象的序列化机制:
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。II当其它程序获取了这种二进制流,就可以恢复成原来的
Java对象
- 序列化代码实现:
/*
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去,使用ObjectOutputStream实现
*/
@Test
public void testObjectOutputStream(){
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("我爱北京! "));
oos.flush();
oos.writeObject(new Person("马",23));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 反序列化代码实现:
/*
反序列化:将磁盘文件中的对象还原为内存中的一个java对象使用objectInputStream来实现
*/
@Test
public void testObjectInputStream(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String)obj;
Object o = ois.readObject();
Person p = (Person) o;
System.out.println(str);
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 实现序列化的对象所属的类需要满足:
1.需要实现接口: Serializable
2.当前类提供一个全局常量: serialVersionUID
3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所属性也必须是可序列化的。(默认情况下, 基本数据类型可序列化)
补充:0biectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
RandomAccessFile的使用
- 随机(任意)存取文件流:RandomAccessFile
- 使用说明:
* 1. RandomAccessFile直接继承java.long.object类,实现了DataInput和DataOutput接口
* 2. RandomAccessFile即可以作为一个输入流,也可以作为一个输出流。(同一个类,但不是同一个对象)
* 3. 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建如果写出到
* 的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
* 4. 可以通过相关的操作,实现RandomAccessFile"插入"数据的效果
典型代码1:复制操作
@Test
public void test1(){
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
raf1 = new RandomAccessFile(new File("m.jpg"),"r");
raf2 = new RandomAccessFile(new File("m3.jpg"),"rw");
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1){
raf2.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf1 != null){
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (raf2 != null){
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
典型代码2:插入操作
/*
使用RandomAccessFiLe实现数据的插入效果
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf = new RandomAccessFile(new File("hello.txt"),"rw");
raf.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有与数据到StringBuilder数组。
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while ((len = raf.read(buffer)) != -1){
builder.append(new String(buffer,0,len));
}
raf.seek(3);
raf.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf.write(builder.toString().getBytes());
}
Path、Paths、Files的使用
- NIO的使用说明:
1.1 Java NlO(New lO,Non-Blocking lO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java lO API。
1.2 NIO与原来的IO同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于通道的
IO操作。
1.3 NIO将以更加高效的方式进行文件的读写操作。
1.4 随着JDK 7的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为NIO.2。
- Path的使用---jdk7提供
2.1Path的说明:Path替换原有的File类。
2.2如何实例化:
2.3常用方法:
3 .Files工具类---jdk7提供
3.1作用:
操作文件或文件目录的工具类
3.2常用方法:
二、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
1.流的分类
*1.操作数据单位:字节流、字符流
* 2.数据的流向:输入流、输出流
*3.流的角色:节点流、处理流
图示:
2.流的体系结构
说明:红框对应的是Io流中的4个抽象基类。
篮筐的流需要重点关注
3.重点说明的几个流结构
抽象基类 | 节点流(或文件流) | 缓冲流(处理流的一种) |
InputStream | FileInputStream(read(byte[]buffer)) BufferedInputStream(read(byte[]buffer)) |
OutputStream | FileOutputStream(write(byte[]buffer,0,len)) BufferedOutputStream(write(byte[]buffer,0,len)) |
Reader | FileReader(read(char[]cbuf)) BufferedReader(read(char[]cbuf)/readLine()) |
Writer | FileWriter(write(char[]cbuf,0,len)) BufferedWriter(write(char[]cbuf,0,len)) |
4.输入、输出的标准化过程
4.1输入过程
①创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
②创建相应的输入流,将File类的对象作为参数,传入流的构造器中
③具体的读入过程:
创建相应的byte[]或char[]。
④关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。
4.2输出过程
①创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)
②创建相应的输出流,将File类的对象作为参数,传入流的构造器中
③具体的写出过程:
write(char[]/byte[] buffer,0,1en)
④关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。