1.IO流
1.1 IO流的概念
我们把数据的传输,可以看成一种数据的流动,按照流动的方向,以内存为基准,分为输入input和输出output,即流向内存的是输入流,流出内存的叫输出流。
java中I/O操作主要是指使用java.io包下内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做写出数据。
1.2 IO的分类
根据数据的流向分为:输入流和输出流
输入流:把数据从其他设备读取到内存中的流。
输出流:把数据从内存中写出到其他设备上的流。
根据格局数据的类型分为:字节流和字符流。
字节流:以字节为单位,读写数据的流
字符流:以字符为单位,读写数据的流、
1.3 IO的流向说明
硬盘——>内存 输入
硬盘<——内存 输出
1.4 顶级父类
输入流 | 输出流 | |
字节流 | 字节输入流 InputStream | 字节输出流 OutputStream |
字符流 | 字符输入流 Reader | 字符输出流 Write |
2.字节流
一切数据在存储时,都是以二进制数字的形式保存的,都是一个一个的字节,那么数据在传输时也是一样的。因此字节流可以传输任意文本数据。在操作流的时候,我们要明确,无论使用什么样的流对象,底层传输的始终是二进制数据。
2.1 字节输出流【OutputStream】
java.io.OutputStream 抽向类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
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) :将指定的字节输出流。
2.2 FileOutputStream类
OutputStream 有很多子类,java.io.FileOutputStream类就是其子类,表示文件输出流,用于将数据写出到文件。
构造方法:
public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。
public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。
构造文件输出流对象。
public class Demo {
public static void main(String[] args) throws FileNotFoundException {
//创建file对象
File file=new File("aaa.txt");
//以file对象为参数,构造文件输出流对象
FileOutputStream fos=new FileOutputStream(file);
//以文件名字构造文件流对象
FileOutputStream fos1=new FileOutputStream("b.txt");
}
}
写出字节数据
1.写出字节:
Write(int b)方法,每次可以写出一个字节数据。
public class Demo {
public static void main(String[] args) throws IOException {
//以文件名字创建文件流对象
FileOutputStream fos=new FileOutputStream("D:\\javawrite\\src\\Demo\\day06\\a.txt");
//写出数据
fos.write(97);
fos.write(98);
fos.write(99);
//关闭资源
fos.close();
}
}
这段代码就会在D:\javawrite\src\Demo\day06中先创建一个文件a.txt ,然后创建一个输出流对象,依次写入a b c 三个字节。
2.写出字节数组
write(byte[] b),每次可以写出数组中的数据。
public class Demo {
public static void main(String[] args) throws IOException {
//以文件名字创建文件流对象
FileOutputStream fos=new FileOutputStream("D:\\javawrite\\src\\Demo\\day06\\c.txt");
//字符串转换成字节数组
byte[] b="路飞".getBytes();
//写出字节数组数据
fos.write(b);
//关闭资源
fos.close();
}
}
这段代码就会在D:\javawrite\src\Demo\day06中先创建一个文件c.txt ,然后创建一个输出流对象,写出字节数组数据“路飞"。
3.写出指定长度字节数组;
write(byte[] int off,int len):每次写出从off索引开始,len个字节。
public class Demo {
public static void main(String[] args) throws IOException {
//以文件名字创建文件流对象
FileOutputStream fos=new FileOutputStream("D:\\javawrite\\src\\Demo\\day06\\d.txt");
//字符串转换成字节数组
byte[] b="abcde".getBytes();
//写出字节数组数据
fos.write(b,2,2);
//关闭资源
fos.close();
}
这段代码就会在D:\javawrite\src\Demo\day06中先创建一个文件d.txt ,然后创建一个输出流对象,写出指定长度的字节数组,从”abcde“的第二个索引开始,长度为2,就是”cd“.
数据追加续写:
上述的代码演示,每次程序运行,创建输出流对象,都会清空文件中的数据,重写写入,可是我们怎么样才能保留目标文件中的数据,然后在新添加数据呢?
public FileOutputStream(File file, boolean append) : 创建文件输出流以写入由指定的 File对象表示的文件。
public FileOutputStream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。
这两个构造方法,参数都需要传递一个boolean类型的值,true表示追加数据,false辨识清空原数据。这样创建的输出流对象,就可以指定是否追加续写了。
public class Demo {
public static void main(String[] args) throws IOException {
//以文件名字创建文件流对象
FileOutputStream fos=new FileOutputStream("D:\\javawrite\\src\\Demo\\day06\\a.txt",true);
//字符串转换成字节数组
byte[] b="abcde".getBytes();
//写出字节数组数据
fos.write(b,2,3);
//关闭资源
fos.close();
}
}
原来的a.txt中有字符创“cd”,经过上述代码后,变为“cdcde”,表示可以续写。
写出换行:
在Windows系统中,换行符号是\r\n。
public class Demo {
public static void main(String[] args) throws IOException {
//以文件名字创建文件流对象
FileOutputStream fos=new FileOutputStream("D:\\javawrite\\src\\Demo\\day06\\a.txt",true);
//字符串转换成字节数组
byte[] words = {97,98,99,100,101};
//遍历数组
for (int i = 0; i < words.length; i++) {
fos.write(words[i]);
fos.write("\r\n".getBytes());
}
fos.close();
}
}
在文件a中的输出结果为 a b c d e 每个都是换行的。
回车符 \r 和换行符 \n
回车符: 回到一行的开头(return) 换行符:下一行(newline)
各个操作系统中的换行:
Windows系统中,每行皆为都是回车+换行,即\r\n
Lunix系统中,每行的结尾值换行,即\n
Max系统里,每行的结尾是回车,即\r
2.3 字节输入流
java.io.InputStream抽象类是表示字节输入流的所有类的父类,可以读取到字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close():关闭此输入流并释放与此相关联的任何系统资源。
public abstract int read():从输入流读取数据的下一个字节。
public int read(byte[] b):从输入流中读取到一些字节数,并将它们存储到字节数组bzhogn .
2.4 FileInputStream类
java.io.FileInputStream类是文件输入流,从文件中读取字节。
构造方法;
FileInputStream(File file) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file 命名。
FileInputStream(String name) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
当创建一个流对象,必须传入一个文件路径,该路径下如果没有文件,就会抛出异常FileNotFoundException。
public class Demo {
public static void main(String[] args) throws IOException {
//使用File对象创建输入流对象
File file=new File("D:\\javawrite\\a.txt");
file.createNewFile();
FileInputStream fis=new FileInputStream(file);
//使用文件名创建输入流对象
FileInputStream fis1=new FileInputStream("b.txt");
}
}
读取字节数据:
1.读取字节:read方法,每次可以读取一个字节数据,提升为int类型,读取到文件末尾,返回-1.
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名创建输入流对象
FileInputStream fis=new FileInputStream("b.txt");
//读取数据返回一个字节
int read=fis.read();
System.out.println((char) read);
read=fis.read();
System.out.println((char) read);
read=fis.read();
System.out.println((char) read);
read=fis.read();
System.out.println((char) read);
//读取到末尾,返回-1
read=fis.read();
System.out.println(read);
//关闭资源
fis.close();
}
}
a
b
c
d
-1
文件夹b.txt中原有数据abcd ,读取结果如程序所示。
循环改进读取的方式:
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名创建输入流对象
FileInputStream fis=new FileInputStream("b.txt");
int read;
while((read=fis.read())!=-1){
System.out.println((char) read);
}
//关闭资源
fis.close();
}
}
a
b
c
d
注:read读取的字节,自动会提升为int类型,操作完毕后,一定要释放资源
2.使用字节数组读取:
read(byte[] b),每次读取到b长度的字节到数组中,返回读取到的有效字节个数,读取到末尾是,返回-1.
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名创建输入流对象
FileInputStream fis=new FileInputStream("b.txt");// 文件中为abcde
//定义变量,作为有效个数
int len;
//定义字节数组,作为装字节数据的容器
byte[] b=new byte[2];
//循环读取
while ((len=fis.read(b))!=-1){
//每次读取后,吧数组变成字符串打印
System.out.println( new String(b));
}
//关闭资源
fis.close();
}
}
ab
cd
ed
我们可以看出最后有一个错误数据ed,是因为最后一次读取,只能读取到一个字节e,在数组中,上次读取的数据就没有被完全替代,因此要通过len,获取有效字节。
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名创建输入流对象
FileInputStream fis=new FileInputStream("b.txt");
//定义变量,作为有效个数
int len;
//定义字节数组,作为装字节数据的容器
byte[] b=new byte[2];
//循环读取
while ((len=fis.read(b))!=-1){
//每次读取后,吧数组变成字符串打印
System.out.println( new String(b,0,len));//len表示每次读取的有效个数
}
//关闭资源
fis.close();
2.5 字节流练习:图片复制;
复制原理图解:
public class Demo {
public static void main(String[] args) throws IOException {
//1创建输出流对象
//先指定数据源
FileInputStream fis=new FileInputStream("D:\\1.jpg");
//指定复制的mdd
FileOutputStream fos=new FileOutputStream("copy_1.jpg");
//读写数据
//2.1 定义数组
byte[] b=new byte[1024];
//2.2 定义长度
int len;
//2.3循环读取
while ((len=fis.read(b))!=-1){
fos.write(b,0,len);
}
//3.关闭资源
fis.close();
fos.close();
}
}
复制的文件都会存在java程序所在的目录下。
3.字符流
当使用字节流去读文件文本时,可能会遇到一个问题,就是遇到中文字符时,可能不会完全显示,因为中文字符可能会占用多个字节,因此java中提供了一些字符流,以字符为单位读写数据,用来专门处理文本文件。
3.1 字符输入流【Reader】
java.io.Reader抽象类是表示读取字符流的所有类的超类,可以读取字符信息到内存中,它定义了字符输入流的基本共性功能的方法。
public void close():关闭此流并释放与此流相关的任何系统资源。
public int read():从输入流读取到一个字符。
public int read(char[] cbuf):从输入流读取到一些字符,并把他们存储到字符数组cbuf中。
3.2 FileReader类
java.io.fileread类是读取字符文件的便利类,构造时使用系统默认的字符编码和默认字节缓冲区。
字符编码:字节与字符的对应规则。windows系统汇总的中文编码默认是GBK编码表。
字节缓冲区:一个字节数组,用来临时存储字节数据。
构造方法:
FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) : 创建一个新的 FileReader ,给定要读取的文件的名称。
当要创建一个流对象是,必须要闯入一个文件路径。类似FileInputStream。
public class Demo {
public static void main(String[] args) throws IOException {
//使用File对象创建FileRead流对象
File file=new File("aa.txt");
file.createNewFile();
FileReader fr=new FileReader(file);
//使用文件名字创建FileRead流对象
FileReader fr1=new FileReader("b.txt");
}
}
读取字符数据:
1.读取字符:
read方法,每次可以读取到一个字符数据,提升为int类型,读取到文件末尾,返回-1,循环读取。
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名字创建FileRead流对象
FileReader fr=new FileReader("b.txt");//b 中的字符串为路飞橡胶
//定义变量,保存数据
int len;
//循环读取
while ((len=fr.read())!=-1){
System.out.println((char) len);
}
//关闭资源
fr.close();
}
}
路
飞
橡
胶
2.使用字符串数组读取:
read(char[] cbuf),每次读取b的长度个字符到数组中,返回读取到的有效个数,读取到末尾时,返回-1.
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名字创建FileRead流对象
FileReader fr=new FileReader("b.txt");//路飞橡胶者
//定义变量,保存数据
int len;
//定义字符数组,作为装字符数据的容器
char[] cbuf=new char[2];
//循环读取
while ((len=fr.read(cbuf))!=-1){
System.out.println(new String(cbuf));
}
//关闭资源
fr.close();
}
}
路飞
橡胶
者胶
和FileInputStream一样,要获取有效的字符,需要改进:
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名字创建FileRead流对象
FileReader fr=new FileReader("b.txt");//路飞橡胶者
//定义变量,保存数据
int len;
//定义字符数组,作为装字符数据的容器
char[] cbuf=new char[2];
//循环读取
while ((len=fr.read(cbuf))!=-1){
System.out.println(new String(cbuf,0,len));
}
//关闭资源
fr.close();
}
}
路飞
橡胶
者
3.3 字符输出流【Write】
java.io.Write抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
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() 关闭此流,但要先刷新它。
3.4 FileWrite类
java.io.FileWrite类是写出字符到文件的便利类。构造时,使用系统默认的字符编码和默认缓冲区。
构造方法:
FileWriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) : 创建一个新的 FileWriter,给定要读取的文件的名称。
当要创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。
public class Demo {
public static void main(String[] args) throws IOException {
//使用File对象创建FileWrite流对象
File file =new File("ab.txt");
FileWriter fw=new FileWriter(file);
//使用文件名称创建FileWrite流对象
FileWriter fw1=new FileWriter("abc.txt");
}
}
写出基本数据:
写出字符:write(int b)方法,每次可以写出一个字符数据。
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名称创建FileWrite流对象
FileWriter fw=new FileWriter("abc.txt");
//写出数据
fw.write(97);// 写出第1个字符
fw.write('b');// 写出第2个字符
fw.write('c');// 写出第3个字符
fw.write(30000);// 写出第4个字符,中文编码表中30000对应一个汉字。
fw.close();
}
}
注: 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出。未调用close方法,数据只是保存到了缓冲区,并未写出到文件中。
关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,就无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的,如果想要既写出数据,邮箱基础使用流,就需要flush方法。
flush: 刷新缓冲区,流对象可以继续使用
close:先刷新缓冲器,然后通知系统释放资源,流对象不可继续在使用。
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名称创建FileWrite流对象
FileWriter fw=new FileWriter("abc.txt");
//写出数据,通过flush
fw.write('刷');
fw.flush();
fw.write('新');
fw.flush();
//写出数据,通过close
fw.write('关');
fw.close();
//fw.write('闭');//报错java.io.IOException: Stream closed
// fw.close();
}
}
写出其它数据:
1.写出字符数组:
write(char[] cbuf) 和 write(char[] cbuf, int off, int len) ,每次可以写出字符数组中的数据,用法类似FileOutputStream,代码使用演示:
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名称创建FileWrite流对象
FileWriter fw=new FileWriter("abc.txt");
//字符串转换成字节数组
char[] chars="路飞橡胶者".toCharArray();
//写出字符数组
fw.write(chars);//路飞橡胶者
//写出从索引2 开始,2个字节
fw.write(chars,2,2);
//关闭资源
fw.close();
}
}
2.写出字符串:
write(String str) 和 write(String str, int off, int len) ,每次可以写出字符串中的数据。
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名称创建FileWrite流对象
FileWriter fw=new FileWriter("abc.txt");
//字符串
String s="路飞索隆山治呀";
//写出字符数组
fw.write(s);//路飞索隆山治呀
//写出从索引2 开始,2个字节
fw.write(s,2,3);
//关闭资源
fw.close();
}
}
3. 续写和换行
public class Demo {
public static void main(String[] args) throws IOException {
//使用文件名称创建FileWrite流对象
FileWriter fw=new FileWriter("abc.txt",true);
//字符串
String s="路飞索隆山治呀";
//写出字符数组
fw.write(s);//路飞索隆山治呀
fw.write("\r\n");
//写出从索引2 开始,2个字节
fw.write(s,2,3);
//关闭资源
fw.close();
}
}