IO流(数据流)
用来处理设备之间的数据传输,Java对数据的操作(硬盘上的文件,内存中的数据)是通过流的方式
Java用于操作流的对象都在IO包中
流按流向分为:输入流,输出流。
流按操作数据分为两种:字节流与字符流
通用:字节流(数据(mp3,mp4等媒体视频音频,图片)都是字节,也就是二进制
ASCII外国人弄的识别英文字母)
我们国家也弄了一个对应中文的表:GBK2312表
国际标准(UNICODE码表(无论什么字符都用16个字节表示),
再进行优化后UTF-8码表(两个相同字母时里面的编码就会优化)
基于字节流产生字符流(内部糅合编码表):对于读取的数据,查哪个表可以由我们来指定
(处理文字就会变得很方便)
字节流的抽象基类:Input Stream ,Output Stream。
字符流的抽象基类:Reader , Writer。
由这四个类派生出来的子类名称都是
以其父类名作为子类名的后缀。
如:Input Stream的子类File Input Stream。
如:Reader的子类File Reader。而前缀名是该流对象的功能
字符流-读取文件
建立一个流对象,将已存在的一个文件加载进流。
File Reader fr = new File Reader(“Test.txt”);
创建一个临时存放数据的数组。
char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);
注:定义文件路径时,可以用“/”或者“\\”。
在创建一个文件时,如果目录下有同名文件将被覆盖。
在读取文件时,必须保证该文件已存在!!否则出异常。
/*writer写*/
//创建一个FileWriter对象,该对象一被初始化就必须明确被操作的文件
//new的文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖.
//该步就是明确数据存放的目的地(要写字得有纸,起到纸的作用)
FileWriter fw = null;//外面建立引用
try {
//里面进行初始化 传递一个true参数,代表不覆盖已有文件,并在已有文件末尾处进行数据续写
fw = new FileWriter("D:\\aio\\demo.txt",true);
//调用write方法,将字符串写入流中,但目前文件中是没有的哦!!
fw.write("hahahha");//写很多到硬盘没空间了,所以有可能有异常
//刷新流对象中的缓冲中的数据,将数据弄到目的地中,流可以继续使用.
fw.flush();//用几次都无所谓,重点是最后要调用close();
//fw.write("3829399dikdjdl");
//fw.flush();
} catch (IOException e) {
e.printStackTrace();
}//抛出异常
finally {
//关闭流资源,但是关闭前会刷新一次内部的缓冲中的数据,将数据弄到目的地中.
//close刷新后,会将流关闭.
try {
if(fw != null) {//为空时,是没法关闭的,所以要判断一下
fw.close();//如果写了5个或更多流,要分别关闭,不能&& 或||写
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//java是调用系统中的资源来进行读写操作,它本身是不能进行这种操作的,
//所以用完了要把系统的资源给关闭,释放出来
}
/*读Reader*/ throws IOException
//先创建一个文件读取流对象,和要读的文件名称相关联
//要保证该文件已经存在,若不存在,会报FileNotFoundException
FileReader fr = new FileReader("D:\\aio\\demo.txt");
//调用读取流对象的read方法,
//read(); :一次读一个字节,并且会自动往下读,返回一个int型的数字
//int ch = 0;
//while((ch = fr.read()) != -1 ) {
// System.out.println((char)ch);//转换成我们认识的字母
//}
/*while(true) {
int ch = fr.read();
if(ch == -1) {
break;
}System.out.println((char)ch);
}
*/
//通过字符数组进行读取
//定义一个字符数组read(char[]),用于存储读到的字符,返回读到的字符个数
char[] buf = new char[1024];//定义为1024(2k)的整数倍的数组长度
int num = 0;
while((num = fr.read(buf)) != -1) {
//把数组打印变成字符串打印一下,从什么位置开始,取几个
System.out.print(new String(buf,0,num));
}
//int num = fr.read(buf);//读一个,存数组里一个
fr.close();
package io;
import java.io.*;
public class lOtext {
/*把复制文件到另一个地方 */
public static void main(String[] args) {
copy_2();
}
//用这个
public static void copy_2() {
FileWriter fw =null;
FileReader fr = null;
try {
fw = new FileWriter("D:\\aio\\demo_copy.txt");
fr = new FileReader("D:\\aio\\demo.txt");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf)) != -1) {
fw.write(buf,0,len);}
}catch(IOException e){
throw new RuntimeException("读写失败");
}finally {
if(fr!= null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//读一个字符,存一个字符的方法
public static void copy_1() throws IOException {
//创建目的地
FileWriter fw = new FileWriter("D:\\aio\\demo_copy.txt");
//与已有文件关联
FileReader fr = new FileReader("D:\\aio\\demo.txt");
int ch = 0;
while((ch=fr.read()) != -1) {
fw.write(ch);
}
fr.close();
fw.close();
}
}
上面的文件复制思路图解
字符流的缓冲区:
缓冲区的出现是为了提高了对数据(流)的读写效率。
所以在创建缓冲区之前要先有流对象
对应类(没有空参构造方法)
• Buffered Writer
• Buffered Reader
缓冲区要结合流才可以使用。在流的基础上对流的功能进行了增强。
//创建一个字符写入流对象 throws IOException
FileWriter fw = new FileWriter("D:\\aio\\buf.txt");
//创建一个字符读取流对象和文件相关联
FileReader fr = new FileReader("D:\\aio\\demo.txt");
//为提高字符写入流效率,加入了缓冲技术
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
//该缓冲区提供了一个跨平台的换行符
BufferedWriter bufw = new BufferedWriter(fw);
//bufw.write("dhjka\r\njdfjlda");//windows换行
//bufw.newLine();//自动换行
for(int x=1;x<5;x++) {
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush();//读一个写进去一个,哪怕突然停电,写进去的也写进去了
}
BufferedReader bufr = new BufferedReader(fr);
//特牛的读取方法,每次读一行,方便对文本的阅读,返回字符串null是读到末尾
//String s1 = bufr.readLine();
String line = null;
while((line=bufr.readLine())!=null) {
System.out.println(line);
//每次读取一行,但是换行的回车符并未被返回回来,打印时如果不写ln是不会换行的
}
bufw.flush();
bufw.close();
bufr.close();
//缓冲区的关闭其实关闭的就是缓冲区的流对象
package io;
import java.io.*;
public class CopyByBuffer {
/*用缓冲区进行文件copy*/
//该缓冲区提供了每次读一行的方法readline,方便对文本数据的获取,当返回null时,表示读到末尾
public static void main(String[] args) {
BufferedReader bufr =null;
BufferedWriter bufw =null;
try {
bufr = new BufferedReader(new FileReader("D:\\aio\\buf.txt"));
bufw = new BufferedWriter(new FileWriter("D:\\aio\\buf_copy.txt"));
String line = null;//起到中转站的作用
while((line=bufr.readLine())!=null) {
bufw.write(line);
bufw.newLine();
//readline方法返回的时候只返回回车符之前的数据内容,并不返回回车符
bufw.flush();
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
}finally {
try {
if(bufr != null)
bufr.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(bufw != null)
bufw.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
基于reader提供的一次读一个字符方法,自己写的一次可以读一行的方法
package io;
import java.io.IOException;
import java.io.Reader;
/*装饰设计模式(方式:构造函数传递,进行功能增强):
*
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有功能,并提供加强功能
那么自定义的该类称为装饰类
装饰类,通常会通过构造方法接受被装饰的对象,并基于被装饰对象的功能,提供更强的功能
*
*/
/*继承先于装饰出来的
* */
//基于reader提供的一次读一个字符方法,自己写的一次可以读一行的方法
class MyBufferedReader extends Reader {
private Reader r;//写他的父类,这样它任意子类都可以往里面传值
MyBufferedReader(Reader r) {
this.r = r;
}
public String myReaderLine() throws IOException {
//原BufferReader封装的是字符数组,这里定义一个StringBuilder容器
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read()) != -1) {
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length() !=0)
return sb.toString();
return null;
}
/*覆盖掉reader中的抽象方法*/
@Override
public void close() throws IOException {
r.close();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return r.read(cbuf,off,len);
}
/*public void myclose() throws IOException {
r.close();
}*/
}
继承是先于装饰这种模式出来的
包装类/装饰类--带行号的装饰类
FileReader fr = new FileReader("D:\\aio\\demo.java");
LineNumberReader lnr =new LineNumberReader(fr);
lnr.setLineNumber(100);//设置行号
String line = null;
while((line=lnr.readLine())!=null) {
//获取行号
System.out.println(lnr.getLineNumber()+":"+line);
//每次读取一行,但是换行的回车符并未被返回回来,打印时如果不写ln是不会换行的
}
lnr.close();
写一下这个带行号的装饰类------
字符流是用系统默认的码表,字节流就可以自己设置了
获取系统的信息,这里可以看系统默认的码表是什么
System.out.println(System.getProperties());