IO(字符流)
计算机如何识别中文对应的两个字节(工具中默认的GBK形式)
Gbk的格式:
一个中文由两个字节组成
第一个字节:肯定是负数
第二个字节:可以是正数也可以是负数,没有影响
1. 编码和解码的问题:
编码:将能看懂的数据编写成一个你看不懂的数据
Public byte[]by(Charsetcharset):使用指定的编码格式编写一个字节数组
PublicString(byte[]by,Charse,charse):使用指定的编码格式将字节数组转换成字符串
编码和解码问题很简单,只要保证编码和解码格式一致就不会有问题
import java.io.IOException;
import java.util.Arrays;
public class StringDemo {
public static void main(String[] args) throws IOException {
String s="好好学习";
byte[]by=s.getBytes();//默认GBK模式
System.out.println(by);//[B@3781efb9
System.out.println(Arrays.toString(by));//[-70, -61, -70, -61, -47, -89, -49, -80]
//使用指定格式编程一个字节数组
byte[]bys=s.getBytes("UTF-8");
System.out.println(bys);
System.out.println(Arrays.toString(bys));//UTF-8模式,一个中文对应三个字节
// String ss=new String(bys,"GBK");//濂藉ソ瀛︿範
// System.out.println(ss);中文乱码,bys字节数组编码使用的是UTF-8模式,这里解码的格式应该保持一致
String sss=new String(by,"GBK");
System.out.println(sss);//好好学习
}
}
2. 字符输入流
Reader------------------à转换流InputStreamReader
PublicInputStreamReader(InputStream in):默认GBK模式
PublicInputStreamReader(InputStream in,Charset cs):指定一种编程格式
字符转换输入流中读数据的方法:
public int read():读取单个字符
public int read(char[] cbuf)一次读取一个字符数组
代码:
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("c.txt")) ;
//读数据 ,一次读取一个字符
int ch=0;
while((ch=isr.read())!=-1){
System.out.print((char) ch);
}
isr.close();
}
}
Writer----------------à字符输出流转换流:字节流+编码格式
构造方法
publicOutputStreamWriter(OutputStream out):默认的字符编码格式
public OutputStreamWriter(OutputStreamout,Charset cs):指定的字符编码格式
字符转换输出流中写数据的方法:
publicvoid write(int c):写单个字符 :int 值--->ASCII码表 的取值范围 ~:126
publicvoid write(char[] cbuf):写一个字符数组
publicabstract void write(char[] cbuf, intoff,int len):写字符数组的一部分
publicvoid write(String str):写字符串
public void write(String str,int off,intlen):写字符串数组的一部分
代码:
public class OutputStreanmWriter {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("osw.txt"));
osw.write('a');
osw.write("\r\n");//换行符
osw.write(97);
osw.write("\r\n");
osw.write("hello");
osw.write("您好世界");
osw.write("\r\n");
osw.write("您好世界",0,2);
osw.write("\r\n");
char[]chs={'a','b','c','d','e'};
osw.write(chs);
osw.write("\r\n");
osw.write(chs,2,3);
osw.write("\r\n");
osw.flush();//刷新缓冲区
osw.write('m');//还可以继续写
osw.close();
//osw.write('n');//不能继续写,流已经关闭了 java.io.IOException: Stream closed
}
3. 练习
代码:
/*
* 把当前项目中a.txt文件中的内容复制到c.txt文件中
* 数据源:a.txt 字符流进行 字符转换输入流读取数据:InputStreamReader
* 目的地:c.txt 字符流进行 字符转换输出流写入数据:OutputStreamReader
*
*/
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
//封装数据源
InputStreamReader isr=new InputStreamReader(new FileInputStream("Demo\\aaa\\bbb\\a.txt"));
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("c.txt"));
char[]chs=new char[1024];
int len=0;
while((len=isr.read(chs))!=-1){
osw.write(chs,0,len);
osw.flush();
}
isr.close();
osw.close();
4. 对于字符转换流,默认格式GBK;一般不用给出编码格式
但是转换流的名称很长,Java提供了一个类:转换流的便捷类
字符转换输入流 InputStreamReader-----àFileReader
字符转换输出流 OutputStreamWriter----àFileWriter
转换流便捷流的构造方法:
FileReader (String fileName)
FileWriter(String fileName)
代码:
/*
* 把当前目录下b.txt文件额度内容复制到c.txt文件中
*/
public class CopyFileDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("Demo\\aaa\\bbb\\b.txt");
FileWriter fw=new FileWriter("c.txt");
char []chs=new char[1024];
int len=0;
while((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
fw.flush();
}
fr.close();
fw.close();
}
}
5. 字符缓冲流
从字符输入流中读取文本,缓冲各个字符,从而实现字符,数组和行的高效运行
可以指定缓冲区的大小,或者可以使用默认的大小,大多数情况下,默认值就足够了
字符缓冲输入流的构造方法
BufferedReader(Reader in)
BufferedReader提供的是一个字符缓冲输入流来更高效的读取数据
代码:
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
//读数据:显示在控制台
//方式1:一次读取一个字符
// int ch = 0 ;
// while((ch=br.read())!=-1){
// System.out.print((char)ch);
// }
//方式2:一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=br.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}
//关闭资源
br.close() ;
}
}
字符缓冲输出流:
BufferdWriter:
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字符写入底层输出流中,而不必针对每次字符写入调用底层系统。
构造方法:
public BufferedWriter( Writer out):
采用默认的缓冲区大小进行字符缓冲输出流对象的创建:默认的缓冲区足够使用,不需要指定缓冲区大小!
代码:
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")) ;
//写数据
bw.write("hello") ;
bw.write("world") ;
bw.write("javaweb") ;
//刷新
bw.flush() ;
//关闭资源
bw.close() ;
}
}
问题是:
FileReader(Stringpathname):对于这种流为什么直接可以将文件的路径抽象表现形式作为参数传递而字符缓冲流里面为什么
不能直接将文件或者目录的抽象路径表现形式来作为参数传递呢?
对于字符缓冲流来说,只是提供一个缓冲区,来提供在程序中的执行效率,但是还要通过基本的字符流进行读取或者进写出
读取数据:
read():一次读取一个字符
read(byte[]bys):一次读取一个字符数组
两种方式在读取的时候只能使用其中一种
由于我们使用一次读取一个字符或者一次读取一个字符数组来进行复制文件(图片,视频,文本文件等等)
读取的效率不高,所以,java针对这种情况提供了另外一种流:字符缓冲流:提供了字符缓冲区(本身就是提供执行效率)
字符缓冲输出流----->面试的时候:说字符缓冲输出流
高效流:自己在开发中可以这样说,由于执行效率高,用这种流读取数据耗费的时间短!