------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------
IO流
IO(Input Output)流
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
IO流常用基类
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
IO程序的书写
导入IO包中的类
进行IO异常处理
在finally中对流进行关闭
字符流——创建文件
创建流对象,建立数据存放文件
FileWriter fw = new FileWriter(“Test.txt”);
调用流对象的写入方法,将数据写入流
fw.write(“text”);
关闭流资源,并将流中的数据清空到文件中
fw.close();
字符流——读取文件
建立一个流对象,和指定的文件数据关联。
FileReader fr = new FileReader(“Test.txt”);
创建一个临时存放数据的数组。
char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组中。
fr.read(ch);
注意:
定义文件路径时,可以用“/”或者“\\”。
在创建一个文件时,如果目录下有同名文件将被覆盖。
在读取文件时,必须保证该文件已存在,否则出异常。
字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。
对应类
BufferedWriter
BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
代码演示1:
/*
字符流的特点:
既然IO流是用于操作数据的
那么数据的最常见体现形式是文件
需求:在硬盘上创建一个文件,并写入一些数据
找到一个专门用于操作文件的Writer子类对象FileWriter
*/
package FileWriterDemo;
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args)
{
FileWriter fw = null;
try
{
/*创建一个FileWriter对象,该对象一初始化就必须要有被操作的文件
而且该文件会被创建到指定目录下,如果该目录下已有同名文件,该文件会被覆盖
其实该步就是在明确数据存放的目的地*/
fw = new FileWriter("Demo.txt",true);
//调用字符串,将字符串写入到流中
fw.write("\r\nnihao\r\nxiexie");
//刷新流对象中的缓冲数据,将数据刷到目的地中
fw.flush();
}
catch (IOException e)
{
System.out.println("catch:"+e.toString());
}
finally
{
try
{
if(fw!=null)
//关闭流资源,但是在关闭之前会刷新一次内部缓冲的数据
fw.close();
}
catch (IOException e)
{
}
}
}
}
/*
演示对已有文件的续写
//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写
FileWriter fw = new FileWrier("demo.txt",true);
*/
代码演示2:
package FileReaderDemo;
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args)
{
method_1();
//method_2();
}
public static void method_1()
{
FileReader fr = null;
try
{
//创建一个读取流对象,和指定的文件相关联
//要保证该文件是一件存在的,如果该文件不存在,会出现FileNotFoundException
fr = new FileReader("Demo.txt");
int ch = 0;
//调用读取流对象的read方法
//read()一次读取一个字符,自动往下读
while((ch=fr.read())!=-1)
{
System.out.print("Ch="+(char)ch+" ");
}
}
catch (IOException e)
{
throw new RuntimeException("读取失败");
}
finally
{
try
{
if(fr!=null)
//关闭流
fr.close();
}
catch (IOException e)
{
}
}
}
//通过字符数组进行读取
public static void method_2()
{
FileReader fr = null;
try
{
fr = new FileReader("Demo.txt");
//定义一个字符数组,用于存储读到的字符
//该read(buf)返回的是读到的字符数
char[] buf = new char[1024];
int len = 0;
while((len = fr.read(buf))!=-1)
{
//打印数组
System.out.print("len="+len+"..."+new String(buf,0,len));
}
}
catch (IOException e)
{
throw new RuntimeException("读取失败");
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch (IOException e)
{
}
}
}
}
代码演示3:
/*
需求:将C盘下的一个文件复制到D盘
复制的原理:
其实就是将C盘下的文件数据存储到D盘下的一个文件中
步骤:
1,在D盘创建一个文件,用于存储C盘文件的数据
2,定义文件读取流和C盘文件关联
3,通过不断的读写完成数据的储存
4,关闭资源
*/
class CopyTest
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
//从C盘读取一个字符,就往D盘写入一个字符
public static void copy()
{
//创建目的地
FileWriter fw = new FileWriter("Demo_copy.txt");
//与已有文件关联
FileReader fr = new FileReader("Demo.txt");
int ch = 0;
while((ch=fr.read())!=-1)
{
fw.write(ch);
}
fw.close();
fr.close();
}
}
代码演示4:
/*
缓冲区的出现是为了提高流的操作效率而出现的
所以在操作缓冲区之前要先有流对象
*/
import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个字符流写入对象
FileWriter fw = new FileWriter("BufferedWriterDemo.txt");
//为了提高字符写入效率,加入了缓冲技术
//只要将需要提高效率的流对象作为参数,传递给缓冲区的构造函数即可
BufferedWriter bufw = new BufferedWriter(fw);
bufw.write("abcde");
//换行
bufw.newLine();
//只要用到缓冲区,就要记得刷新
bufw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象
bufw.close();
}
}
/*
字符读取流缓冲区
该缓冲区提供了一个一次读取一行的方法readLine() 方便对文本文件的获取
当返回null时,表示读到文件末尾
readLine()方法的原理:
无论是读一行,读取多个字符,其实最终都是在硬盘上一个一个的读取
所以最终还是调用的read()方法
*/
装饰设计模式
1 当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,提供加强功能
2 那么自定义的该类被称为装饰类
装饰类通常会通过构造方法接收被装饰的对象
并基于被装饰的对象功能,提供更强的功能
MyReader //专门用于读取数据的类
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差
找到其参数的共同类型,利用多态,可以提高扩展性
class MyBufferReader
{
MyBufferReader(MyReader r)
{}
}
MyReader //专门用于读取数据的类
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader
装饰模式比继承体系要灵活,避免了继承体系臃肿
而且降低了类与类之间的关系
装饰类因为增强已有对象,具备的功能和已有的功能时相同的,只不过提供了更强功能
所以装饰类和被装饰的类都属于一个体系
字节流
基本操作与字符流类相同
但它不仅可以操作字符,还可以操作其他媒体文件
读取键盘录入:
System.out:对应的是标准输出设备,控制台
System.in:对应的标准输入设备,键盘
转换流
InputStreamReader,OutputStreamWriter
转换流的由来
字符流与字节流之间的桥梁
方便了字符流与字节流之间的操作
转换流的应用
字节流中的数据都是字符时,转成字符流操作更高效。
代码演示5:
/*
需求:
通过键盘录入一行数据并打印其大写,发现其实就是读一行的原理
也就是readLine()
能不能直接使用readLine方法来完成键盘录入的一行数据读取呢?
readLine方法是字符流BufferedReader类中的方法
而键盘录入的read()方法是字节流InputStream的方法
那么能不能将字节流转换成字符流再使用字符流缓冲区的readLine()方法呢?
*/
import java.io.*;
class TransDemo
{
public static void main(String[] args)
{
//获取键盘录入对象
InputStream in = System.in;
//将字节流对象转换成字符流对象,使用InputStreamReader()
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,使用缓冲技术
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while((line=bufr.readLine())!=null)
{
if(line.equals("over");
break;
System.out.println(line.toUpperCase());
}
bufr.close();
/*
输出转换流
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
*/
}
}
流操作规律:
1
源:键盘录入
目的:控制台
2 需求:把键盘录入的数据存储到一个文件中
源:键盘
目的:文件
3 需求:想要将一个文件的数据打印在控制台上
源:文件
目的:控制台
流操作的基本规律:通过两个明确来完成
1 明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2 操作的数据是否是纯文本
是:字符流
不是:字节流
4 当体系明确后再确定使用哪个对象
源设备:内存,键盘,硬盘
目的设备:内存,硬盘,控制台
File类
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。
File类常见的方法
创建
boolean createNewFile() 在指定位置创建文件,如果该文件已经存在,则不创建。返回false
和输出流不一样,输出流对象一旦创建文件,而且文件已经存在,会覆盖
boolean mkdir() 创建文件夹
boolean mkdirs() 创建多级文件夹
删除
boolean delete() 删除失败,返回false如果文件正在使用,则不能删除,返回false
void deleteOnExit() 在程序退出时删除指定文件
判断
boolean exists() 文件是否寻在
isFile();
isDirectory();
isHidden();
isAbsolute();
获取信息
getName();
getPath();
getParent();//该方法返回的是绝对路径下的父目录,如果获取的是先对路径,返回null
//如果该相对路径中有上一层目录,那么该目录就是返回结果
getAbsolutePath();
long lastModified();
long length();
代码演示6:
import java.io.*;
class FileDemo
{
public static void main(String[] args)
{
listDemo_1();
}
public static void method_1()
{
try
{
//将file.txt封装成文件对象
File f = new File("file.txt");
sop("create:"+f.createNewFile()); //
sop("canExcute:"+f.canExecute()); //测试应用程序是否可以执行这个文件
sop("parent:"+f.getParent()); //返回父目录的路径名字符串
sop("existe:"+f.exists()); //测试此文件或目录是否存在
sop("delete:"+f.delete()); //删除此抽象路径名表示的文件或目录
sop("AbsPath:"+f.getAbsolutePath());//返回此抽象路径名的绝对路径名形式
File dir = new File("abc");
sop("mkdir:"+dir.mkdir()); //在dir文件目录下创建一个文件夹
File f1 = new File("d:\\java0217\\day20\\FileDemo1.java");
File f2 = new File("d:\\java0217\\day20\\haha.java");
sop("raname:"+f2.renameTo(f1)); //重新f2表示的文件
}
catch (IOException e)
{
throw new RuntimeException("file Exception");
}
}
public static void listRootsDemo()
{
File[] files = File.listRoots();//表示可用文件系统根的 File 对象数组
for(File f : files)
{
System.out.println(f);
}
}
public static void listDemo_1()
{
File f = new File("d:\\java0217\\day20\\");
//返回一个字符串数组,这些字符串指定d:\java0217\day20\路径表示的目录中的文件和目录
String[] names = f.list(); //调用list()的file对象必须封装了一个目录,该目录必须存在
for(String name : names)
{
System.out.println(name);
}
}
public static void listDemo_2()
{
//创建一个File对象
File dir = new File("d:\\java0217\\day20");
String[] arr = dir.list(new FilenameFilter()
{
//list方法依据accept方法的返回值判定是不是需要过滤文件
public boolean accept(File dir ,String name)
{
return name.endsWith(".java");
}
});
for(String name : arr)
{
System.out.println(name);
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
代码演示7:
import java.io.*;
/*
列出指定目录下文件或者文件夹,包含子目录中的内容
也就是列出指定目录下的所有内容
递归要注意:
1,限定条件
2,要注意递归的次数,避免内存的溢出
*/
class FileDemo2
{
public static void main(String[] args)
{
File dir = new File("d:\\java0217\\day20");
int level = 0;
showDir(dir,level);
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+" "+dir.getName());
level++;
//列出指定目录下的所有文件
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++)
{
//如果该文件对象是一个目录
if(files[x].isDirectory())
showDir(files[x],level);
else
System.out.println(getLevel(level)+" "+files[x]);
}
}
//根据不同的层级返回不同的空格数
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
for(int x=0; x<level; x++)
{
sb.append(" ");
}
return sb.toString();
}
}
Properies类
Properties是hashtable的子类
也就是说它具备map集合的特点,而且它里边存的键值对都是字符串
是集合中和IO技术相结合的集合容器
该对象的特点:可以用于键值对形式的配置文件
那么在加载数据时,需要数据有固定格式:健=值
代码演示8:
import java.io.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args)
{
method_2();
}
//设置和获取元素
public static void method_1()
{
Properties prop = new Properties();
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","29");
String value = prop.getProperty("zhangsan"); //返回zhangsan对应的值
System.out.println(value);
//返回该集合中所有的键值
Set<String> names = prop.stringPropertyNames(); //1.6开始出现的stringPropertyNames()
for(String s : names
{
System.out.println(s+" "+prop.getProperty(s));
}
}
/*
想要将info.txt中的键值数据存储到集合中进行操作
1,用一个流和info.txt文件相关联
2,读取一行数据,将该行数据用=进行切割
3,等号左边作为键,右边作为值,存入到Properties集合中即可
*/
public static void method_2()
{
BufferedReader bufr = null;
try
{
bufr = new BufferedReader(new FileReader("info.txt"));
String line = null;
Properties prop = new Properties();
while((line = bufr.readLine())!= null)
{
//切割每一行数据
String[] arr = line.split("=");
//将等号两边的内容存放到Properties集合中
prop.setProperty(arr[0],arr[1]);
}
System.out.println(prop);
}
catch (IOException e)
{
throw new RuntimeException("read exception");
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("close failed");
}
}
}
}
打印流:
PrintStream为其他输出流添加了功能,使他们能够方便的打印各种数据值表现形式
该流提供了打印方法,可以将各种数据类型的数据都原样打印
字节打印流:
PrintStream
构造函数可以接收的参数类型
1,file对象 File
2,字符串路径 String
3,字节输出流 OutputStream
字符打印流:
1,file对象 File
2,字符串路径 String
3,字节输出流 OutputStream
4,字符输出流 Writer
代码演示9:
class PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
//读取键盘录入
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//创建一个字符打印流,将数据存储到指定的文件中,自动刷新
PrintWriter pw = new PrintWriter(new FileWriter("a.txt"),true);
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
//打印并自动换行
pw.println(line.toUpperCase());
//pw.flush();
}
pw.close();
bufr.close();
}
}
IO包中的其他类
打印流
PrintWriter与PrintStream
可以直接操作输入流和文件。
序列流
SequenceInputStream
对多个流进行合并。
操作对象
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable (标记接口);
RandomAccessFile
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)来达到随机访问。
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
操作基本数据类型
DataInputStream与DataOutputStream
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
操作字符数组
CharArrayReader与CharArrayWrite
操作字符串
StringReader 与 StringWriter
字符编码
字符流的出现为了方便操作字符。
更重要是的加入了编码转换。
通过子类转换流来完成。
InputStreamReader
OutputStreamWriter
在两个对象进行构造的时候可以加入字符集。
编码表的由来
1 计算机只能识别二进制数据,早期由来是电信号。
2 为了方便应用计算机,让它可以识别各个国家的文字。
3 就将各个国家的文字用数字来表示,并一一对应,形成一张表。
常见的编码表
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。