字节缓冲区流概述与使用:
字节缓冲流 :
BufferedOutputStream:字节缓冲输出流
BufferedInputStream:字节缓冲输入流
BufferedOutputStream(OutputStream out)
使用这种构造方法,它提供了一个默认的缓冲区大小,所以一般我们使用默认缓冲区
为什么构造方法传递的是一个:OutputStream,而不是具体的文件或者路径呢
字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
//FileOutputStream fos = new FileOutputStream("a.txt");
//BufferedOutputStream bos = new BufferedOutputStream(fos);
//上面两句和下面一句效果相同
// BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
// bos.write("hello".getBytes());
// bos.close();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
//方式一一次读取一个字节
// int by;
// while ((by=bis.read())!=-1){
// System.out.println((char)by);
// }
byte []bys = new byte[1024];
int len;
while ((len = bis.read(bys))!=-1){
System.out.print(new String(bys,0,len));
}
bis.close();
}
}
字节流四种方式复制JPG并测试效率:
复制文件时间计算可System类方法实现
public static long currentTimeMillis():返回以毫秒为单位的当前时间。
426 1 7 1
import java.io.*;
public class CopyAviTest {
public static void main(String[] args) throws IOException {
//记录开始时间
long start = System.currentTimeMillis();
//记录结束时间
method1();
method2();
method3();
method4();
long end = System.currentTimeMillis();
System.out.println("共"+(end - start)+"毫秒");
}
private static void method4() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\timg.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
byte[]bys = new byte[1024];
int len;
while ((len = bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
private static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\timg.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
int by;
while ((by = bis.read())!=-1){
bos.write(by);
}
bis.close();
bos.close();
}
private static void method2() throws IOException {
FileInputStream fis = new FileInputStream("d:\\timg.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");
byte []bys = new byte[1024];
int len;
while ((len = fis.read(bys))!=-1) {
fos.write(bys, 0, len);
}
fis.close();
fos.close();
}
private static void method1() throws IOException {
FileInputStream fis = new FileInputStream("d:\\timg.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");
int by;
while ((by = fis.read())!=-1){
fos.write(by);
}
fis.close();
fos.close();
}
}
可通过分别注释方法获取时间分别为
426 1 7 1
笔者此处是用的jpg格式不大,所以方法2和方法4相差不大
但多试验其他格式
会发现带缓冲字节流效率最高,即第四种方法
转换流出现的原因:
字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取一个字节后就转为字符输出了,而汉字是由两个字节组成的,所以会出问题。
文件复制时,字节流读取 一个字节,写入一个字节,这个未出现问题,是因为最终底层会根据字节做拼接,得到汉字。
汉字存储规则:
左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数
由于字节流操作中文不是特别方便,Java就提供了转换流
转换流 = 字节流+编码表
文件内容如下:
import java.util.Arrays;
public class FileDemo {
public static void main(String[] args) {
String s ="你好";
byte[]bys =s.getBytes();
System.out.println(Arrays.toString(bys));
}
}
输出结果:
[-28, -67, -96, -27, -91, -67]
编码表概述:
编码表:
由字符及其对应的数据组成的一张表
ASCII:
‘a’ 97
‘A’ 65
‘0’ 48
常见的编码表:
ASCII:美国标准信息交换码,用一个字节的7位表示数据
ISO-8859-1:欧洲码表,用一个字节的8位表示数据,兼容ASCII
GB2312:中文码表,兼容ASCII
GBK:中文码表的升级版,融合了更多的中文文字符号,兼容ASCII
UTF-8:是一种可变长度的字符编码,用1-3个字节表示数据,又称为万国码,兼容ASCII。用在网页上可以统一页面中的中文简体繁体和其他语言的显示。
乱码问题:
针对同一个数据采用的编码和解码的解码表不一致导致的。
字符串中的编码解码问题:
编码
把看得懂的变成看不懂的
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
解码
把看不懂的变成看得懂的
public String(byte[] bytes, String charsetName)
通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。
重点强调 : 编码和解码的方式需要一致
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class n {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "你好";
//编码
// byte[]bys = s.getBytes("GBK");
//输出:[-60, -29, -70, -61]
byte[]bys = s.getBytes("UTF-8");
//[-28, -67, -96, -27, -91, -67]
// byte[]bys = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bys));
String ss = new String(bys,"UTF-8");
System.out.println(ss);
}
}
转换流中编码与解码问题:
转换流其实就是一个字符流。
转换流 = 字节流+编码表
OutputStreamWriter 字符输出流
public OutputStreamWriter(OutputStream out)
根据默认编码把字节流的数据转换为字符流
public OutputStreamWriter(OutputStream out,String charsetName)
根据指定编码把字节流数据转换为字符流
InputStreamReader 字符输入流
public InputStreamReader(InputStream in)
用默认的编码读数据
public InputStreamReader(InputStream in,String charsetName)
import java.io.*;
public class a {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"UTF-8");
osw.write("你好");
osw.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"UTF-8");
int ch;
while ((ch=isr.read())!=-1){
System.out.print((char)ch);
}
isr.close();
}
}
字符流OutputStream写数据方法:
OutputStreamWriter写数据方法
public void write(int c):写一个字符
public void write(char[] cbuf):写一个字符数组
public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
public void write(String str):写一个字符串
public void write(String str,int off,int len):写一个字符串的一部分
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputStreamDemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("o.txt"));
// osw.write(97);
// osw.write('a');
//写完数据后没有发现数据
//1字符等于2字节
//文件中数据存储的基本单位是字节刷新该流的缓冲
//字符数组
// char[]chs = {'a','b','c','d'};
// osw.write(chs,1,2);
//字符串
// osw.write("hello");
osw.write("hello",0,3);
//osw.flush();//刷新
osw.close();//释放资源前先做刷新,防止数据丢失
}
}
字符流InputStreamReader读数据的方式:
public int read():一次读取一个字符
public int read(char[] cbuf):一次读取一个字符数组
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class newtest {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("o.txt"));
// int ch;
// while ((ch = isr.read())!=-1){
// System.out.print((char)ch);
char []ch = new char[1024];
int len;
while ((len = isr.read(ch))!=-1){
System.out.println(new String(ch,0,len));
}
}
}
字符流练习之复制Java文件:
import java.io.*;
public class Demo2 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IdeaProjects\\Mybuffered\\src\\Day_14\\OutputStreamDemo.java"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("copy.java"));
// int ch;
// while ((ch = isr.read())!=-1){
// osw.write(ch);
// }
char []cha = new char[1024];
int len;
while ((len = isr.read(cha))!=-1){
osw.write(cha,0,len);
}
osw.close();
isr.close();
}
}
字符流的练习之复制java文件改进版:
转换流名字较长,为简化书写,提供了
FileWriter:用来写入字符文件的便捷类
FileReader:用来读取字符文件的便捷类
import java.io.*;
public class Demo2 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IdeaProjects\\Mybuffered\\src\\Day_14\\OutputStreamDemo.java"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("copy.java"));
// int ch;
// while ((ch = isr.read())!=-1){
// osw.write(ch);
// }
char []cha = new char[1024];
int len;
while ((len = isr.read(cha))!=-1){
osw.write(cha,0,len);
}
osw.close();
isr.close();
}
}
字符缓冲区流的概述和使用:
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
构造方法:
BufferedWriter(Writer out)
BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
构造方法:
BufferedReader(Reader in)
import java.io.*;
public class BufferedDemo {
public static void main(String[] args) throws IOException {
// BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// bw.write("hello");
// bw.close();
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// int by;
// while ((by = br.read())!=-1){
// System.out.print((char)by);
// }
char []ch = new char[1024];
int len;
while ((len = br.read(ch))!=-1){
System.out.print(new String(ch,0,len));
}
br.close();
}
}
字符缓冲区流之复制文本文件:
把项目目录下的a.txt内容复制到项目目录下的b.txt中
数据源:
a.txt---读数据---字符流---InputStreamReader---FileReader---BufferedReader
目的地:
b.txt---写数据---字符流---OutputStreamWriter---FileWriter---BufferedWriter
字符缓冲区特殊功能:
BufferedWriter
void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
BufferedReader
String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
import java.io.*;
public class BufferedDemo {
public static void main(String[] args) throws IOException {
// BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// for (int x = 0;x<3;x++){
// bw.write("hello");
bw.write("\r\n");
// bw.newLine();
// bw.flush();
// }
// bw.close();
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
//读取一次
// String line = br.readLine();
// System.out.println(line);
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
字符缓冲流特殊功能复制Java文件:
数据源:
BufferedStreamDemo.java---BufferedReader
目的地:
Copy.java---BufferedWriter
import java.io.*;
public class BufferedDemo {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("b.java"));
BufferedReader br = new BufferedReader(new FileReader("copy.java"));
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
字符流的5种方式复制文本文件:
基本字符流一次读写一个字符
基本字符流一次读写一个字符数组
缓冲字符流一次读写一个字符
缓冲字符流一次读写一个字符数组
缓冲字符串一次读写一个字符串
重点掌握第五种方法
public class CopyFileTest {
public static void main(String[] args) throws IOException {
method1();
// method2();
// method3();
// method4();
// method5();
}
//缓冲字符流一次读写一个字符串
private static void method5() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("d:\\林青霞.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("窗里窗外.txt"));
String line;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
//缓冲字符流一次读写一个字符数组
private static void method4() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("d:\\林青霞.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("窗里窗外.txt"));
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
bw.write(chs, 0, len);
}
bw.close();
br.close();
}
//缓冲字符流一次读写一个字符
private static void method3() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("d:\\林青霞.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("窗里窗外.txt"));
int ch;
while((ch=br.read())!=-1) {
bw.write(ch);
}
bw.close();
br.close();
}
// 基本字符流一次读写一个字符数组
private static void method2() throws IOException {
FileReader fr = new FileReader("d:\\林青霞.txt");
FileWriter fw = new FileWriter("窗里窗外.txt");
char[] chs = new char[1024];
int len;
while((len=fr.read(chs))!=-1) {
fw.write(chs, 0, len);
}
fw.close();
fr.close();
}
// 基本字符流一次读写一个字符
private static void method1() throws IOException {
FileReader fr = new FileReader("d:\\林青霞.txt");
FileWriter fw = new FileWriter("窗里窗外.txt");
int ch;
while ((ch = fr.read()) != -1) {
fw.write(ch);
}
fw.close();
fr.close();
}
}
字符流的练习之把集合中的字符串数据存储到文本文件:
思路:
A:创建集合对象
B:往集合中添加字符串元素
C:创建字符缓冲输出流对象
D:遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
E:释放资源
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class ArraylistTest {
public static void main(String[] args) throws IOException {
ArrayList<String>array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));
for (String s :array){
bw.write(s);
bw.newLine();
bw.flush();
}
bw.close();
}
}
从文本文件中读取数据到集合:
需求: 从文本文件中读取数据到ArrayList集合中,并遍历集合,每一行数据作为一个字符串元素
分析:
A:创建字符缓冲输入流对象
B:创建集合对象
C:读取数据,每一次读取一行,并把该数据作为元素存储到集合中
D:释放资源
E:遍历集合
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class ADemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
ArrayList<String>array = new ArrayList<String>();
String line;
while ((line = br.readLine())!=null){
array.add(line);
}
br.close();
for (String s:array){
System.out.println(s);
}
}
}
字符流的练习之把集合中的学生对象数据存储到文本文件:
需求:
把ArrayList集合中的学生数据存储到文本文件
每一个学生数据作为文件中的一行数据
定义一个学生类。
学生:
学号,姓名,年龄,所在城市
it001,张曼玉,35,北京
it002,王祖贤,33,上海
it003,林青霞,30,西安
分析:
A:创建集合对象
B:创建学生对象
C:把学生对象添加到集合中
D:创建字符缓冲输出流对象
E:遍历集合,得到每一个学生对象,然后把该对象的数据拼接成一个指定格式的字符串写到文本文件
F:释放资源
public class Student {
private String name;
private int age;
private String sid;
private String city;
public Student() {
}
public Student(String name, int age, String sid, String city) {
this.name = name;
this.age = age;
this.sid = sid;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws IOException {
ArrayList<Student>arr = new ArrayList<Student>();
Student s1 = new Student("张曼玉",35,"it001","北京");
Student s2 = new Student("林青霞",33,"it002","上海");
Student s3 = new Student("王祖贤",30,"it003","南京");
arr.add(s1);
arr.add(s2);
arr.add(s3);
BufferedWriter bw = new BufferedWriter(new FileWriter("c.txt"));
for (Student s :arr){
StringBuilder sb = new StringBuilder();
sb.append(s.getSid()+","+s.getName()+","+s.getAge()+","+s.getCity());
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
bw.close();
}
}
输出结果:
如图
字符流的练习之把文本文件中的学生对象数据读取到集合:
需求:
从文本文件中读取学生数据到ArrayList集合中,并遍历集合
每一行数据作为一个学生元素
it001,张曼玉,35,北京要使用String类中的一个方法:split()
分析:
A:创建字符缓冲输入流对象
B:创建集合对象
C:读取数据,每一次读取一行数据,把该行数据想办法封装成学生对象,并把学生对象存储到集合中
D:释放资源
E:遍历集合
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("c.txt"));
ArrayList<Student>arr = new ArrayList<Student>();
String line;
while ((line = br.readLine())!=null){
String[]stry = line.split(",");
Student s = new Student();
s.setSid(stry[0]);
s.setName(stry[1]);
s.setAge(Integer.parseInt(stry[2]));
s.setCity(stry[3]);
arr.add(s);
}
br.close();
for (Student s :arr){
System.out.println(s.getSid()+"---"+s.getName()+"---"+s.getAge()+"---"+s.getCity());
}
}
}
输出结果:
it001---张曼玉---35---北京
it002---林青霞---33---上海
it003---王祖贤---30---南京