文件的字节流:
FileInputStream
FileOutputStream
当我们学习完了文件的字节流,就可能会考虑,既然有了字节流了,为什么还要文件字符流呢?
我们来看这样一个操作,对如下的一个文件进行拷贝操作,每5个字节进行一次读取到buffer中.并且在程序中输出拷贝结果
这样一个文本文件:
进行读取5个字节,然后拷贝一次.
public class FileInputStreamDemo{
public static void main(String[] args) throws IOException {
File f = new File("file/Stream.txt");
FileInputStream in = new FileInputStream(f);
byte[] buffer = new byte[5];
System.out.println(Arrays.toString(buffer));
int len = -1;
while( (len = in.read(buffer))!=-1){
String str= new String(buffer,0,len);
System.out.println(str);
}
in.close();
}
但是这里就出现问题了,因为一个汉字占两个字节,拷贝不完整的时候输出如下
使用字节流操作汉字或者特殊的符号语言的时候,容易乱码,建议使用字符流
先有字节流,后有字符流,字符流是对字节流的补充
使用记事本打开某个文件,可以看到文件的内容的就是文本文件,否则可以理解二进制
一般的,操作二进制文件
(图片,音频,视频等)必须使用字节流
操作文文件使用字符流
如果不清楚是哪一类文件,
使用字节流
-----------------------------------------------
文件的字符流:
FileReader
FileWriter
流的分类,从不同角度,有不同的分类:
从流向上分,有输入流和输出流
从单位上分,有字节流和字符流
从功能上分,有节点流和包装流
处理流/包装流相对于节点流更高级:
1.隐藏了底层节点流的差异,并对外提供了方便的输入/输出功能,让我们只
关心高级流的操作
2.使用处理流包装了节点流程序直接操作处理流,让节点流与底层的设备io交流
3.只需要关闭处理流即可
包装流如何区分:
创建对象的时候需要传递另一个流对象
new 包装流(其他流对象)
------------------------------------------------
缓冲流:
是一个包装流,起缓冲作用
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
提供的默认缓冲区大小是 1024*8=8192个字节/字符,一般不用修改这个大小
缓冲流的作用:
操作流的时候,习惯定义一个char/byte数组
int read()每次都从磁盘文件中读取一个字节,直接操作磁盘文件性能极低。
没有经过Buffered处理的IO, 意味着每一次读和写的请求都会由OS底层直接处理,这会导致非常低效的问题。
解决方法:定义一个数组作为缓冲区
byte[] a = new byte[
1024
];该数组其实就是一个缓冲区
一次性从磁盘文件中读取1024个字节,如此一来,磁盘文件的操作次数少了————性能得以提升
经过Buffered处理过的输入流将会从一个buffer内存区域读取数据,本地API只会在buffer空了之后才会被调用(可能一次调用会填充很多数据进buffer)。
经过Buffered处理过的输出流将会把数据写入到buffer中,本地API只会在buffer满了之后才会被调用。
//比较节点流和缓冲流的方式的效率比较
public class BufferedStreamvsNodeStreamDemo {
public static void main(String[] args) throws IOException {
File srcfile = new File("file/伯乐油画体.ttf");
File desfile = new File("target/ziti.ttf");
// test1(srcfile, desfile);使用节点流从磁盘文件一个一个字节读取
// test2(srcfile, desfile);
//test3(srcfile, desfile);
test4(srcfile, desfile);
}
//使用缓冲流,一次从磁盘文件读取1024个字节
private static void test4(File srcfile, File desfile) throws IOException {
long begin = System.currentTimeMillis();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(srcfile));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(desfile));
byte[] bu = new byte[1024];
int len = -1;
while ((len = in.read(bu)) != -1) {
out.write(len);
}
in.close();
out.close();
System.out.print("使用缓冲流的方式,一次读取1024byte:\n");
System.out.println(System.currentTimeMillis() - begin);
}
//使用节点流,一次从磁盘文件读取1024个字节
static void test3(File srcfile, File desfile) throws IOException {
long begin = System.currentTimeMillis();
FileInputStream in = new FileInputStream(srcfile);
FileOutputStream out = new FileOutputStream(desfile);
byte[] bu = new byte[1024];
int len = -1;
while ((len = in.read(bu)) != -1) {
out.write(len);
}
in.close();
out.close();
System.out.print("使用节点流,一次从磁盘文件读取1024个字节:\n");
System.out.println(System.currentTimeMillis() - begin);
}
// 使用缓冲流从文件一个一个字节读取
static void test2(File srcfile, File desfile) throws IOException {
long begin = System.currentTimeMillis();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(srcfile));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(desfile));
int len = -1;
while ((len = in.read()) != -1) {
out.write(len);
}
in.close();
out.close();
System.out.print("使用缓冲流的方式:");
System.out.println(System.currentTimeMillis() - begin);
}
// 使用节点流从磁盘文件一个一个字节读取
static void test1(File srcfile, File desfile) throws IOException {
long begin = System.currentTimeMillis();
FileInputStream in = new FileInputStream(srcfile);
FileOutputStream out = new FileOutputStream(desfile);
int len = -1;
while ((len = in.read()) != -1) {
out.write(len);
}
in.close();
out.close();
System.out.print("使用节点流的方式:");
System.out.println(System.currentTimeMillis() - begin);
}
}
节点流的方式:
使用缓冲流的方式:
使用节点流,一次从磁盘文件读取1024个字节:
使用缓冲流的方式,一次读取1024byte:
-----------------------------------------------
转换流:把字节流转换为字符流
InputStreamReader:把字节输入流转换为字符输入流
OutputStreamReader:把字节输出流转换为字符输出流
为什么只有字节流转为字符流,没有字符流转为字节流:
字节流可以操作一切文件,包括纯文本文件和二进制文件;字符是用来操作中文文本使用的,本身是对字节流的一个增强。
public class TransferDemo {
public static void main(String[] args) throws IOException {
File src = new File("file/Stream.txt");
File des = new File("file/Stream_copy.txt");
InputStreamReader ir = new InputStreamReader(new FileInputStream(src),"GBK");
OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream(des),"GBK");
int len = -1;
//操作字符流
char[] buffer= new char[1024];
while((len = ir.read(buffer))!=-1){
ow.write(buffer,0,len);
}
ir.close();
ow.close();
}
}
内存流(数组流):
把数据先临时存在数组中,待会儿再从数组中取出来:
(1):字节内存流 ByteArrayInputStream/ByteArrayOutputStream
(2):字符内存流
(3):字符串流
字节内存流
public class ByteArrayDemo {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write("ABCDE".getBytes());
//要使用存储的临时数据
byte[] buffer = bos.toByteArray();
//字节数组输入流:内存->程序
ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
byte[] bys= new byte[5];
int len = -1;
while((len =bis.read(bys)) !=-1){
System.out.println(new String(buffer,0,len));
}
bis.close();
}
}
字符串
public class StringWriterReaderDemo {
public static void main(String[] args) throws IOException {
//字符串的输出流
StringWriter sw = new StringWriter();
sw.write("hello");
System.out.println(sw.toString());
//字符串输入流:内存->程序
StringReader sr = new StringReader(sw.toString());
char[] buffer =new char[1024];
int len = -1;
while((len =sr.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
sr.close();
}
}
另外还有一个合并流的概念:
合并流(sequenceInputStream):
就是把多个输入流合并成一个流对象
public class SequenceInputDemo {
public static void main(String[] args) throws IOException {
//创建顺序流对象
SequenceInputStream sis = new SequenceInputStream(new FileInputStream("file/Stream.txt"), new FileInputStream("file/Stream_copy.txt"));
byte[] buffer = new byte[1024];
int len = -1;
while( (len = sis.read(buffer)) != -1){
System.out.println(new String(buffer,0,len));
}
sis.close();
}
}