IO流
流:用来处理不同设备之间的数据传输。
IO流分类:按功能分:输入流和输出流
按内容分:字节流和字符流
字节输出流:
public abstract class OutputStream extendsObject implements Closeable, Flushable。此抽象类是表示输出字节流的所有类的超类。已知子类:FileOutputStream、FilterOutputStream。
方法:
public abstract void write(int b) throws IOException将指定的字节写入此输出流。一次写一个字节。
public void write(byte[] b) throws IOException将 b.length 个字节从指定的 byte 数组写入此输出流。一次写一个字节数组。
public void write(byte[] b,int off,int len)throws IOException将指定 byte 数组中从偏移量 off
开始的 len
个字节写入此输出流。
public void flush() throwsIOException刷新此输出流并强制写出所有缓冲的输出字节。
public void close() throwsIOException关闭此输出流并释放与此流有关的所有系统资源。
FileOutputStream:(文件字节输出流)
public class FileOutputStream extendsOutputStream文件输出流是用于将数据写入File 或 FileDescriptor 的输出流。以字节为单位将数据写入指定文件。
构造方法:
public FileOutputStream(File file) throws FileNotFoundException创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果文件不存在,自动创建文件,如果父目录不存在,报错。
public FileOutputStream(String name) throws FileNotFoundException创建一个向具有指定名称的文件中写入数据的输出文件流。
public FileOutputStream(String name, boolean append) throws FileNotFoundException创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。如果第二个参数是false,则每次都重新写入。
public FileOutputStream(File file, boolean append) throws FileNotFoundException创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。如果第二个参数是false,则每次都重新写入。
方法:继承父类方法。在传入字符串时,可以使用String的getBytes()方法将字符串转为byte数组,再使用public void write(byte[] b)方法写入数据。
public void write(int b) throws IOException将指定的字节写入此输出流。一次只能写一个字节,不能写中文,因为一个中文汉字在GBK编码中占2个字节。
代码示例:
package io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Lianxi1 {
publicstatic void main(String[] args) throws IOException {
Filef = new File("a.txt");//写文件时如果文件不存在,会自动创建,但是如果父目录不存在,会报错。
FileOutputStreamos = new FileOutputStream(f);
os.write(98);//一次写入一个字节
os.write('}');
os.write("98".getBytes());//写入的是98
byte[] b = {'a','n','g','w','u'};
os.write(b);//一次写入一个字节数组
os.write(b,0, b.length);
os.write("云和数据".getBytes());//通过String类的getBytes()方法(返回byte数组)将字符串转为byte数组。
os.close();
}
}
BufferedOutputStream(高效字节输出流):
public class BufferedOutputStreamextendsFilterOutputStream,FilterOutputStream是OutputStream的子类。在创建 BufferedOutputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。
构造方法:
public BufferedOutputStream(OutputStream in),传入的参数是普通的字节输出流对象。
public BufferedOutputStream(OutputStream out,int size),size是缓冲区大小,一般不设置,有默认值。缓冲区长度不要太大,否则浪费空间。
方法:继承父类方法。
特别注意:高效流中必须调用flush方法才能写出成功,因为在高效流中有缓冲区,每次调用write方法时其实是先把数据写在缓冲区,调用flush方法时才写到底层输出流中。
为什么不写flush,只写close也可以写入成功?
因为close方法底层其实调用了flush方法,即在关闭时也进行刷新了,我们一般把flush和close都写上。
为什么普通流不需要刷新?
因为普通=流每一次write方法时都调用了底层资源,直接写在底层数据流中。
代码示例:
package io;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Lianxi3 {
publicstatic void main(String[] args) throws IOException {
FileOutputStreamos = new FileOutputStream("cc.txt");//创建普通流,自动生成文件
BufferedOutputStreambos = new BufferedOutputStream(os);//传入普通输出流对象,创建高效流
byte [] c = {'w','y','h','j','a','v','a'};
bos.write(c,2,3);//从数组的索引为2的元素开始长度为3的元素写出:hja
bos.flush();//必须刷新或关闭
bos.close();//关闭流时只需要关闭高效流即可,因为高效流的底层关闭了普通流。
}
}
字节输入流:
public abstract class InputStream extendsObjectimplements Closeable此抽象类是表示字节输入流的所有类的超类。已知子类:FileInputStream、FilterInputStream。
方法:
public abstract int read() throwsIOException从输入流中读取数据的下一个字节。一次读一个字节。
public int read(byte[] b) throws IOException从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b
中。一次读一个字节数组。返回读入缓冲区的总字节数。如果因为已到达流末尾而不再有数据可用,则返回 -1。
public int read(byte[] b, int off, int len) throws IOException将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。返回读入缓冲区的总字节数。如果因为已到达流末尾而不再有数据可用,则返回 -1。
public void close() throwsIOException关闭此输入流并释放与该流关联的所有系统资源。
FileInputStream:(文件字节输入流)
public class FileInputStream extendsInputStream,从文件系统中的某个文件中获得输入字节。
构造方法:
public FileInputStream(File file) throws FileNotFoundException,传入的参数是要读取的文件。
public FileInputStream(String name) throws FileNotFoundException。传入的参数是要读取的文件名。
方法:继承父类方法。
public int read() throws IOException从此输入流中读取一个数据字节。返回下一个数据字节;如果已到达文件末尾,则返回 -1。
代码示例:
package io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Lianxi2 {
publicstatic void main(String[] args) throws IOException {
//TODO Auto-generated method stub
FileInputStreamis = new FileInputStream("a.txt");
/*
* int count = 0;
intb = 0;
while((b= is.read()) != -1){//此处read方法一个字节一个字节读入,while条件中read返回的是下一个字节数据,
当文件已经到达末尾时,返回-1,所以在返回值不等于-1时,
就说明读取到了字节,那么就执行循环体输出字节内容。如果想要输出文件中的每一个字节,那么就必须用一个变量来接收,
否则在while条件中已经调用了一次read方法了,在输出时如果不定义变量还用read方法时输出的就已经是下一个字节了。
System.out.println(b);
count++;
}*/
/*inta = is.read();//返回的是下一个字节数据
System.out.println((char)a);*///如果文件中读取到的是非字节,那么强转为字符输出的时候就是出现乱码
/* byte [] c = new byte[8];//数组的长度就是一次最多能读几个字节,如果长度小于文件总字节数,
* 那么一次读的字节数就是数组长度,如果数组长度大于文件字节总数,那就一次就能读完文件。
//System.out.println(is.read(c));//返回每次读取到的字节数。
intlen;
while((len= is.read(c)) != -1){//使用传入数组的read方法
Stringstr = new String(c,0,len);使用String的构造方法将字节数组转为字符串,第二个参数0就是将字节数组转为字符串时从数组的索引为0处开始,第三个参数是要把数组中的几个字节转换过来。一般长度都写在读取文件时的长度len,即read方法的返回值。while循环根据数组的长度8,每次读取8个字节,读取的数据放入数组中,然后string构造方法再把这8个字节转为字符串,等到下一次读取时,read方法记得上一次读取的位置,从上一次读取结束的位置开始本次读取,然后再把第二次读取的字节数据放入到数组中,
即数组重新赋值了,把第一次读取到的数据一一覆盖。但是如果把第三个参数即将字符数组转为字符串时要转的数组元素个数不写的话,在前面几次read放入字节数据时不会出现问题,在最后一次读取时,如果读取到的字节数据长度小于数组长度,那么存入数据时,只会把最后一次读取到的字节长度的内容覆盖掉上一次数组中的内容,而由于此次数据长度小于数组长度,所以最后一次覆盖原数据时,后面一部分元素并没有覆盖到,就会继续保留上一次的内容,这样的结果并不是我们想要的,所以一般都把第三个参数写为read返回的长度。
//如果第三个参数不是read返回值,运行结果:云和数据
b}98angw
uangwu云 和数据云
(注意:在最后一次读取时只会读取到6个字节数据,所以在存入数组中时, 前6个字节重新赋值,而数组中的后两个字节没有被覆盖,所以还是上一次元素中的内容,即最后一行输出的最后两个字节”云“字还是倒数第二次存入的后两个字节的内容)
//如果第三个参数是read返回值,输出结果:云和数据
b}98angw
uangwu云
和数据
(在将数组转为字符串时,最后一次转的个数就是只读取到的6个字节的个数)
System.out.println(str);
}*/
byte[] bb = new byte[8];
intlen1;
intcount2 = 0;
while((len1= is.read(bb, 2, 4)) != -1){/*传入的第二个参数意思是在将读取到的数据向数组中存储时,在数组中的偏移量。
即从数组中索引为2的地方开始存储。第三个参数是每读取字节数据的最大长度,该长度如果超过数组长度,就会报出数组索引越界异常。此处,每次读取4个字节,这4个字节从数组索引为2的地方开始存放:示意图:
数组索引: 0 1 2 3 4 5 6 7
存储内容: 云 和(云占两个字节,索引2和3)
数 据
b } 9 8
.....
*/
Stringstr1 = new String(bb,0,len1);/*在转成字符串时,如果第二个参数是0,第三个参数如果还是read返回值,那么转换的时候会有内容缺失,会按照read方法中的第三个参数即每次读取的最大长度来转换数组,所以只会转换数组中从索引为0 开始且长度为4的部分(即索引从0到3),要想内容不缺失,在len上加上数组偏移量。另外一种方法就是,在转为字符串时,string构造方法中的第二个参数可以写成和数组偏移量一致,第三个参数就可以写len1,这样就不会有内容缺失。
*/
System.out.println(str1);
count2++;
}
System.out.println(count2);
is.close();
//System.out.println(count);
}
}
BufferedInputStream(高效输入流):
public class BufferedInputStream extendsFilterInputStream。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。
构造方法:
public BufferedInputStream(InputStream in)
public BufferedInputStream(InputStream in, int size)
用法与高效输出流相同。
方法:继承父类方法。
代码示例:
package io;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Lianxi4 {
publicstatic void main(String[] args) throws IOException {
FileInputStreamfs = new FileInputStream("a.txt");
BufferedInputStreambis = new BufferedInputStream(fs);
byte[] b = new byte [10];
intlen2;
while((len2= (bis.read(b, 2,6))) != -1){
Strings = new String(b,2,6);
System.out.println(s);
}
bis.close();
}
}
字符输出流:
public abstract class Writerextends Object,抽象类,子类:BufferedWriter、OutputStreamWriter。。。。
java.io.OutputStreamWriter的子类:FileWriter。
FileWriter:(文件字符输出流)
public class FileWriter extendsOutputStreamWriter。用于写入字符流。
由于内部维护了一个缓冲区,所以必须刷新或者关闭才能写出成功。(与高效字节输出流相同)字符流只能写文本(图片,音乐,视频都不能使用字符流)。
构造方法:
public FileWriter(File file) throwsIOException
public FileWriter(File file, boolean append)throws IOException
public FileWriter(String fileName, booleanappend) throws IOException
public FileWriter(String fileName) throwsIOException
用法与普通字节输出流相同。
方法:
public void write(int c) throws IOException,写入单个字符,参数是要写入字符的int。
public void write(char[] cbuf, int off, intlen) throws IOException写入字符数组的某一部分。cbuf - 字符缓冲区,off - 开始写入字符处的偏移量
,len - 要写入的字符数 。
public void write(String str, int off, int len) throwsIOException写入字符串的某一部分。str - 字符串,off - 开始写入字符处的偏移量,len - 要写入的字符数 。
public void flush() throws IOException刷新该流的缓冲。
public void close() throws IOException,关闭流。
代码示例:
packageio;
importjava.io.FileWriter;
importjava.io.IOException;
publicclass Lianxi6 {
public static void main(String[] args)throws IOException {
FileWriter f1 = newFileWriter("m.txt");
f1.write('你');
char [] c ={'i','l','o','v','e','j','a','v','a'};
f1.write(c,2,4);
String s = "好好学习天天向上";
f1.write(s, 3, 5);
f1.flush();
f1.close();
}
}
BufferedWriter(高效字符输出流):
publicclass BufferedWriter extends Writer,将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
构造方法:
publicBufferedWriter(Writer out)创建一个使用默认大小输出缓冲区的缓冲字符输出流。
publicBufferedWriter(Writer out, int sz)创建一个使用给定大小输出缓冲区的新缓冲字符输出流。 sz - 输出缓冲区的大小,是一个正整数 。
需要传入普通字符输出流。(必须刷新才能写入成功)
方法:
与文件字符输出流相同。
publicvoid newLine() throws IOException写入一个行分隔符。(换行)
字符输入流:
publicabstract class Readerextends Objectimplements Readable, Closeable。是抽象类,子类:BufferedReader,InputStreamReader(子类:FileReader)
FileReader:(文件字符输入流)
publicclass FileReader extends InputStreamReader。用于读取字符流。
构造方法:
publicFileReader(File file) throws FileNotFoundException
publicFileReader(String fileName) throws FileNotFoundException
方法:
publicint read() throws IOException,读取单个字符。返回作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1。
publicint read(char[] cbuf) throws IOException,将字符读入数组。返回
读取的字符数,如果已到达流的末尾,则返回 -1 。
publicabstract int read(char[] cbuf, int off, int len) throws IOException
将字符读入数组的某一部分。返回读取的字符数,如果已到达流的末尾,则返回 -1 。
代码示例:
packageio;
importjava.io.FileNotFoundException;
importjava.io.FileReader;
importjava.io.IOException;
importjava.util.Arrays;
publicclass Lianxi7 {
public static void main(String[] args)throws IOException {
FileReader f1 = newFileReader("m.txt");
/* intlen;
while ((len = f1.read()) != -1) {//读取一个字符
System.out.println((char)len);
}*/
char [] c = new char [4];
int len1;
while ((len1 = f1.read(c,1,3)) != -1) {//读取数组
System.out.println(Arrays.toString(c));
}
f1.close();
}
}
高效字符输入流:(BufferedReader)
public class BufferedReader extends Reader,从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
构造方法:
public BufferedReader(Reader in)创建一个使用默认大小输入缓冲区的缓冲字符输入流。
public BufferedReader(Reader in, int sz)创建一个使用指定大小输入缓冲区的缓冲字符输入流。sz -输入缓冲区的大小 。
方法:
继承父类方法。
publicString readLine() throws IOException读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。 返回:包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null 。
复制文件的多种方法性能比较
字节流方法:
package io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
public class Lianxi5 {
publicstatic void main(String[] args) throws IOException {
/*//使用普通流一次一个字节的方法复制文件
longt1 = System.currentTimeMillis();
FileInputStreamf1 = new FileInputStream("C:\\Users\\Administrator\\Desktop\\day11\\video\\1.wmv");
FileOutputStream f2 = newFileOutputStream("C:\\Users\\Administrator\\Desktop\\11日录屏");
int n1;
while((n1 = f1.read()) != -1){
f2.write(n1);
}
f1.close();
f2.close();
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);//379878 复制文件所用时长
*/
/* //使用一次一个字节数组的方法复制文件
long t3 = System.currentTimeMillis();
FileInputStream f3 = new FileInputStream("C:\\Users\\Administrator\\Desktop\\day11\\video\\1.wmv");
FileOutputStream f4 = newFileOutputStream("C:\\Users\\Administrator\\Desktop\\11日录屏2");
byte [] b3 = new byte[1024];
int len2;
while((len2 = f3.read(b3)) != -1){
f4.write(b3);
}
long t4 = System.currentTimeMillis();
System.out.println(t4-t3);//608 复制文件所用时长
*/
/* //使用高效流一次一个字节的方法复制文件
longt5 = System.currentTimeMillis();
FileInputStreamf5 = newFileInputStream("C:\\Users\\Administrator\\Desktop\\day11\\video\\1.wmv");
FileOutputStream f6 = newFileOutputStream("C:\\Users\\Administrator\\Desktop\\11日录屏3");
BufferedInputStream f7 = new BufferedInputStream(f5);
BufferedOutputStream f8 = new BufferedOutputStream(f6);
int len3;
while((len3 = f7.read()) != -1){
f8.write(len3);
}
f7.close();
f8.flush();
f8.close();
long t6 = System.currentTimeMillis();
System.out.println(t6-t5);//复制文件所用时长 3604
*/
//使用高效流一次一个字节数组复制文件
longt7 = System.currentTimeMillis();
FileInputStreamf9 = newFileInputStream("C:\\Users\\Administrator\\Desktop\\day11\\video\\1.wmv");
FileOutputStream f10 = newFileOutputStream("C:\\Users\\Administrator\\Desktop\\11日录屏3");
BufferedInputStream f11 = new BufferedInputStream(f9);
BufferedOutputStream f12 = new BufferedOutputStream(f10);
int len4;
byte [] b4 = new byte [2048];
while((len4 = f11.read(b4)) != -1){
f12.write(b4);
}
long t8 = System.currentTimeMillis();
System.out.println(t8-t7);//所用时长 171
/*总结:从以上四种复制文件的方法来分析高效流与普通流以及按字节读取和写入、按字节数组读取和写入
* 在性能方面由高到低:高效流数组字节输入输出>普通流字节输入输出>高效流数组字节输入输出>普通流字节输入输出
*/
}
}
字符流方法:
package io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Lianxi8 {
publicstatic void main(String[] args) throws IOException {
//普通字符流一次一个字符复制文件
longt1 = System.currentTimeMillis();
FileReaderf1 = new FileReader("C:\\Users\\Administrator\\Desktop\\java基础知识总结蓝皮书.doc");
FileWriter f2 = newFileWriter("C:\\Users\\Administrator\\Desktop\\代码复制.doc");
int len;
while((len = f1.read()) != -1){
f2.write(len);
}
f1.close();
f2.close();
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);//所用时长:230
/* //高效字符流字符数组复制文件
long t3 = System.currentTimeMillis();
FileReaderf1 = new FileReader("C:\\Users\\Administrator\\Desktop\\java基础知识总结蓝皮书.doc");
FileWriter f2 = new FileWriter("C:\\Users\\Administrator\\Desktop\\代码复制");
BufferedReader f3 = new BufferedReader(f1);
BufferedWriter f4 = new BufferedWriter(f2);
int len;
char [] c = new char [1024];
while((len = f3.read(c)) != -1){
f4.write(c);
}
f3.close();
f4.close();
long t4 = System.currentTimeMillis();
System.out.println(t4-t3);//所用时长:78
*/
//普通字符流字符数组复制文件
/* longt1 = System.currentTimeMillis();
FileReaderf1 = new FileReader("C:\\Users\\Administrator\\Desktop\\java基础知识总结蓝皮书.doc");
FileWriter f2 = newFileWriter("C:\\Users\\Administrator\\Desktop\\代码复制");
int len;
char [] c = new char[1024];
while((len = f1.read(c)) != -1){
f2.write(c);
}
f1.close();
f2.close();
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);//所用时长:78
*/
/*
//高效字符流一个字符复制文件
longt1 = System.currentTimeMillis();
FileReaderf1 = new FileReader("C:\\Users\\Administrator\\Desktop\\java基础知识总结蓝皮书.doc");
FileWriter f2 = newFileWriter("C:\\Users\\Administrator\\Desktop\\代码复制");
BufferedReader f3 = new BufferedReader(f1);
BufferedWriter f4 = new BufferedWriter(f2);
int len;
while((len = f3.read()) != -1){
f4.write(len);
}
f3.close();
f4.close();
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);//所用时长:141
*/
//高效字符流按行复制文件
/* longt1 = System.currentTimeMillis();
FileReaderf1 = new FileReader("C:\\Users\\Administrator\\Desktop\\java基础知识总结蓝皮书.doc");
FileWriter f2 = newFileWriter("C:\\Users\\Administrator\\Desktop\\代码复制");
BufferedReader f3 = new BufferedReader(f1);
BufferedWriter f4 = new BufferedWriter(f2);
String s;
while((s = f3.readLine()) != null){
f4.write(s);
}
f3.close();
f4.close();
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);//所用时长:125
*/
}
}
递归思想复制文件夹:
package io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Lianxi14 {
//递归复制文件夹
publicstatic void main(String[] args) throws IOException {
Fileof = new File("C:\\Users\\Administrator\\Desktop\\IOTest");
Filenf = new File("C:\\Users\\Administrator\\Desktop\\IOTest复制");
nf.mkdirs();
copyFile(of,nf);
}
publicstatic void copyFile(File oldFile,File newFile) throws IOException{
File[] files = oldFile.listFiles();
for(Filea:files){
if(a.isFile()){//是文件
FileInputStreamf1 = new FileInputStream(a); //创建输入流对象
Filefnew = new File(newFile,a.getName());//创建要复制的同名文件实例
fnew.createNewFile();//创建文件
FileOutputStreamf2 = new FileOutputStream(fnew);//创建输出流对象
intlen;//定义读文件时返回的读取长度
byte[] b = new byte [2048];//定义存储数据的数组
while((len= f1.read(b)) != -1){//读原文件
f2.write(b,0, len);//向同名新文件写出数据
}
f1.close();//关闭流应该写在while循环之外,否则在对一个文件还没读取完就关闭流,文件就不能继续读取
f2.close();
}
else{//是文件夹
//递归调用该方法
Fileff = new File(newFile,a.getName());
ff.mkdirs();
copyFile(a,ff);
}
}
}
}