IO的概述
—什么是IO (input, output)
—什么叫流 一组有序的,有起点和终点的数据集合,比如文件流,网络流等等
—和文件的区别 :文件是一种静态的数据呈现, 流是一种动态的概念
java中对数据的操作都是以流的方式来进行的,java中操作流的对象,都在 java.io 包下
流按操作的数据类型来分,分为 字符流,字节流
流按方向来分,分为字输入流,输出流
java.io包中,有四个抽象基类
字符流
Reader , Writer
字节流
InputStream , OutputStream
其他所有的IO操作的类,都是由它们派生来的
所有字符流,都是以 Reader 或 Writer 结尾 比如 :FileReader, BufferedReader, FileWriter
所有的字节流,都是`是 InputStream 或 OutputStream` 结尾的 ,比如 FileInputStream , FileOutputStream
标准的IO异常处理
//例子,把一个集合中的内容,写到文件中
static void test2() {
List<String> nameList=new ArrayList<String>(); ///把集合中的人员名单写到文本文件中
nameList.add("陈聪");
nameList.add("钱进才");
nameList.add("孙宝憲");
nameList.add("陈强强");
nameList.add("赵庆");
Writer w=null;
try {
w=new FileWriter("c://名单.txt");
for(String name: nameList) {
w.write(name +"\r\n");
}
w.flush();
w.close(); //关流,清理资源
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if(w!=null) {
w.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2 字符流 Writer
Writer
BufferedWriter
CharArrayWriter
OutputStreamWriter --> FileWriter
FilterWriter //过滤流
PipedWriter //管道流
StringWriter
//例子 在文件里写入一些内容
static void test() throws IOException {
Writer w=new FileWriter("c:/1.txt",true); //true 表示以追加的方式写入,不会覆盖原来的内容
w.write("今年是2020年");
w.write("\r\n"); //写入回车换行
w.write("今年都在家呆着");
//字符流,在写出的时候,会往缓冲区中写
w.flush(); //用来刷缓冲区
w.close(); //关闭流,它会自动刷缓冲区
System.out.println("运行成功...ok ");
}
==== 3 标准的IO异常处理
//例子,把一个集合中的内容,写到文件中
static void test2() {
List nameList=new ArrayList();
nameList.add(“陈聪”);
nameList.add(“钱进才”);
nameList.add(“孙宝憲”);
nameList.add(“陈强强”);
nameList.add(“赵庆”);
Writer w=null;
try {
w=new FileWriter("c://名单.txt");
for(String name: nameList) {
w.write(name +"\r\n");
}
w.flush();
w.close(); //关流,清理资源
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if(w!=null) {
w.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键点:
1) 在finally 关闭流
2) 关流之前,一定要判断一下它是不是null
==== 4 字符流 Reader
int read() //读取单个字符,返回的int型是读到的字符的ASII值,如果流读到了末尾,返回 -1
int read(char [] buff) //读数据到 buff中, int型的返回值,表示读到了几个字符,如果读到了末尾,返回-1
int read(char [] buff, int off,int len) //读数据到 buff中 ,从数组的第 off 个位置开始放,len表示要读多少个,int型的返回值表示实际读到的个数
//例子 从文件中读数据,将读到的字符打印出来,本例是一个字符一个字符的读取
static void test3() throws IOException {
Reader r=new FileReader("c:/名单.txt");
int ch=0;
while( (ch=r.read())!=-1 ) {
System.out.print((char)ch);
}
r.close();
}
//例二 用字符数组接收读到的数据
static void test4()throws IOException {
Reader r=new FileReader("c:/名单.txt");
char [] buff=new char[1024];
int len=r.read(buff); //len 代表读到了多少数据
String str=new String(buff,0,len); //构造字符串的时候,要按实际读到的数据构造
System.out.println("|"+str+"|");
r.close();
}
//例三 文件的复制 本例是一个字符一个字符的复制的
//输入:从外面往内存中读
//输出:把内存中的数据写出去
static void test5()throws IOException {
//读入
Reader r =new FileReader("C:\\Users\\Administrator\\Desktop\\java99\\作业\\texts.sql");
//写出
Writer w =new FileWriter("C:\\test_copy.sql");
int ch=0;
while((ch=r.read())!=-1) {
w.write(ch);
}
r.close();
w.close();
}
//例四 文件的复制
static void test6() throws IOException{
Reader r = new FileReader("C:\\\\Users\\\\Administrator\\\\Desktop\\\\java99\\\\作业\\\\texts.sql");
Writer w =new FileWriter("C:\\test_copy_new.sql");
char [] buff=new char[1024];
int len=0; //每次往数组中读的时候,实际读到了多少个字符
while((len=r.read(buff))!=-1) {
w.write(buff,0,len);
}
r.close();
w.close();
}
==== 5 缓冲流和包装类
缓冲流, 底层有缓冲区(和系统提供的缓冲区有区别,系统提供的缓冲区直接和目标设备打交道,但缓冲流的缓冲区,是通过被包装的对象)
缓冲流 有很多, 主要有 BufferedReader BufferedWriter
对流进行 "包装"
对流进行加强
static void test7() throws IOException {
Writer w=new FileWriter("c:/a.txt");
BufferedWriter bw=new BufferedWriter(w);
bw.write("这是第一行");
bw.newLine(); //写入换行符,这是缓冲流增加的方法
bw.write("这是第二行");
bw.flush();
bw.close();
}
//BufferedReader 的 readLine() 方法一次可以读一行
static void test8() throws IOException{
Reader r =new FileReader("c:/test_copy.sql");
BufferedReader br =new BufferedReader(r);
String str=null;
while( ( str=br.readLine() )!=null ) {
System.out.println(str);
}
br.close(); //它内部就是 r.close();
}
装饰模式
public class Test2 {
public static void main(String[] args) {
Japan p =new Japan();
NiceJapan nicejapan=new NiceJapan(p);
nicejapan.speak();
nicejapan.eat();
}
}
class Japan{
void speak() {
System.out.println("哟西..");
}
}
class NiceJapan{
private Japan japan;
NiceJapan(Japan japan){
this.japan=japan;
}
void speak() {
System.out.println("点点头..");
System.out.println("弯弯腰..");
japan.speak();
System.out.println("磕磕头..");
}
void eat() {
System.out.println("正在eat....");
}
}
//使用了接口的装饰模式
public class Test2 {
public static void main(String[] args) {
/*
Japan p=new Japan();
p.speak();
p.eat();
p.work();
*/
Person p=new Japan();
p= new NiceJapan(p);
p.eat();
p.speak();
p.work();
}
}
interface Person{
void speak();
void eat();
void work();
}
class Japan implements Person{
public void speak() {
System.out.println("苍白的讲话");
}
public void eat() {
System.out.println("苍白的吃");
}
public void work() {
System.out.println("苍白的工作");
}
}
//通常来说,装饰类,和被装饰的类,要实现共同的接口
class NiceJapan implements Person{
Person p;
NiceJapan(Person p){
this.p=p;
}
public void speak() {
System.out.println("哇拉哇拉...");
p.speak();
System.out.println("呜了呜了...");
}
public void eat() {
System.out.println("先祈祷..");
p.eat();
}
public void work() {
System.out.println("先弯腰..");
p.work();
System.out.println("再站起来..");
}
}
==== 6 字节流
字节流 的后缀全是 InputStream 或 OutputStream
//例子 用字节流对文件进行读写
static void test1() throws IOException {
OutputStream out =new FileOutputStream("c:/2.txt");
out.write("root这是一个字符串admin".getBytes()); //字节流不用flush,字节也没有直接写出字符串的方法,所以要转成字节数组
out.close();
InputStream in =new FileInputStream("c:/2.txt");
//in.read() 从流中读一个字节,返回的值就是这个字节对应的码值
int ch=0;
while((ch=in.read())!=-1) {
System.out.print((char)ch); //可以发现,中文出现了乱码
}
in.close();
}
字符流和字节流的最大区别:
字符流总是按字符读取(至于一个字符要读几个字节,我们不用考虑),适合处理文本文件
字节流总是按字节读取(哪怕这个字节无法组成一个字符), 适合处理图片,声音等二进制文件
//例子, 用字节数组读取
static void test2() throws IOException {
InputStream in =new FileInputStream("c:/test_copy.sql");
byte [] buff=new byte[20];
int len=0;
while((len=in.read(buff))!=-1) {
String str=new String(buff,0,len);
System.out.println(str);
}
in.close();
}
注意,中文有的时候还是会出现乱码的
//例子 关于 available()方法
它的作用是判断流中还有多少个字节没有读
static void test3()throws IOException {
InputStream in =new FileInputStream("c:/test_copy.sql");
System.out.println(in.available()); //23390
in.read();
in.read();
in.read();
in.read();
System.out.println(in.available()); //23386
}
//例子 用available()得到数据的长度,再进行处理
static void test2() throws IOException {
InputStream in =new FileInputStream("c:/test_copy.sql");
byte [] buff=new byte[in.available()];
in.read(buff);
String str=new String(buff);
System.out.println(str);
in.close();
}
//例子 图片的复制
static void test4() throws IOException {
InputStream in=new FileInputStream("C:\\Users\\Administrator\\Desktop\\1.jpg");
OutputStream out =new FileOutputStream("C:\\Users\\Administrator\\Desktop\\1_copy.jpg");
byte [] buff=new byte [in.available()];
in.read(buff);
out.write(buff);
in.close();
out.close();
}
注意,上面的写法适合于处理小的文件
==== 7 转换流
InputStreamReader, OutputStreamWriter
把字节输入流转为字符输入流
InputStreamReader public class InputStreamReader extends Reader
把字节输出流转为字符输出流
OutputStreamWriter public class OutputStreamWriter extends Writer
1) InputStreamReader
它有四个构造函数:
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, Charset cs)
InputStreamReader(InputStream in, CharsetDecoder dec) //CharsetDecoder 解码器
InputStreamReader(InputStream in, String charsetName)
2) OutputStreamWriter
它有四个构造函数:
OutputStreamWriter(OutputStream out) //创建使用默认字符编码的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, CharsetEncoder enc) // 创建使用给定字符集的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName) // 创建使用给定字符集编码器的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName) // 创建使用指定字符集的 OutputStreamWriter。
//例 用 InputStreamReader 把一个字节流转成字符流
static void test1() throws IOException {
//字节流
InputStream in=new FileInputStream("c:/名单.txt");
//用转换流去包装字节流
InputStreamReader inr=new InputStreamReader(in);
//用缓冲流去包装转换流
BufferedReader br =new BufferedReader(inr);
String str=null;
while((str=br.readLine())!=null) {
System.out.println(str);
}
br.close();
}
//例 把从键盘输入的一行行字母变成大写打印出来
static void test2() throws IOException {
BufferedReader br= new BufferedReader( new InputStreamReader(System.in)); //流栈
String str=null;
while((str=br.readLine())!=null) {
System.out.println(str.toUpperCase());
}
br.close();
}
==== 8 练习
从一个输入流中,读取字符,变成大写,存到输出流中
public static void main(String[] args) throws IOException {
InputStream in=new FileInputStream(“c:/a.txt”);
OutputStream out =new FileOutputStream(“c:/a_copy.txt”);
transform(in,out);
in.close();
out.close();
System.out.println("ok");
}
public static void main(String[] args) throws IOException {
transform(System.in,System.out);
System.out.println("ok");
}
/**
* 参数1 输入流
* 参数2 输出流
* @throws IOException
*/
static void transform(InputStream in,OutputStream out) throws IOException {
int ch=0;
while((ch=in.read())!=-1 ) {
out.write( Character.toUpperCase(ch) );
}
}