目录
第一章 IO概述
1.1 什么是IO
生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了ctrl+s ,可能文件就白白编辑了。当你电脑上插入一个u盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。
我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为 输入input 和输output,即流向内存是输入流,流出内存的输出流。
Java中I/O操作主要是指使用 java.io 包下的内容,用于处理设备之间的数据传输。输入也叫做读取数据,输出也叫做作写出数据,对于数据的输入/输出操作以“流(stream)” 的 方式进行。
1.2 IO的分类
根据数据的流向分为:输入流和输出流
- 输入流input:读取外部数据(磁盘、光盘等存储设备的数据)程序(内存)中的流。
- 输出流output:将程序(内存)数据输出到磁盘、光盘等存储设备中的流。
- 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流
1.3 顶级父类们
由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
第二章 字节流
2.1 一切皆为字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
2.2 字节输出流【OutputStream】
java.io.0utputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
- public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
- public void flush() : 刷新此输出流并强制任何缓冲的输出字节被写出。
- public void write(byte[] b) : 将 b.length字节从指定的字节数组写入此输出流。
- public void write(byte[] b, int off, int len) :从指定的字节数组写入len字节,从偏移量 off开始输出到此输出流。
- public abstract void write(int b):将指定的字节输出流。
package com.hp.tset1;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutPutStreamTest02 {
public static void main(String[] args) throws IOException {
/**
* void write(int b) 一次写一个字节数据
* void write(byte[] b) 一次写一个字节数组数据
* void write(byte[] b, int off, int,len) 一次写一个字节数组的部分数据
* 参数一:数组
* 参数二:索引起始
* 参数三:个数
*/
//1.创建对象
FileOutputStream fos = new FileOutputStream("io\\a.txt");
//2.写出数据
fos.write(97);//a //按照ASCII解析数组 写入文件
fos.write(98);//b
byte[] b ={97,98,99,100,101};
fos.write(b);//abcde
fos.write(b,0,4); //abcd //数组,索引起始,个数
//3.释放资源
fos.close();
}
}
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
2.3 FileOutputStream类
outputstream 有很多子类,我们从最简单的一个子类开始
java.io.FileOutputstream 类是文件输出流,用于将数据写出到文件。
构造方法
- public Fileoutputstream(File file): 创建文件输出流以写入由指定的 File对象表示的文件。
- public FileOutputstream(String name) : 创建文件输出流以指定的名称写入文件。
当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。
构造举例,代码如下:
package com.hp.tset1;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutPutStreamTest01 {
public static void main(String[] args) throws IOException {
/**
* 细节1: 参数是宁符串表示的路径或者是File对象都是可以的
* 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。
* 细节3:如果文件已存在,则会清空文件
*/
//使用File对象创建流对象
File file = new File("atxt"):
FileOutputStream fos = new FileOutputStream(file);
//使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("io\\a.txt");
}
}
写出字节数据
写出字节 : write(int b) 方法,每次可以写出一个字节数据,代码使用演示 :
package com.hp.tset1;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutPutStreamTest01 {
public static void main(String[] args) throws IOException {
//1.创建对象
//写出一段文字 输出 FileOutputstream
FileOutputStream fos = new FileOutputStream("io\\a.txt");
//2.写出数据
fos.write(98);//b
//3.释放资源
fos.close();//解除了资源的占用
}
}
写出换行
Windows系统里,换行符号是r\n 。把以指定是否追加续写了,代码使用演示:
package com.hp.tset1;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutPutStreamTest03 {
public static void main(String[] args) throws IOException {
/**
* 换行写:
* 再次写出一个换行符就可以了
* windows: \r\n
* Linux: \n
* Mac: \r
* 细节:
* 在windows操作系统当中,java对回车换行进行了优化。虽然完整的是\r\n,
* 但是我们写其中一个\r或者\n,java也可以实现换行,因为java在底层会补全。
* 建议:
* 不要省略,还是写全了。
* 续写:
* 如果想要续写,打开续写开关即可开关位置:创建对象的第二个参数默认false: 表示关闭续写,
* 此时创建对象会清空文件手动传递true: 表示打开续写,
* 此时创建对象不会清空文件
*/
//1.创建对象
FileOutputStream fos = new FileOutputStream("io\\a.txt",true);
//2.写出数据
String src1 = "yiyangqianxi";
byte[] b1 = src1.getBytes();
// System.out.println(Arrays.toString(b));
fos.write(b1);
String wrap = "\r\n";
byte[] b2 = wrap.getBytes();
fos.write(b2);
String src2 = "999";
byte[] b3 = src2.getBytes();
fos.write(b3);
//3.释放资源
fos.close();
}
}
2.4 字节输入流【InputStream】
java,io.Inputstream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
- public void close():关闭此输入流并释放与此流相关联的任何系统资源。
- public abstract int read() : 从输入流读取数据的下一个字节。
- public int read(byte[] b) : 从输入流中读取一些字节数,并将它们存储到字节数组b中。
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
package com.hp.test1;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\chenge\\Desktop\\work\\a.txt");
//read()读取一个字节,把当前字符转换成对应的整数返回,如果读取到文件末尾,则返回-1
int read1 = fis.read();
System.out.println(read1);//121
int read2 = fis.read();
System.out.println(read2);//121
int read3 = fis.read();
System.out.println(read3);//113
int read4 = fis.read();
System.out.println(read4);//120
int read5 = fis.read();
System.out.println(read5);//-1
fis.close();
}
}
字节循环输出流
package com.hp.test1;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest01 {
public static void main(String[] args) throws IOException {
//输出流: 把内容的内存输出到文件中(写操作) 输入流: 把文件的内容输入到内存中(读操作)
FileInputStream fis = new FileInputStream("C:\\Users\\chenge\\Desktop\\work\\a.txt");
//字节循环输出流
int len1;
while ((len1 = fis.read()) != -1){
System.out.println((char)len1);//强转
}
fis.close();
}
}
读取多个字节文件
package com.hp.test1;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest04 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\chenge\\Desktop\\work\\a.txt");
byte[] bytes1 = new byte[8];
int ab;
while (( ab = fis.read(bytes1))!= -1){
String str = new String(bytes1, 0, ab);
System.out.println(str);
}
fis.close();
}
}
2.5 FilelnputStream类
java.io.FileInputstream 类是文件输入流,从文件中读取字节。
构造方法
- FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FilelnputStream,该文件由文件系O统中的 File对象 file命名。
- FileInputStream(String name) : 通过打开与实际文件的连接来创建一个FilelnputStream,该文件由文件系统中的路径名 name命名。
当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FleNotFoundException。
构造举例,代码如下 :
package com.hp.tset1;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInPutStreamTest01 {
public static void main(String[] args) throws IOException {
//使用File对象创建流对象
File file = new File("a.txt"):
FileInputStream fis = new FileInputStream(file);
//使用文件名称创建流对象
FileInputStream fis = new FileInputStream ("io\\a.txt");
}
}
2.6 字节流练习: 复制
原理:从已有文件中读取字节,将该字节写出到另一个文件中。
案例:文件的复制
我们把a.txt文件复制
package com.hp.test2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class copyTest01 {
public static void main(String[] args) throws IOException {
/**
* 文件的复制
*/
//定义输入输出流关联文件
FileInputStream fis = new FileInputStream("C:\\Users\\chenge\\Desktop\\work\\a.txt");
FileOutputStream fos = new FileOutputStream("C:\\Users\\chenge\\Desktop\\work\\c.txt");
//使用缓冲区读写
byte[] bytes = new byte[8];
int aa;
while ((aa = fis.read(bytes)) != -1){
fos.write(bytes,0,aa);
}
//4.释放资源 先开的后关闭
fos.close();
fis.close();
}
}
运行效果:
第三章 字符流
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为个中文字符可能占用多个字节存储。所以ava提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
3.1字符输入流【Reader】
java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
- public void close():关闭此流并释放与此流相关联的任何系统资源
- public int read() : 从输入流读取一个字符。
- public int read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中。
-
int read(char[] cbuf,int off,int len) : 将字符读入数组的某一部分。存到数组cbuf 中,从 off 处开始存储,最多读 len 个字符。如果已到达流的末尾,则返回 -1 。否则返回本次读取的字符数。
package com.hp.test1;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public class ReaderTest01 {
public static void main(String[] args) throws IOException {
//1.定义字符输入流:在字节流汉字占三个字节,字符流中汉字占一个字符
FileReader fr = new FileReader("C:\\Users\\chenge\\Desktop\\work\\a.txt");
//每次读取一个字符
int i1 = fr.read();
System.out.println((char)i1);
int i2= fr.read();
System.out.println((char)i2);
//每次读取缓冲区
char[] chars = new char[3];
int i1 = fr.read(chars);//每次至多读取数组长度个字符,把读取到字符存入数组中,返回的是实际读取的字符数
String s1 = new String(chars,0,i1);//截收数组,从第0个索引,截取读收有效字符数长度
System.out.println(s1);
int i2 = fr.read(chars);//每次至多读取数组长度个字符,把读取到字符存入数组中,返回的是实际读取的字符数
String s2= new String(chars,0,i2);
System.out.println(s2);
//3.释放资源
fr.close();
}
}
3.2 FileReader类
java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
1.字符编码: 字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。idea中UTF-8
2.字节缓冲区:一个字节数组,用来临时存储字节数据。
构造方法
- FileReader(File file) : 创建一个新的 FileReader,给定要读取的File对象。
- FileReader(String fileName): 创建一个新的 FileReader,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径。类似于FilelnputStream 。
构造举例,代码如下:
public class FileReaderConstructor throws IOExceptionf{
public static void main(String[] args){
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
//使用文件名称创建流对象
FileReader fr = new FileReader("b,txt");
}
}
3.3 字符输出流【Writer】
java.io.writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
- void write(int c) 写入单个字符。
- void write(char[] cbuf) 写入字符数组。
- abstract void write(char[] cbuf,int off,int len) 写入字符数组的某一部分,off数组的开始索引len写的字符个数。
- void write(String str) 写入字符串。
- void write(String str,int off,int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
- void flush()刷新该流的缓冲。
- void close() 关闭此流,但要先刷新它。
package com.hp.test1;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class WriterTest02 {
public static void main(String[] args) throws IOException {
File f1=new File("C:\\Users\\chenge\\Desktop\\work\\d.txt");
if(!f1.exists()) {
f1.createNewFile();
}
//1.定义字符输出流:
FileWriter fw = new FileWriter(f1);
//2.写出数据
fw.write(97);
fw.write((int)'我');
char[] chars = {'易','烊','千','玺'};
fw.write(chars,0,3);//索引0 取3个
fw.write("姊姊,鑫鑫,玉玉");
fw.flush();//字符流必须刷新缓冲区,才会真正写入磁盘文件中
//3.释放资源
fw.close();
}
}
3.4 FileWriter类
java.io.FileNriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区构造方法。
- Filewriter(File file) : 创建一个新的FileWriter,给定要读取的File对象。
- FileWriter(String fileName): 创建一个新的FileWriter,给定要读取的文件的名称。
public class FileWriterConstructor throws IOExceptionf{
public static void main(String[] args){
// 使用File对象创建流对象
File file = new File("a.txt");
FileWriterfr = new FileWriter(file);
//使用文件名称创建流对象
FileWriterfr = new FileWriter("b,txt");
}
}
续写和换行 : 操作类似于FileOutputStream。
public class FWWrite {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象,可以续写数据
Filewriter fw = new FileWriter("fw.txt" , true);
// 写出字符串
fw.write("姊姊");
// 写出换行
fw.write("\r\n");
// 写出字符串
fw,write("鑫鑫");
// 关闭资源
fw.close();
}
}
关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要 flush 方法了。
第四章 缓冲流
1.1 概述
- 字节缓冲流: BufferedInputStream , BufferedOutputStream
- 字符缓冲流 : BufferedReader , Bufferedwriter
1.2 字节缓冲流
- public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流。
- public Bufferedoutputstream(OutputStream out) : 创建一个新的缓冲输出流。
构造举例,代码如下:
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("io\\a.txt"));
//创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("io\\bbb.txt"));
package com.hp.test5;
import java.io.*;
public class BufferedStreamTest01 {
public static void main(String[] args) throws IOException {
/**
* 需求:
* 利用字节缓冲流拷贝文件
* 字节缓冲输入流的构造方法:
* public BufferedInputStream(InputStream is)
* 字节缓冲输出流的构造方法:
* public BufferedOutputStream(OutputStream os)
*/
//1.创建缓冲流的对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("io\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("io\\bbb.txt"));
//2.循环读取并写到目的地
int c;
while ((c = bis.read()) != -1){
bos.write(c);
}
//2.拷贝(一次读写多个字节)
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
//3.释放资源
bos.close();
bis.close();
}
}
1.3字符缓冲流
构造方法
- public BufferedReader(Reader in):创建一个新的缓冲输入流。
- public BufferedWriter(writer out):创建一个新的缓冲输出流。
构造举例,代码如下:
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
//创建字符缓冲输出流
Bufferedwriter bw = new Bufferedwriter(new FileWriter("bw.txt"));
特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法
- BufferedReader: public String readLine():读一行文字。
- BufferedWriter: public void newLine(): 写一行行分隔符,由系统属性定义符号。
readLine 方法演示,代码如下:
package com.hp.test5;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedStreamTest03 {
public static void main(String[] args) throws IOException {
/**
* 字符缓冲输入流:
* 构造方法:
* public BufferedReader(Reader r)
* 特有方法:
* public String readLine()读一整行
*/
//1.创建字符缓冲输入流的对象
BufferedReader br = new BufferedReader(new FileReader("io\\a.txt"));
//2.读取数据
//细节:
//readLine方法在读取的时候,一次读一整行,遇到回车换行结束 但是他不会把回车换行读到内存当中
// String s = br.readLine();
// System.out.println(s);
//
// String s2 = br.readLine();
// System.out.println(s2);
String lind;
while ((lind = br.readLine()) != null){
System.out.println(lind);
}
//3.释放资源
br.close();
}
}
newLine 方法演示,代码如下:
package com.hp.test5;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedStreamTest04 {
public static void main(String[] args) throws IOException {
/**
*字符缓冲输出流
* 构造方法:
* public BufferedWriter(Writer r)
* 特有方法:
* public void newLine() 跨平台的换行
*/
//1.创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt",true));
//2.写出数据
bw.write("易烊千玺");
bw.newLine();//跨平台的换行
bw.write("红海不倒,我们一直在");
//3.释放资源
bw.close();
}
}
- 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区。
- 当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。
- 向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法 flush()可以强制将缓冲区的内容全部写入输出流。
- 关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流。
- flush()方法的使用:手动将buffer中内容写入文件如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。