IO流
定义:IO流用来处理设备之间的数据传输
java对数据的操作是通过流的方式
java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流和字符流
早期都是字节流,机器上都是字节。字符流的由来是因为可以在内部融合编码表。通用字节流,字符流基于字节流。
流按流向分为:输入流,输出流
字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer。
注:由这四个类派生出来的子类名称都是以期父类名作为子类名的后缀。如
InputStream的子类FileInputStream,Reader的子类FileReader。
字符流的缓冲区
缓冲区的出现提高了对数据的读写效率
对应类
BufferedWriter;BufferedReader
缓冲区要结合流才可以使用
在流的基础上对流的功能进行了增强。
Reader:
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("demo2.txt");
int c = 0;
while((c=fr.read()) != -1){
System.out.println((char)c);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注释:Reader接口提供了很多的实现,其中FileReader可以跟文件相关来操作,其中它的read方法一次读取一个字符。
读取字符的自定义缓冲区读取:
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo2.txt");
char [] buf = new char[1024];//相当于一个缓冲区
int num = 0;
while((num=fr.read(buf))!=-1)
System.out.println("num=" + num +"___"+new String(buf,0,num));
我们这样可以增加效率,java给我们的缓冲区操作进行了优化,增加了一个BufferedReader类,它自带缓冲区
示例程序:
public static void main(String[] args) throws IOException {
//创建一个读取流对象和文件相关联
FileReader fr = new FileReader("buf.txt");
BufferedReader br = new BufferedReader(fr);
String s1 = null;
while((s1=br.readLine())!=null){
System.out.println(s1);
}
br.close();
练习:
读取一个.java文件,并打印在控制台上
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("StringDemo.java");
char [] buf = new char[1024];
int num = 0;
try {
while((num=fr.read(buf)) != -1){
System.out.print(new String(buf,0,num));
}
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Writer:
学习字符流的特点
既然IO流是用于操作数据的
那么数据的常见体现形式是:文件
先以操作文件为主来演示
需求:在硬盘上,创建一个文件并写入一些文字数据
找到一个专门的操作文件的Writer的子类对象,FileWriter,后缀名是父类名,前缀是具体的功能
使用到的装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,提供加强功能
那么自定义的该类称为装饰类
特点:装饰类通常会通过构造方法接受被装饰的对象,并基于别装饰的对象的功能,提供增强的功能;装饰模式比继承要灵活,避免了继承体系的臃肿。而且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,所以装饰类和被装饰类通常是都属于一个体系中。
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作
File对象可以作为参数传递给流的构造函数
了解File类中的常用方法
注:流只能操作数据,要操作文件信息就要File类
public static void main(String[] args) throws IOException {
// 创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
//而且该文件会被创建到指定的目录下,如果该目录下已有同名文件,将被覆盖
//其实该步就是在明确要存放的目的地
FileWriter fw = new FileWriter("demo.txt");
//调用write方法写入到流里面去了,没到目的地中,
fw.write("hello ylm");
//通过flush方法把数据刷到目的地去。
fw.flush();//
fw.write("how are you");
fw.flush();//流资源没有关闭,通过flush刷到目的地
fw.close();//关闭流资源,会刷新一次内部的缓冲中的数据
IO异常的处理方式:
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo2.txt");
fw.write("adfsdf");
fw.close();
} catch (IOException e) {
System.out.println(e.toString());
}finally{
try {
if(fw != null)//要为空判断,若是创建不成功fw为空。
fw.close();
} catch (IOException e) {
System.out.println("关闭异常");
}
}
Writer同样也有缓冲区操作的类BufferedWriter:
public static void main(String[] args) throws IOException {
//创建一个字符写入流对象
FileWriter fw = new FileWriter("buf.txt");
BufferedWriter bufw = new BufferedWriter(fw);
bufw.write("fasdf");
//记住,只要用到缓冲区,就要记得刷新
bufw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象
bufw.close();
}
缓冲区的出现是为了提高流的操作效率而出现的
所以在创建缓冲区之前,必须要先有流对象
示例程序:
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("bufwriter.txt");
BufferedWriter bw = new BufferedWriter(fw);
for (int i = 0; i < 5; i++) {
bw.write("sfsdf" + i);
bw.newLine();//提供的一个跨平台的换行符
bw.flush();
}
bw.close();//实际关闭的是fw的close方法。
} catch (IOException e) {
e.printStackTrace();
}
在原有文件的后面续写数据:由于之前我们的写入流关联的文件是直接创建,硬盘有的话也会直接覆盖。
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo2.txt",true);
fw.write("nihao\r\nhahha");//回车符
fw.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
练习:
将c盘一个文件复制到D盘 复制的原理:其实就是将c盘下的文件数据存储到d盘的一个文件中 定义读取流和c盘文件管理
通过不断的读写完成数据的存储 关闭资源
// 方法一:从c盘读取一个字符,就往d盘写一个字符
public static void copy_1() {
FileWriter fw = null;
FileReader fr = null;
try {
// 创建目的地
fw = new FileWriter("StringDemo_copy.txt", true);
// 与已有的文件相关联
fr = new FileReader("StringDemo.java");
int c = 0;
while ((c = fr.read()) != -1) {
fw.write((char) c);
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw != null)
fw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 方法二:读取到一个字符数组缓冲区。再写到另一个文件中
public static void copy_2() {
FileReader fr = null;
FileWriter fw = null;
int ch = 0;
char[] buf = new char[1024];
try {
fr = new FileReader("StringDemo.java");
fw = new FileWriter("copy_2.txt", true);
while ((ch = fr.read(buf)) != -1) {
fw.write(buf,0,ch);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fr != null)
fr.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过缓冲区复制一个.java 文件:
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
FileWriter fw = null;
FileReader fr = null;
String line = null;
try {
fw = new FileWriter("bufferCopy.txt");
fr = new FileReader("StringDemo.java");
bufr = new BufferedReader(fr);
bufw = new BufferedWriter(fw);
while((line=bufr.readLine()) != null){
bufw.write(line);//注意这里要换行
bufw.newLine();
bufw.flush();
}
} catch (IOException e1) {
e1.printStackTrace();
}finally{
try {
if(bufr != null)
bufr.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if(bufw != null)
bufw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
InputStream
字节流读入类
OutputStream
字节流写出类
注:对字节流的读写顺序和字符流一样,字节流针对的字节数据,字符流是针对纯文本数据,那些字符是我们可以看懂的,字节流的数据是二进制数据,是存在机器里面的二进制形式。同样字节流也有自己的缓冲区类BufferedInputStream,BufferedOutputStream
练习:将一个图片文件中数据存储到另一个文件中。复制文件。
public static void copy_1()
{
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\0.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\test\\1.jpg"));
int len = 0;
while((len = bis.read()) != -1){
bos.write(len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Properties类:
想要将info.txt中的健值数据存到集合中
1.用一个流和Info.txt文件关联
2.读取一行数据,将该行数据用“=”进行切割
3.等号左边作为健,右边作为值,存到Properties中
public static void loadDemo() throws IOException{
FileInputStream fis = new FileInputStream("info.txt");
FileOutputStream fos = new FileOutputStream("info.txt");
Properties p = new Properties();
p.load(fis);
//p.setProperty("lisi", "5");
//p.store(fos, "haha");
p.list(System.out);
//fis.close();
//fos.close();
}
public static void getProperties() throws IOException{
BufferedReader br = new BufferedReader(new FileReader("info.txt"));
String line = null;
Properties p = new Properties();
while((line=br.readLine()) != null){
String[] arr = line.split("=");
System.out.println();
p.setProperty(arr[0],arr[1]);
}
System.out.println(p);
}
public static void setAndGet(){
Properties p = new Properties();
p.setProperty("zhangsan", "20");
p.setProperty("lisi", "20");
System.out.println(p);
}
PrintStream
字符文件输出类:
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream(System.out);
BufferedReader bw = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bw.readLine()) != null){
if(line.equals("over"))
break;
ps.println(line.toUpperCase());
ps.flush();
}
ps.close();
bw.close();
}
PrintWriter
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter p = null;
try {
p = new PrintWriter(new FileWriter("d:\\test\\printWriterDemo.txt"));
String line = null;
while((line=br.readLine()) != null)
{
if("over".equals(line))
break;
p.println(line.toUpperCase());
}
} catch (IOException e) {
e.printStackTrace();
}finally{
p.close();
try {
if(br != null)
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
练习:将错误信息存储到到硬盘文件中
public static void main(String[] args) {
try {
int[] arr = new int[2];
System.out.println(arr[5]);
} catch (Exception e) {
try {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
String s = sdf.format(date);
PrintStream p = new PrintStream("d:\\test\\error.txt");
p.println(s);
System.setOut(p);
} catch (IOException e1) {
throw new RuntimeException("日志文件创建失败");
}
e.printStackTrace(System.out);
}
}
File类常见方法
1.创建
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false
和输出流不一样,输出流对象一建立创建文件,而且文件已经存在,会覆盖
2.删除
void deleteOnExit();//当程序结束时删除,即时出现异常,也可以删除
3.判断
/boolean exists();//文件是否存在
boolean mkdir()//创建文件夹,这个函数只可以创建一级目录
boolean mkdirs();//可以创建多级目录
boolean isDirectory;//是否是目录
boolean isFile;//是否是文件
/4.获取信息
getName();
getPath();//获取封装的路径
getParent();//该方法返回的是绝对路径的父目录,如果获取的是相对路径返回为null
如何相对路径中有上一层目录,则返回父目录
getAbsolutePath();//获取绝对的路径
private static void method_3() {
File f = new File("StringDemo2.java");
//在创建文件对象是否是文件或者目录是,必须要先判断该文件对象封装的内容是否存在
try {
f.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//syso(f.i)
}
//删除文件
public static void method_2(){
File f = new File("file.txt");
syso("delete:" + f.delete());
syso(f);
}
//创建文件
public static void method_1(){
File f = new File("file.txt");
try {
syso("create:" + f.createNewFile());
syso(f);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//创建File对象
public static void consMethod(){
File f = new File("a.txt");
File f2 = new File("c:\\abc","b.txt");
File f3 = new File("c:" + File.separator + "d"+ File.separator + "abc.txt");
syso(f);
syso(f2);
syso(f3);
}
public static void syso(Object obj){
System.out.println(obj);
}
}
练习:遍历目录
public static void showDir(File str,int level){
System.out.println(getLevel(level)+str.getName());
level++;
File [] fileList = str.listFiles();
for(int x = 0; x < fileList.length; x++) {
if(fileList[x].isDirectory())
showDir(fileList[x],level);
else
System.out.println(fileList[x].getName());
}
}
练习
.对指定的目录进行递归获取递归过程所有的java文件的路径.将这些路径存储到集合中将集合中的数据写入到一个文件中
public static void main(String[] args) {
List<File> list = new ArrayList<File>();
File f = new File("c:\\");
fileToList(f,list);
System.out.println(list.size());
}
public static void listToFile(List<File> list,File f) throws IOException{
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
for(File file:list){
bw.write(file.getAbsolutePath());
bw.newLine();
bw.flush();
}
bw.close();
}
public static void fileToList(File dir,List<File> list){
File[] files = dir.listFiles();
for(File f:files){
if(f.isDirectory()){
fileToList(f,list);
}else{
if(f.getName().endsWith(".java"))
list.add(f);
}
}
}
编码表的由来:
计算机只能识别二进制数据,早期由来是电信号
为了方便应用计算机,让它可以识别各个国家的文字
就将各个国家的文字用数字来表示,并一一对应,形成一张表
这就是编码表
常见的编码表:
ASCII:美国标准信息交换吗
用一个字节的7位可以表示
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示
GB2312:中国的中文编码表
GBK:中国的中文编码表升级,融合了更多的中文文字符号
Unicode:国际标准码,融合了多种文字
所有文字都用两个字节来表示,java语言使用的就是Unicode
UTF-8:最多用三个字节来表示一个字符