缓冲流和常用API
1. 缓冲流
1.1 缓冲流概述
BufferedInputStream
字节缓冲输入流
BufferedOutputStream
字节缓冲输出流
BufferedReader
字符缓冲输入流
BufferedWriter
字符缓冲输出流
- 缓冲流是Java中提供的系统缓冲,底层都是一个缓冲数组,根据处理的数据方式不同,提供的数据有字节缓冲数组和字符缓冲数组。
- 字节缓冲流,默认的字节数组缓冲区是8KB
byte[] buffer = new byte[1024 * 8]; - 字符缓冲流,默认的字符数组缓冲区是16KB
char[] buffer = new char[1024 * 8]; - 【重点】
任何一个缓冲流都没有任何操作文件的能力!!!读取文件数据,写入文件数据,都是依赖于对应的字符流或者字节流提供的!!! - 缓冲流使用的方法,也是read write 而且是对应创建当前缓冲流使用的字符流或者字节流的!!!
- 缓冲流减少了CPU通过内存访问磁盘或者说文件的次数。极大的提高了开发效率。IO流操作文件内容都是在缓冲流内部的缓冲数组中,也就是内存中。
1.2 BufferedInputStream 字节缓冲输入流
构造方法 Constructor
BufferedInputStream(InputStream in);
这里需要的参数是字节输入流对象
成员方法 Method
int read();
int read(byte[] buf);
其实就是InputStream中使用的方法。
代码演示
package com.qfedu.a_buffer;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/*
* 字节缓冲输入流操作
*/
public class Demo1 {
public static void main(String[] args) throws IOException {
// 1. 明确操作文件
File file = new File("D:/aaa/1.txt");
// 2. 创建对应的FileInputStream对象
FileInputStream fis = new FileInputStream(file);
// 3. 根据FileInputStream创建对应的BufferedInputStream,给缓冲流提供必要的读写能力
BufferedInputStream bis = new BufferedInputStream(fis);
// BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("D:/aaa/1.mp4"));
// 4. 读取数据
System.out.println((char) bis.read());
System.out.println((char) bis.read());
System.out.println((char) bis.read());
System.out.println((char) bis.read());
System.out.println((char) bis.read());
byte[] buf = new byte[1024 * 4];
int length = -1;
while ((length = bis.read(buf)) != -1) {
System.out.println(new String(buf, 0, length));
}
// 5. 关闭资源
bis.close();
}
}
1.3 BufferedOutputStream 字节缓冲输出流
构造方法 Constructor
BufferedOutputStream(OutputStream out);
这里需要一个字节输出流作为方法的参数
常用方法 Method
void write(int b);
void write(byte[] buf);
void write(byte[] buf, int off, int len);
以上方法都是OutputStream提供的方法。
所有的数据都是首先都是写入保存到BufferedOutputStream 底层操作的数组中,当数组填满以后,或者执行指定的方法,才会将数据之间写入到内存中。
代码演示
package com.qfedu.a_buffer;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
/*
* 字节缓冲输出流操作
*/
public class Demo2 {
public static void main(String[] args) throws IOException {
// 1. 直接创建对应的缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/aaa/2.txt"));
for (int i = 0; i < 10000; i++) {
bos.write("1234567890".getBytes());
}
new Scanner(System.in).next();
for (int i = 0; i < 10000; i++) {
bos.write("1234567890".getBytes());
}
bos.close();
}
}
1.4 使用缓冲和不使用缓冲的时间效率问题
package com.qfedu.a_buffer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 使用缓冲和非缓冲情况下操作对比!!!
*/
public class Demo3 {
public static void main(String[] args) throws IOException {
// 空间换时间!!!
// 210 8KB
//useBuffer();
// 50373 4byte
noBuffer();
}
public static void noBuffer() throws IOException {
long start = System.currentTimeMillis();
// 使用基本IO流
FileInputStream fis = new FileInputStream("D:/aaa/2.txt");
FileOutputStream fos = new FileOutputStream("D:/aaa/noBuffer.txt");
int content = -1;
while ((content = fis.read()) != -1) {
fos.write(content);
}
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - start));
}
private static void useBuffer() throws IOException {
long start = System.currentTimeMillis();
// 使用缓冲流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/aaa/2.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/aaa/useBuffer.txt"));
int content = -1;
while ((content = bis.read()) != -1) {
bos.write(content);
}
bos.close();
bis.close();
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - start));
}
}
1.5 关于字节缓冲使用总结
- 使用缓冲时间效率是远远高于未使用缓冲情况,这里是一个非常经典的空间换时间概念
缓冲占用内存 16KB 非缓冲 4byte 时间效率大于250倍 空间占用4000倍 - 利用代码可以发现,非缓冲IO操作时使用数组作为缓冲区和使用缓冲流操作,时间效率相似。这里还是推荐使用系统提供的缓冲流,更加安全,并且提供了一些其他方法,可以作为一定参考和使用。
1.6 BufferedReader 字符输入缓冲流
构造方法 Constructor:
BufferedReader(Reader in);
常用方法 Method:
int read();
int read(byte[] buf);
String readLine(); 【新方法】
从文件中读取一行数据,返回值类型是字符串,如果读取到文件末尾,返回null
一行数据??? 结尾标记 \r\n
代码演示
package com.qfedu.a_buffer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Demo4 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:/aaa/3.txt"));
System.out.println(br.read());
String str = null;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
br.close();
}
}
1.7 BufferedWriter 字符输出缓冲流
构造方法 Constructor:
BufferedWriter(Writer in);
常用方法:
void write(int ch);
void write(char[] buf);
void write(char[] buf, int off, int len);
void write(String str);
void write(String str, int off, int len);
void newLine();
换行操作
代码演示
package com.qfedu.a_buffer;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class Demo5 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/aaa/4.txt"));
bw.write("没有什么知识点是20遍抄写解决不了的");
bw.newLine();
bw.write("如果有???!!!");
bw.newLine();
bw.write("那就再来20遍!!!\r\n");
bw.close();
}
}
2. Java常用API
2.1 关于String字符串的冗余问题
String字符串常量操作会导致大量的字符串冗余问题,浪费内存。
为了解决这个冗余问题,Java中提供了两个可变长字符串
StringBuffer和StringBuilder 底层保存字符串数据的都是字符串数组形式,并且该数组的初始化容量为16个char类型。
2.2 StringBuffer方法
2.2.1 StringBuffer概述
StringBuffer是一个线程安全的可变长字符串对象。
涉及的方法有,增删改查
2.2.1 StringBuffer构造方法
Constructor:
StringBuffer();
创建一个StringBuffer类对象,在底层char类型数组中,初始化容量为16,并且
未存储任何的数据
StringBuffer(String str); [最常见]
根据用户传入参数String类型字符串,创建对应的StringBuffer对象,底层
char类型数组保存对应的字符串信息。
StringBuffer(int capacity);
根据用户传入初始化底层char类型数组容量确定StringBuffer对象
2.2.3 添加方法
append(EveryThing);
在StringBuffer末尾追加内容,可以是任意数据类型
insert(int index, EveryThing);
在StringBuffer指定下标位置添加内容,可以是任意数据类型
代码演示
package com.qfedu.b_stringbuffer;
import java.util.ArrayList;
public class Demo3 {
public static void main(String[] args) {
StringBuffer stb = new StringBuffer(“加多宝凉茶”);
Demo1 str = null;
stb.append(1);
stb.append(true);
stb.append('z');
stb.append(3.14F);
stb.append(5.5);
stb.append(new Demo3());
stb.append(str);
System.out.println(stb);
StringBuffer stb2 = new StringBuffer("骚磊伦布");
ArrayList<String> list = new ArrayList<String>();
list.add("123");
list.add("ABC");
list.add("BBC");
stb2.insert(0, list);
System.out.println(stb2);
//
// boolean flag = true;
// while (flag) {
//
// }
//
// System.out.println(1111);
}
}
2.2.4 查看方法
String toString();
将StringBuffer底层保存数据的char类型字符数组内容,转换为String类型返回
int indexOf(String str);
指定字符串在StringBuffer出现的第一次下标位置
int lastIndexOf(String str);
指定字符串在StringBuffer中最后一次出现的下标位置
String substring(int begin);
从指定位置开始,到字符串末尾截取获得对应的字符串
String substring(int begin, int end);
从指定位置begin开始,到end结束,获取对应的字符串,要头不要尾
代码演示
package com.qfedu.b_stringbuffer;
public class Demo4 {
public static void main(String[] args) {
StringBuffer stb = new StringBuffer("12345678901234567890");
int index = stb.indexOf("78");
System.out.println(index);
int lastIndexOf = stb.lastIndexOf("78");
System.out.println(lastIndexOf);
String substring = stb.substring(5);
System.out.println(substring);
String substring2 = stb.substring(5, 9);
System.out.println(substring2);
}
}
2.2.5 修改方法
replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。该子字符串从指定的 start 处开始,一直到索引 end - 1 处的字符
setCharAt(int index, char ch)
指定索引位置替换一个字符
代码演示
package com.qfedu.b_stringbuffer;
public class Demo5 {
public static void main(String[] args) {
StringBuffer stb = new StringBuffer("0123456789");
StringBuffer replace = stb.replace(3, 9, "深圳是个好地方!!!");
System.out.println("replace: " + replace);
System.out.println("stb: " + stb);
stb.setCharAt(1, '你');
System.out.println(stb);
}
}
2.2.6 删除和反序
delete(int start, int end);
删除从start开始,到end结束区间的所有内容,要头不要尾
deleteCharAt(int index);
删除指定下标的字符
reverse();
StringBuffer内容反序
2.3 StringBuilder和StringBuffer的关系
ArrayList 线程不安全,效率高
Vector 线程安全,效率低
StringBuffer 线程安全,效率低
StringBuilder 线程不安全,效率高
StringBuffer和StringBuilder操作使用的方法,是一致的,只不过StringBuffer的方法带有大量的同步问题。效率比较低。
2.4 System类
System是系统类
static Properties getProperties();【重点】
获取系统属性
static long currentTimeMillis();
获取当前时间的毫秒数
static void exit(int status);
JVM退出程序,0表示正常退出
Properties类是一个重点
属性类,里面保存的数据都是键值对形式。
代码演示
package com.qfedu.c_system;
import java.util.Properties;
public class Demo1 {
public static void main(String[] args) {
Properties properties = System.getProperties();
properties.list(System.out);
System.out.println();
String property = properties.getProperty("os.name");
System.out.println(property);
System.out.println(System.currentTimeMillis());
System.exit(0);
}
}